Add a Vue Project

The code for this example is available on Github:

Supported Features

We'll be using an Nx plugin for Vue 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

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

Nx 15 and lower use @nrwl/ instead of @nx/

Create the application

touch index.html

And add the following content:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Acme</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link rel="icon" type="image/x-icon" href="./favicon.ico" /> </head> <body> <div id="app"></div> <script type="module" src="./src/main.ts"></script> </body> </html>

Navigate to src/index.ts and change it to src/main.ts and add the following content:

import { createApp } from 'vue'; import App from './App.vue'; createApp(App).mount('#app');

Create a new file src/App.vue with the following content:

<script setup lang="ts"> import { ref } from 'vue'; const count = ref(0); function increment() { count.value++; } </script> <template> <div>count is {{ count }}</div> <button @click="increment">Increment</button> </template>

Configure Nx to use build and serve your Vue application

Navigate to vite.config.ts and add the following content:

// Add this to your imports import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; export default defineConfig({ plugins: [ //.... other plugins vue(), vueJsx(), ], });

Create a new file env.d.ts for example at the root of the project and add the following content:

/// <reference types="vite/client" /> /* eslint-disable */ declare module '*.vue' { import type { DefineComponent } from 'vue'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const component: DefineComponent<object, object, any>; export default component; }

We 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:

{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "dist/out-tsc", "types": ["node", "vite/client"], "jsxImportSource": "vue" }, "files": [], "exclude": [ "src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx" ], "include": [ "src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "**/*.vue", "vite.config.ts", "env.d.ts" ] }

We 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:

"build": { "executor": "@nx/vite:build", "outputs": ["{options.outputPath}"], "defaultConfiguration": "production", "options": { "outputPath": "dist/test-vue" }, "configurations": { "development": { "mode": "development" }, "production": { "mode": "production" } } }, "serve": { "executor": "@nx/vite:dev-server", "defaultConfiguration": "development", "options": { "buildTarget": "test-vue:build" }, "configurations": { "development": { "buildTarget": "test-vue:build:development", "hmr": true }, "production": { "buildTarget": "test-vue:build:production", "hmr": false } } },
Nx 15 and lower use @nrwl/ instead of @nx/

This 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.

Create a new library nx generate @nx/js:library --name=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.

export { default as Counter } from './Counter.vue';

The 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:

export default defineConfig({ //... other config resolve: { alias: { '@acme/counter': fileURLToPath( new URL('./counter/src/index.ts', import.meta.url) ), }, }, });

This allows the runtime to resolve the @acme/counter import to the correct location.

Finally update your src/App.vue to use the Counter component.

<script setup lang="ts"> import { Counter } from '@acme/counter'; </script> <template> <Counter /> </template>

Test 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.