Add a Vue Project
The code for this example is available on GitHub:
Example repository/nrwl/nx-recipes/tree/main/vue
This recipe does not use the official Vue plugin, so it doesn't use generators or automate updating framework dependencies. Use @nx/vue to use those features.
Supported Features
We'll be using an Nx plugin called @nx/vite. Although we are using @nx/vite, not all dependencies will be able to be automatically updated. So we'll have to update any framework dependencies as needed.
✅ Run Tasks ✅ Cache Task Results ✅ Share Your Cache ✅ Explore the Graph ✅ Distribute Task Execution ✅ Integrate with Editors ✅ Automate Updating Nx ✅ Enforce Module Boundaries ✅ Use Task Executors 🚫 Use Code Generators 🚫 Automate Updating Framework Dependencies
Setup workspace
Create a new Nx workspace
❯
create-nx-workspace@latest acme --preset=ts-standalone --nx-cloud=true
Add @nx/vite, vue, and other dependencies to your workspace
Keep Nx Package Versions In SyncMake sure to install the @nx/vite and @nx/js versions that matches the version of nx in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can fix Nx version mismatches with this recipe.
❯
npm install --save-dev @nx/vite @nx/js vue vue-tsc vitest vite-tsconfig-paths vite-plugin-dts vite @vitejs/plugin-vue @vitejs/plugin-vue-jsx
Create the application
❯
touch index.html
And add the following content:
1
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <title>Acme</title>
6
7 <meta name="viewport" content="width=device-width, initial-scale=1" />
8 <link rel="icon" type="image/x-icon" href="./favicon.ico" />
9 </head>
10 <body>
11 <div id="app"></div>
12 <script type="module" src="./src/main.ts"></script>
13 </body>
14</html>
15Navigate to src/index.ts and change it to src/main.ts and add the following content:
1import { createApp } from 'vue';
2import App from './App.vue';
3
4createApp(App).mount('#app');
5Create a new file src/App.vue with the following content:
1<script setup lang="ts">
2import { ref } from 'vue';
3
4const count = ref(0);
5
6function increment() {
7 count.value++;
8}
9</script>
10<template>
11 <div>count is {{ count }}</div>
12 <button @click="increment">Increment</button>
13</template>
14Configure Nx to use build and serve your Vue application
Navigate to vite.config.ts and add the following content:
1// Add this to your imports
2import vue from '@vitejs/plugin-vue';
3import vueJsx from '@vitejs/plugin-vue-jsx';
4
5export default defineConfig({
6 plugins: [
7 //.... other plugins
8 vue(),
9 vueJsx(),
10 ],
11});
12Create a new file env.d.ts for example at the root of the project and add the following content:
1/// <reference types="vite/client" />
2/* eslint-disable */
3declare module '*.vue' {
4 import type { DefineComponent } from 'vue';
5 // eslint-disable-next-line @typescript-eslint/no-explicit-any
6 const component: DefineComponent<object, object, any>;
7 export default component;
8}
9We need this file to ensure that Vue types are available to the compiler.
Update your tsconfig.lib.json to be tsconfig.app.json an add the following content:
1{
2 "extends": "./tsconfig.json",
3 "compilerOptions": {
4 "outDir": "dist/out-tsc",
5 "types": ["node", "vite/client"],
6 "jsxImportSource": "vue"
7 },
8 "files": [],
9 "exclude": [
10 "src/**/*.spec.ts",
11 "src/**/*.test.ts",
12 "src/**/*.spec.tsx",
13 "src/**/*.test.tsx",
14 "src/**/*.spec.js",
15 "src/**/*.test.js",
16 "src/**/*.spec.jsx",
17 "src/**/*.test.jsx"
18 ],
19 "include": [
20 "src/**/*.ts",
21 "src/**/*.d.ts",
22 "src/**/*.tsx",
23 "**/*.vue",
24 "vite.config.ts",
25 "env.d.ts"
26 ]
27}
28We include vite.config.ts and env.d.ts to ensure that the types are available to the compiler.
Navigate to project.json and update it with the following content:
1 "build": {
2 "executor": "@nx/vite:build",
3 "outputs": ["{options.outputPath}"],
4 "defaultConfiguration": "production",
5 "options": {
6 "outputPath": "dist/acme"
7 },
8 "configurations": {
9 "development": {
10 "mode": "development"
11 },
12 "production": {
13 "mode": "production"
14 }
15 }
16 },
17 "serve": {
18 "executor": "@nx/vite:dev-server",
19 "defaultConfiguration": "development",
20 "options": {
21 "buildTarget": "acme:build"
22 },
23 "configurations": {
24 "development": {
25 "buildTarget": "acme:build:development",
26 "hmr": true
27 },
28 "production": {
29 "buildTarget": "acme:build:production",
30 "hmr": false
31 }
32 }
33 },
34This allows us to use nx build and nx serve to build and serve our Vue application.
Test it out
Build
❯
nx build acme
Serve
❯
nx serve acme
Create a library
Instead of having our Counter directly defined in the app we can instead create a library that exports the Counter component.
Directory Flag Behavior ChangesThe command below uses the as-provided directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the derived option, omit the --directory flag. See the as-provided vs. derived documentation for more details.
Create a new library nx generate @nx/js:library --name=Counter --directory=libs/counter --unitTestRunner=vitest --bundler=vite --importPath=@acme/counter
Create your Counter component at counter/src/lib/Counter.vue and copy the contents of your src/App.vue into it.
Update your libs/counter/src/lib/index.ts to export your Counter component.
1export { default as Counter } from './Counter.vue';
2The default is very import here as it allows us to import the component using import { Counter } from '@acme/counter' instead of import Counter from '@acme/counter'.
Update your root ./vite.config.ts to include the following:
1export default defineConfig({
2 //... other config
3 resolve: {
4 alias: {
5 '@acme/counter': fileURLToPath(
6 new URL('./counter/src/index.ts', import.meta.url)
7 ),
8 },
9 },
10});
11This allows the runtime to resolve the @acme/counter import to the correct location.
Finally update your src/App.vue to use the Counter component.
1<script setup lang="ts">
2import { Counter } from '@acme/counter';
3</script>
4<template>
5 <Counter />
6</template>
7Test it out
Build
❯
nx build acme
Serve
❯
nx serve acme
More Documentation
A larger example including libraries, tests, and more is available at Nx Vue Example on GitHub.