Welcome to BaseButton!
``` ## You're ready to go! In the previous sections you learned about the basics of using Nx, running tasks and navigating an Nx workspace. You're ready to ship features now! But there's more to learn. You have two possibilities here: - [Jump to the next steps section](#next-steps) to find where to go from here or - keep reading and learn some more about what makes Nx unique when working with Vue. ## Modularize your Vue App with Local Libraries When you develop your Vue application, usually all your logic sits in the `src` folder. Ideally separated by various folder names which represent your "domains". As your app grows, this becomes more and more monolithic though. ``` └─ vue-app ├─ ... ├─ src │ ├─ views │ │ ├─ products │ │ └─ cart │ ├─ components │ │ ├─ ui │ │ └─ ... │ ├─ App.vue │ └─ main.ts ├─ ... ├─ package.json ├─ ... ``` Nx allows you to separate this logic into "local libraries". The main benefits include - better separation of concerns - better reusability - more explicit "APIs" between your "domain areas" - better scalability in CI by enabling independent test/lint/build commands for each library - better scalability in your teams by allowing different teams to work on separate libraries ### Create a Local Library Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for these areas using the Vue library generator: ``` nx g @nx/vue:library products --unitTestRunner=vitest --bundler=vite --directory=modules/products --component ``` Note how we use the `--directory` flag to place the library into a subfolder. You can choose whatever folder structure you like to organize your libraries. Nx tries to set up your workspace to work with the modular library architecture, but depending on your existing configuration, you may need to tweak some settings. In this repo, you'll need to do a few things in order to prepare for future steps. #### Lint Settings We want the `lint` task for the root `vue-app` project to only lint the files for that project, so we'll change the `lint` command in `package.json`: ```json {% fileName="package.json" %} { "scripts": { "lint": "eslint src --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" } } ``` Now we need to update the `.eslintrc.cjs` file to extend the `.eslintrc.base.json` file: ```js {% fileName=".eslintrc.cjs" highlightLines=[11,13] %} /* eslint-env node */ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { root: true, extends: [ 'plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript', '@vue/eslint-config-prettier/skip-formatting', './.eslintrc.base.json', ], ignorePatterns: ['!**/*'], overrides: [ { files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], extends: ['plugin:playwright/recommended'], }, ], parserOptions: { ecmaVersion: 'latest', }, }; ``` #### Build Settings To make sure that the build can correctly pull in code from libraries, we need to move the typescript `paths` from the `tsconfig.app.json` file to the newly created `tsconfig.base.json` and extend that base file. ```json {% fileName="tsconfig.app.json" highlightLines=[2] %} { "extends": ["@vue/tsconfig/tsconfig.dom.json", "./tsconfig.base.json"], "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], "exclude": ["src/**/__tests__/*"] } ``` ```json {% fileName="tsconfig.vitest.json" highlightLines=[2] %} { "extends": "./tsconfig.app.json", "exclude": [], "compilerOptions": { "lib": [], "types": ["node", "jsdom"] } } ``` ```json {% fileName="tsconfig.base.json" highlightLines=["5-8"] %} { "compileOnSave": false, "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"], "products": ["modules/products/src/index.ts"] } } } ``` We also need to update `vite.config.ts` to account for typescript aliases. Run the following generator to automatically update your configuration file. ```shell npx nx g @nx/vite:setup-paths-plugin ``` This will update the `vite.config.ts` file to include the `nxViteTsPaths` plugin in the `plugins` array. ```ts {% fileName="vite.config.ts" highlightLines=[6,10] %} import { fileURLToPath, URL } from 'node:url'; import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue(), vueJsx(), nxViteTsPaths()], build: { outDir: 'dist/vue-app', }, resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, }); ``` ### Create More Libraries Now that the repository is set up, let's generate the `orders` and `ui` libraries. ``` nx g @nx/vue:library orders --unitTestRunner=vitest --bundler=vite --directory=modules/orders --component nx g @nx/vue:library ui --unitTestRunner=vitest --bundler=vite --directory=modules/shared/ui --component ``` Running the above commands should lead to the following directory structure: ``` └─ vue-app ├─ ... ├─ e2e/ ├─ modules │ ├─ products │ │ ├─ .eslintrc.json │ │ ├─ README.md │ │ ├─ vite.config.ts │ │ ├─ package.json │ │ ├─ project.json │ │ ├─ src │ │ │ ├─ index.ts │ │ │ └─ lib │ │ │ ├─ products.spec.ts │ │ │ └─ products.vue │ │ ├─ tsconfig.json │ │ ├─ tsconfig.lib.json │ │ ├─ tsconfig.spec.json │ │ └─ vite.config.ts │ ├─ orders │ │ ├─ ... │ │ ├─ project.json │ │ ├─ src │ │ │ ├─ index.ts │ │ │ └─ ... │ │ └─ ... │ └─ shared │ └─ ui │ ├─ ... │ ├─ project.json │ ├─ src │ │ ├─ index.ts │ │ └─ ... │ └─ ... ├─ src │ ├─ components │ ├─ ... │ ├─ App.vue │ └─ main.tsx ├─ ... ``` Each of these libraries - has a project details view where you can see the available tasks (e.g. running tests for just orders: `nx test orders`) - has its own `project.json` file where you can customize targets - has a dedicated `index.ts` file which is the "public API" of the library - is mapped in the `tsconfig.base.json` at the root of the workspace ### Importing Libraries into the Vue Application All libraries that we generate automatically have aliases created in the root-level `tsconfig.base.json`. ```json {% fileName="tsconfig.base.json" %} { "compilerOptions": { ... "paths": { "@/*": ["./src/*"], "orders": ["modules/orders/src/index.ts"], "products": ["modules/products/src/index.ts"], "ui": ["modules/shared/ui/src/index.ts"] }, ... }, } ``` That way we can easily import them into other libraries and our Vue application. As an example, let's import the `Products` component from the `products` project into our main application. First, configure the router in the `src/router/index.ts`. ```tsx {% fileName="src/router/index.ts" %} import { createRouter, createWebHistory } from 'vue-router'; import HomeView from '../views/HomeView.vue'; const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'home', component: HomeView, }, { path: '/about', name: 'about', // route level code-splitting // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import('../views/AboutView.vue'), }, { path: '/products', name: 'products', component: () => import('products').then((m) => m.Products), }, { path: '/orders', name: 'orders', component: () => import('orders').then((m) => m.Orders), }, ], }); export default router; ``` Then we can add links to the routes in `App.vue`. ```tsx {% fileName="src/App.vue" %}Welcome to Products!
``` If you lint your workspace you'll get an error now: ```{% command="nx run-many -t lint" %} ✔ nx run ui:lint [existing outputs match the cache, left as is] ✔ nx run orders:lint [existing outputs match the cache, left as is] —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— ✖ nx run products:lint > eslint . ~/vue-app/modules/products/src/lib/products.vue 5:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries ✖ 1 problem (1 error, 0 warnings) ✔ nx run vue-app:lint (892ms) ✔ nx run vue-app:lint (1s) —————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— NX Ran targets lint for 4 projects (1s) ✔ 4/5 succeeded [2 read from cache] ✖ 1/5 targets failed, including the following: - nx run products:lint ``` Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Migrating to a Monorepo When you are ready to add another application to the repo, you'll probably want to move `myvueapp` to its own folder. To do this, you can run the [`convert-to-monorepo` generator](/nx-api/workspace/generators/convert-to-monorepo) or [manually move the configuration files](/recipes/tips-n-tricks/standalone-to-integrated). ## Set Up CI for Your Vue App This tutorial walked you through how Nx can improve the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. - Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). - Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. - Nx Agents [efficiently distribute tasks across machines](/ci/concepts/parallelization-distribution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. - Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). ### Generate a CI Workflow If you are starting a new project, you can use the following command to generate a CI workflow file. ```shell npx nx generate ci-workflow --ci=github ``` {% callout type="note" title="Choose your CI provider" %} You can choose `github`, `circleci`, `azure`, `bitbucket-pipelines`, or `gitlab` for the `ci` flag. {% /callout %} This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. The key line in the CI pipeline is: ```yml - run: npx nx affected -t lint test build e2e-ci ``` ### Connect to Nx Cloud Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. To connect to Nx Cloud: - Commit and push your changes - Go to [https://cloud.nx.app](https://cloud.nx.app), create an account, and connect your repository #### Connect to Nx Cloud Manually If you are not able to connect via the automated process at [https://cloud.nx.app](https://cloud.nx.app), you can connect your workspace manually by running: ```shell npx nx connect ``` You will then need to merge your changes and connect to your workspace on [https://cloud.nx.app](https://cloud.nx.app). ### Enable a Distributed CI Pipeline The current CI pipeline runs on a single machine and can only handle small workspaces. To transform your CI into a CI that runs on multiple machines and can handle workspaces of any size, uncomment the `npx nx-cloud start-ci-run` line in the `.github/workflows/ci.yml` file. ```yml - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="e2e-ci" ``` For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: - [Circle CI with Nx](/ci/intro/tutorials/circle) - [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) ## Next Steps Connect with the rest of the Nx community with these resources: - [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx. - [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news - [Read our Nx blog](/blog) - [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights