Manually set up your project to use Vite.js

Use our generator!

It is recommended that you use the @nx/vite:configuration generator to do convert an existing project to use Vite.

You can use the @nx/vite:dev-server,@nx/vite:build and @nx/vite:test executors to serve, build and test your project using Vite and Vitest. To do this, you need to make a few adjustments to your project. It is recommended that you use the @nx/vite:configuration generator to do this, but you can also do it manually.

A reason you may need to do this manually, is if our generator does not support conversion for your project, or if you want to experiment with custom options.

The list of steps below assumes that your project can be converted to use the @nx/vite executors. However, if it's not supported by the @nx/vite:configuration generator, it's likely that your project will not work as expected when converted. So, proceed with caution and always commit your code before making any changes.

1. Change the executors in your project.json

The serve target

This applies to applications, not libraries.

In your app's project.json file, change the executor of your serve target to use @nx/vite:dev-server and set it up with the following options:

1//... 2"my-app": { 3 "targets": { 4 //... 5 "serve": { 6 "executor": "@nx/vite:dev-server", 7 "defaultConfiguration": "development", 8 "options": { 9 "buildTarget": "my-app:build", 10 }, 11 "configurations": { 12 ... 13 } 14 }, 15 } 16} 17
Nx 15 and lower use @nrwl/ instead of @nx/
Other options

Any extra options that you may need to add to your server's configuration can be added in your project's vite.config.ts file. You can find all the options that are supported in the Vite.js documentation. You can see which of these options you can add in your project.json in the @nx/vite:dev-server documentation.

The build target

In your project's project.json file, change the executor of your build target to use @nx/vite:build and set it up with the following options:

1//... 2"my-app": { 3 "targets": { 4 //... 5 "build": { 6 "executor": "@nx/vite:build", 7 ... 8 "options": { 9 "outputPath": "dist/apps/my-app" 10 }, 11 "configurations": { 12 ... 13 } 14 }, 15 } 16} 17
Nx 15 and lower use @nrwl/ instead of @nx/
Other options

You can specify more options in the vite.config.ts file (see Step 2 below).

2. Configure Vite.js

TypeScript paths

You need to use the vite-tsconfig-paths plugin to make sure that your TypeScript paths are resolved correctly in your monorepo.

React plugin

If you are using React, you need to use the @vitejs/plugin-react plugin.

DTS plugin

If you are building a library, you need to use the vite-plugin-dts plugin to generate the .d.ts files for your library.

Skip diagnostics

If you are building a library, you can set the skipDiagnostics option to true to speed up the build. This means that type diagnostic will be skipped during the build process. However, if there are some files with type errors which interrupt the build process, these files will not be emitted and .d.ts declaration files will not be generated.

If you choose to skip diagnostics, here is what your 'vite-plugin-dts' plugin setup will look like:

