This template can be used for creating new projects using Nx. It contains a working example that uses a very opinionated list of tools and libraries.
Nx is a monorepo tool that comes with CLI and VS Code tooling. It allows the user to have multiple libraries (public and private) and applications in the same repository. Libraries can be shared between applications and can be imported by other libraries and/or deployed to npm. The application(s) can also be deployed individually.
📘 Explaining how Nx works is not part of this README. Please refer to the Nx documentation for more information.
Scripts to Rule Them All is a pattern for organizing scripts. In this project they can be used to access commonly used functionality. Each script also comes with helpful error messages.
script/build-all
: Builds all libraries and applicationsscript/ci
: Runs the commands necessary to build in a CI environmentscript/docker-up
: Starts the docker container(s)script/docker-down
: Stops the docker container(s)script/projects
: Lists all projectsscript/run
: Starts a project that has been built beforescript/serve
: Starts a project in development modescript/setup
: Prepares the monorepo for developmentscript/test-all
: Runs all tests
📙 Nx sometimes fails to properly manage the cache which can result in a passing build that fails in a CI environment. For this reason the following aliases can be used (add them to .zshrc / .bashrc):
alias nba="clear && nx run-many --target=build --all --skip-nx-cache" alias nta="clear && nx run-many --target=test --all --skip-nx-cache" alias nra="clear && nba && nta"
This project can be used with Docker. The docker-compose.yml
file contains the configuration for the containers.
This project can be used with PostgreSQL. The docker-compose.yml
file contains the configuration for the database in case you don't want a locall installment.
📘 RDS can also be used as it is fully compatible with PostgreSQL.
Husky is a tool that allows you to run scripts before or after git commands. In this project it is used to run the linter (lint-staged
) before committing.
The .lintstagedrc
file describes how linting works. It will run
eslint and prettier on all staged files.
Testing is done using Jest. All files that have the .spec.ts
extension will be run by Jest. You can peruse the example tests in the yourapp
project.
Volta is a tool that allows you to manage your Node.js version. It is recommended to use it to ensure that everyone is using the same version of Node.js. If you run script/setup
it will install Node with Volta for you.
Dotenv is a tool that allows you to load environment variables from a .env
file. They are ignored by git and can be used to store sensitive information.
React is used for the frontend.
📘 If you don't know how to use React this course is a superb source of information.
React Query is a library that allows you to fetch data in a declarative way. It is used in the yourapp
project.
tRPC is a library that allows seamless integration between the frontend and the backend
with an RPC-like interface. It is used in the yourapp
project.
📘 A note on the T3 stack: The T3 stack might be familiar if you take a look at the tooling used here. This is not a coincidence. We've started with T3, but it doesn't work well with monorepos, so we integrated the same tech into Nx.
Tailwind is a utility-first CSS framework. It is used to style the frontend.
Next.js is a framework for React that allows you to create server-side rendered applications. It is used in the yourapp
project.
NextAuth.js is a library that allows you to add authentication to your Next.js application. It is used in the yourapp
project.
For authorization a custom-made library (PBAC) is used. It is used in the yourapp
project.
Prisma is an ORM(ish) tool that can be used to connect to a database.
It is used in the yourapp
project for database access.
For serializing (and validating) data between the backend and the frontend we're using the Zod library.
We're using functional programming in this project with the help of fp-ts.
The main reasons:
- Established and well-known coding patterns: even though people sometimes have an aversion to strictly typed fp, its concepts are well understood and applicable across many languages. If you've learned it once you can apply it elsewhere too. In our opinion it is much better than using arbitrary patterns and semantics that most frameworks bring to the table
- Straightworward error handling
- Simple to write asynchronous code
- Easy to test
- Less error-prone