Development
May 29, 2025 ยท View on GitHub
Development
- Development
Documentation
- Nx Documentation
- Vite Documentation
- Husky Documentation
- commitlint Documentation
- Conventional Commits
Commands
To start the development server, build or see the build preview of a specific app
go to this project directory and look for a README.md for more information.
All projects are located in the /apps directory and libraries in the /libs directory.
Root commands
# Install dependencies
pnpm run init
# Install dependencies for CI
pnpm run ci
# Build projects for production - outputs are saved in the `/dist` directory
pnpm run build:prod
# Build projects for staging - outputs are saved in the `/dist` directory
pnpm run build:staging
# Clean dependencies
pnpm run clean
Server build - CI/CD
Locally for testing purposes all of the projects will be built, thanks to the run-many command.
In a CI/CD pipeline Nx should only build the affected projects (only projects containing changes).
For this purpose, the affected command should be configured.
pnpm nx affected -t build:prod
# or
pnpm nx affected -t build:staging
By default the command checks if a package/project is affected by comparing the HEAD of the current branch
with the main branch. Check the official documentation for more options.
Commits
Thanks to the commitlint and husky packages, the commit messages are being checked before the commit.
This ensures that the messages are in a standardized format.
# type: feat, fix, docs, ...
# scope: the part of the project you are working on (optional)
# subject: short description of the changes
git commit -m "<type>(<scope>): <subject>"
Read more about the Conventional Commits
Environment variables
NODE_ENV & VITE MODE
The NODE_ENV=production is not supported by Vite.
Only the NODE_ENV=development is being respected to create a development build of the project
Vite has also so called Mode, depending on the .env file used for build or a serve command.
Respectively it uses
.env.developmentfile for development mode (local; serve command).env.productionfile for production mode (build command).env.[mode]file for custom mode (build command with --mode [mode] argument)
More about modes here
Caution
If you need some local environment variables in apps or libs you theoretically could use simple .env file,
but in combination with Nx it causes a known issue. Nx will use the .env file for every build mode,
effectively ignoring the .env.production and other .env.[mode] files.
Therefore, if you need some local environment variables, use .env.development or .env.development.local file.
Code usage
To make use of environment variables in your code, you can simply use import.meta.env.MODE variable.
if (import.meta.env.MODE !== 'production') {
console.log('Not the production mode');
}
VITE_APP_*
Use VITE_APP_ prefix to expose environment variables to your app
VITE_APP_API_URL=https://api.example.com
Caution
Such variables are exposed to the client-side code and can be seen in the browser's developer tools.
Do not expose any sensitive data in this way (secret api keys, etc.).
Dependencies management
Add new dependencies
Go to the root directory and run the following command.
# for dependencies
pnpm add <package-name> -w
# for devDependencies
pnpm add <package-name> -Dw
If a specific package is required only for one specific project, then go to the directory of this project
and run the same command without the -w flag.
# for dependencies
pnpm add <package-name>
# for devDependencies
pnpm add <package-name> -D
Update dependencies
pnpm update --latest
Libraries
Add a new library
Libraries in the monorepo are located in the /libs directory.
In our case they are not meant to be build separately, but to be used in the projects directly and bundled with them.
To add a new library:
- go to the directory -
/libsand add a new directory with the library name - copy and paste the following files from an existing library:
package.jsontsconfig.json.eslint.jsonREADME.md- src/
index.ts - src/
vue-shim.d.ts(if the library is for Vue.js)
- finally modify the
package.jsonfile with- the new unique library name
- as well as planned exports if they should be any different,
- add dependencies & devDependencies
(only if they are unique for this library; otherwise they should be added to the rootpackage.jsonfile -> Dependencies management)
A standard package.json file for a library looks like this:
Sample 'package.json'
{
"name": "@monorepo/<library-name>",
"version": "1.0.0",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts",
"./composables/*": "./src/composables/*",
"./lib/*": "./src/lib/"
},
"nx": {
"projectType": "library"
},
"scripts": {
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.vue src",
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx,.vue --fix src"
},
"dependencies": {}
}
Note
If you just added a new app or library, it is possible that nx has to be restarted to recognize the new project.
If Nx Console plugin is installed in your IDE, most probably all will be recognized automatically.
Otherwise, you can run the following command from the root directory.
npx nx watch --all -- echo \$NX_PROJECT_NAME
Adding library types to the app
Be aware that if you define the exports field in the package.json file, most probably you will
have to add in your app project a clear definition of those paths in the tsconfig.json file.
{
"compilerOptions": {
"paths": {
"@monorepo/<library-name>": [
"libs/<library-name>/src/index.ts"
],
"@monorepo/<library-name>/composables/*": [
"libs/<library-name>/src/composables/*"
],
"@monorepo/<library-name>/lib/*": [
"libs/<library-name>/src/lib/*"
]
}
}
}
Connect library to an app
To use an existing or newly created library in an app, follow these steps:
-
Add it to the
package.jsonfile of the app without the version number.
By doing so you will always get the latest version of the library.{ "dependencies": { "@monorepo/<library-name>": "*" } } -
Modify the
tsconfig.jsonfile in the app directory to include the library in thecompilerOptions.pathsobject.{ "compilerOptions": { "paths": { "@monorepo/<library-name>": [ "libs/<library-name>/src/index.ts" ] } } } -
Run the following command from the root directory -
/pnpm run init -
Finally you can import the library functions / components in your app
import { <library-name> } from '@monorepo/<library-name>';
Linting, formatting and types
ESLint
The ESLint configuration is located in the .eslintrc.cjs file in the root directory
and is imported and extended in the apps if needed.
There is no Prettier in this template for a good reason. Having yet another tool to format the code and solving
the conflicts between Prettier and ESLint can be avoided thanks to the Anthony Fu's @stylistic/eslint-plugin package.
Now ESLint can do the same and at the same time warn us about the code quality.
More on this subject
ESLint Stylistic
RECOMMENDED
Add in your IDE the ESLint extension and activate formatting on save.
ESLint in Visual Studio Code
Visual Studio Code settings
To use the ESLint extension in Visual Studio Code, install the dbaeumer.vscode-eslint extension.
Add the following settings to the settings.json file in Visual Studio Code for the best experience.
You can open the settings.json by going to File -> Preferences -> Settings
and pressing on the {} icon in the top right corner.
๐ฆ Note
If you use the default
.code-workspacefile from the root directory, you don't need to add these settings.
They are already there.
{
"[html]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[vue]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.format.enable": true,
"eslint.options": {
"extensions": [
".html",
".js",
".cjs",
".vue",
".jsx"
]
},
"eslint.validate": [
"html",
"vue",
"language",
"javascriptreact",
"typescript",
"javascript"
],
}
ESLint in Rider / other JetBrains IDEs
Rider settings
To use the ESLint extension in Rider, you need to open settings and search for ESLint and set the following settings:
- Automatic ESLint configuration
- Run for files:
**/*.{js,ts,jsx,tsx,html,vue,cjs} - Run eslint --fix on save

๐ฆ Note
If you are on a Mac you can open two windows of Rider in the same application.
Just open the second Project in the second window and choose theWindow -> Merge All Project Windowsoption.
More on this subject here
Tailwind
To work with a projects utilizing Tailwind CSS, you should (strongly recommended) install the Tailwind CSS IntelliSense extension.
You will find one in the marketplace for Visual Studio Code as well as for Rider.
The extension will provide you with the IntelliSense for the Tailwind CSS classes, but not everywhere you could need it.
That's why we developed additional configuration.
Tailwind in Visual Studio Code
Visual Studio Code settings
To use the Tailwind extension in Visual Studio Code, install the bradlc.vscode-tailwindcss extension.
Add the following settings to the settings.json file in Visual Studio Code for the best experience.
You can open the settings.json by going to File -> Preferences -> Settings
and pressing on the {} icon in the top right corner.
๐ฆ Note
If you use the default
.code-workspacefile from the root directory, you don't need to add these settings.
They are already there.
{
"tailwindCSS.experimental.classRegex": [
// for VuePrime styling. Example: class: [strings_in_this_array]
[
"class:\\s*\\[((?:[^[\\]]|\\[(?:[^[\\]]|\\[[^[\\]]*\\])*])*?)\\]",
"(?:['\"`]([^'\"`]*)['\"`])"
],
// for computed functions. Example: const textClass = computed(() => ['text-red'])
[
"computed\\(\\s*\\(\\s*\\)\\s*=>\\s*([\\s\\S]*?)\\)",
"(?:['\"`]([^'\"`]*)['\"`])"
],
// additional inline option - add /*tw:*/ before any string
"\\/\\*\\s?tw:\\s?\\*\\/\\s?['\"`](.*)['\"`]"
],
}
Tailwind in Rider / other JetBrains IDEs
Rider settings
Install the Tailwind CSS plugin from the JetBrains marketplace.
Then go to the File -> Settings -> Languages & Frameworks -> Style Sheets -> Tailwind CSS
and ad this configuration to the experimental > classRegex field.
{
"experimental": {
"classRegex": [
[
"class:\\s*\\[((?:[^[\\]]|\\[(?:[^[\\]]|\\[[^[\\]]*\\])*])*?)\\]",
"(?:['\"`]([^'\"`]*)['\"`])"
],
[
"computed\\(\\s*\\(\\s*\\)\\s*=>\\s*([\\s\\S]*?)\\)",
"(?:['\"`]([^'\"`]*)['\"`])"
],
"\\/\\*\\s?tw:\\s?\\*\\/\\s?['\"`](.*)['\"`]"
]
}
}
Typescript
The typescript configuration is located in the tsconfig.base.json file in the root directory.
All projects (app and libs) are extending this configuration.
Missing types from libraries
If it's your case - check if the library index file or one of the shortcuts to library directories is not missing
in the in the app in tsconfig.json file. More on this -> Adding library types to the app.
Setting up the typescript configuration
Keep in mind that referencing the tsconfig.json file in a project and changing any of the settings
will not merge everything with the tsconfig.base.json file but partially override it.
More on this subject
To see the typescript configuration, you can run the following command from the directory
in which you want to see the local one - a merge/overwrite of the base and the extending one.
npx tsc --showconfig