libs/my-lib/vite.config.ts
1... 2import dts from 'vite-plugin-dts'; 3import { join } from 'path'; 4... 5... 6export default defineConfig({ 7 plugins: [ 8 ..., 9 dts({ 10 entryRoot: 'src', 11 tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'), 12 skipDiagnostics: true, 13 }), 14

Do not skip diagnostics

If you are building a library, and you want to make sure that all the files are type checked, you can set the skipDiagnostics option to false to make sure that all the files are type checked. This means that type diagnostic will be run during the build process.

If you choose to enable diagnostics, here is what your 'vite-plugin-dts' plugin setup will look like:

libs/my-lib/vite.config.ts
1... 2import dts from 'vite-plugin-dts'; 3... 4... 5export default defineConfig({ 6 plugins: [ 7 ..., 8 dts({ 9 root: '../../', 10 entryRoot: 'libs/my-lib/src', 11 tsConfigFilePath: 'libs/my-lib/tsconfig.lib.json', 12 include: ['libs/my-lib/src/**/*.ts'], 13 outputDir: 'dist/libs/my-lib', 14 skipDiagnostics: false, 15 }), 16

You can read more about the configuration options in the vite-plugin-dts plugin documentation).

How your vite.config.ts looks like

For applications

Add a vite.config.ts file to the root of your project. If you are not using React, you can skip adding the react plugin, of course.

apps/my-app/vite.config.ts
1import { defineConfig } from 'vite'; 2import react from '@vitejs/plugin-react'; 3import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths'; 4 5export default defineConfig({ 6 plugins: [ 7 react(), 8 ViteTsConfigPathsPlugin({ 9 root: '../../', 10 }), 11 ], 12}); 13

For libraries

If you are setting up a library (rather than an application) to use vite, your vite.config.ts file should look like this:

libs/my-lib/vite.config.ts
1import { defineConfig } from 'vite'; 2import react from '@vitejs/plugin-react'; 3import viteTsConfigPaths from 'vite-tsconfig-paths'; 4import dts from 'vite-plugin-dts'; 5import { join } from 'path'; 6 7export default defineConfig({ 8 plugins: [ 9 dts({ 10 entryRoot: 'src', 11 tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'), 12 skipDiagnostics: true, 13 }), 14 react(), 15 viteTsConfigPaths({ 16 root: '../../', 17 }), 18 ], 19 20 // Configuration for building your library. 21 // See: https://vitejs.dev/guide/build.html#library-mode 22 build: { 23 lib: { 24 // Could also be a dictionary or array of multiple entry points. 25 entry: 'src/index.ts', 26 name: 'pure-libs-rlv1', 27 fileName: 'index', 28 // Change this to the formats you want to support. 29 // Don't forget to update your package.json as well. 30 formats: ['es', 'cjs'], 31 }, 32 rollupOptions: { 33 // External packages that should not be bundled into your library. 34 external: ['react', 'react-dom', 'react/jsx-runtime'], 35 }, 36 }, 37}); 38
The `root` path

Make sure the root path in the ViteTsConfigPathsPlugin options is correct. It should be the path to the root of your workspace.

In that config file, you can configure Vite.js as you would normally do. For more information, see the Vite.js documentation.

3. Move index.html and point it to your app's entrypoint

This applies to applications, not libraries.

First of all, move your index.html file to the root of your app (e.g. from apps/my-app/src/index.html to apps/my-app/index.html).

Then, add a module script tag pointing to the main.tsx (or main.ts) file of your app:

apps/my-app/index.html
1... 2 <body> 3 <div id="root"></div> 4 <script type="module" src="src/main.tsx"></script> 5 </body> 6</html> 7

4. Add a public folder

You can add a public folder to the root of your project. You can read more about the public folder in the Vite.js documentation.

1myorg/ 2├── apps/ 3│ ├── my-app/ 4│ │ ├── src/ 5│ │ │ ├── app/ 6│ │ │ ├── assets/ 7│ │ │ ├── ... 8│ │ │ └── main.tsx 9│ │ ├── index.html 10│ │ ├── public/ 11| . | . | ├── favicon.ico 12│ │ │ └── my-page.md 13│ │ ├── project.json 14│ │ ├── ... 15│ │ ├── tsconfig.app.json 16│ │ ├── tsconfig.json 17│ │ └── tsconfig.spec.json 18

You can use the public folder to store static assets, such as images, fonts, and so on. You can also use it to store Markdown files, which you can then import in your app and use as a source of content.

5. Adjust your project's tsconfig.json

Change your app's tsconfig.json (e.g. apps/my-app/tsconfig.json) compilerOptions to the following:

For React apps

apps/my-app/tsconfig.json
1... 2 "compilerOptions": { 3 "jsx": "react-jsx", 4 "allowJs": false, 5 "esModuleInterop": false, 6 "allowSyntheticDefaultImports": true, 7 "forceConsistentCasingInFileNames": true, 8 "isolatedModules": true, 9 "lib": ["DOM", "DOM.Iterable", "ESNext"], 10 "module": "ESNext", 11 "moduleResolution": "Node", 12 "noEmit": true, 13 "resolveJsonModule": true, 14 "skipLibCheck": true, 15 "strict": true, 16 "target": "ESNext", 17 "types": ["vite/client"], 18 "useDefineForClassFields": true 19 }, 20... 21

For Web apps

apps/my-app/tsconfig.json
1... 2 "compilerOptions": { 3 "target": "ESNext", 4 "useDefineForClassFields": true, 5 "module": "ESNext", 6 "lib": ["ESNext", "DOM"], 7 "moduleResolution": "Node", 8 "strict": true, 9 "resolveJsonModule": true, 10 "isolatedModules": true, 11 "esModuleInterop": true, 12 "noEmit": true, 13 "noUnusedLocals": true, 14 "noUnusedParameters": true, 15 "noImplicitReturns": true, 16 "skipLibCheck": true, 17 "types": ["vite/client"] 18 }, 19 "include": ["src"], 20... 21

You can read more about the TypeScript compiler options in the Vite.js documentation.

6. Use Vite.js

Now you can finally serve and build your app using Vite.js:

Serve the app

1nx serve my-app 2

or

1nx run my-app:serve 2

Now, visit http://localhost:4200 to see your app running!

Build the app

1nx build my-app 2

or

1nx run my-app:build 2