From 45ce3b2a0ad5b08fcb82bb83bc6fb9d247e3b0c7 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Thu, 8 Dec 2022 20:36:45 +0200 Subject: [PATCH] feat(vite): update vite-tsconfig-paths (#13714) --- docs/generated/packages/vite.json | 2 +- docs/shared/vite-plugin.md | 2 - packages/vite/migrations.json | 22 ++- packages/vite/migrations.spec.ts | 12 ++ .../init/__snapshots__/init.spec.ts.snap | 2 +- .../vite/src/generators/vitest/vitest.spec.ts | 10 +- .../update-vite-tsconfig-paths.spec.ts | 35 ++++ .../update-vite-tsconfig-paths.ts | 100 ++++++++++++ packages/vite/src/utils/generator-utils.ts | 13 +- packages/vite/src/utils/options-utils.ts | 11 +- .../test-files/react-vite-project.config.json | 53 ++++++ packages/vite/src/utils/test-utils.ts | 153 ++++++++++++++++-- packages/vite/src/utils/versions.ts | 2 +- 13 files changed, 378 insertions(+), 39 deletions(-) create mode 100644 packages/vite/migrations.spec.ts create mode 100644 packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.spec.ts create mode 100644 packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.ts create mode 100644 packages/vite/src/utils/test-files/react-vite-project.config.json diff --git a/docs/generated/packages/vite.json b/docs/generated/packages/vite.json index eb22652a0d..01a7826aa6 100644 --- a/docs/generated/packages/vite.json +++ b/docs/generated/packages/vite.json @@ -11,7 +11,7 @@ "id": "overview", "path": "/packages/vite", "file": "shared/vite-plugin", - "content": "The Nx plugin for [Vite](https://vitejs.dev/) and [Vitest](https://vitest.dev/).\n\n[Vite.js](https://vitejs.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects.\n\nWhy should you use this plugin?\n\n- Instant dev server start\n- Lightning fast Hot-Module Reloading\n- _Fast_ builds using Vite.\n- Vite-powered tests with smart and instant watch mode\n\nRead more about Vite and Vitest in the [Vite documentation](https://vitejs.dev/).\n\n## Setting up Vite\n\nYou can create a new workspace that uses Vite with one of the following commands:\n\n- Generate a new monorepo with a Web Components app set up with Vite\n\n```shell\nnpx create-nx-workspace@latest --preset=web-components\n```\n\n- Generate a new standalone React app set up with Vite\n\n```shell\nnpx create-nx-workspace@latest --preset=react-standalone\n```\n\n### Add Vite to an existing workspace\n\nTo add the Vite plugin to an existing workspace, run the following:\n\n{% tabs %}\n{% tab label=\"npm\" %}\n\n```shell\nnpm install -D @nrwl/vite\n```\n\n{% /tab %}\n{% tab label=\"yarn\" %}\n\n```shell\nyarn add -D @nrwl/vite\n```\n\n{% /tab %}\n{% tab label=\"pnpm\" %}\n\n```shell\npnpm install -D @nrwl/vite\n```\n\n{% /tab %}\n{% /tabs %}\n\n### Initialize Vite.js\n\nAfter you install the plugin, you need to initialize Vite.js. You can do this by running the `init` executor. This executor will make sure to install all the necessary dependencies.\n\n```bash\nnx g @nrwl/vite:init\n```\n\n{% callout type=\"note\" title=\"Choosing a framework\" %}\nYou will notice that the executor will ask you of the framework you are planning to use. This is just to make sure that the right dependencies are installed. You can always install manually any other dependencies you need.\n{% /callout %}\n\n## Generate an application using Vite\n\nYou can generate a React or a Web application that uses Vite.js. The `@nrwl/react:app` and `@nrwl/web:app` generators accept the `bundler` option, where you can pass `vite`. This will generate a new application configured to use Vite.js, and it will also install all the necessary dependencies.\n\nTo generate a React application using Vite.js, run the following:\n\n```bash\nnx g @nrwl/react:app my-app --bundler=vite\n```\n\nTo generate a Web application using Vite.js, run the following:\n\n```bash\nnx g @nrwl/web:app my-app --bundler=vite\n```\n\n## Modify an existing React or Web application to use Vite.js\n\nYou can use the `@nrwl/vite:configuration` generator to change your React or Web application to use Vite.js. This generator will modify your application's configuration to use Vite.js, and it will also install all the necessary dependencies.\n\nYou can read more about this generator on the [`@nrwl/vite:configuration`](/packages/vite/generators/configuration) generator page.\n\n## Set up your apps to use Vite.js manually\n\nYou can use the `@nrwl/vite:dev-server` and the `@nrwl/vite:build` executors to serve and build your applications using Vite.js. To do this, you need to make a few adjustments to your application.\n\n{% github-repository url=\"https://github.com/mandarini/nx-recipes/tree/feat/react-vite-recipe/vite-example\" /%}\n\n### 1. Change the executors in your `project.json`\n\n#### The `serve` target\n\nIn your app's `project.json` file, change the executor of your `serve` target to use `@nrwl/vite:dev-server` and set it up with the following options:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"serve\": {\n \"executor\": \"@nrwl/vite:dev-server\",\n \"defaultConfiguration\": \"development\",\n \"options\": {\n \"buildTarget\": \"my-app:build\",\n \"port\": 4200,\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\n{% callout type=\"note\" title=\"Other options\" %}\nYou do not have to set the `port` here, necessarily. You can also specify the port in the `vite.config.ts` file (see **Step 2** below).\nThe same goes for all other Vite.js options that you can find the [Vite.js documentation](https://vitejs.dev/config/). All these can be added in your `vite.config.ts` file.\n{% /callout %}\n\n#### The `build` target\n\nIn your app's `project.json` file, change the executor of your `build` target to use `@nrwl/vite:build` and set it up with the following options:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"build\": {\n \"executor\": \"@nrwl/vite:build\",\n ...\n \"options\": {\n \"outputPath\": \"dist/apps/my-app\"\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\n{% callout type=\"note\" title=\"Other options\" %}\nYou can specify more options in the `vite.config.ts` file (see **Step 2** below).\n{% /callout %}\n\n### 2. Configure Vite.js\n\n#### TypeScript paths\n\nYou need to use the [`vite-tsconfig-paths` plugin](https://www.npmjs.com/package/vite-tsconfig-paths) to make sure that your TypeScript paths are resolved correctly in your monorepo.\n\n#### React plugin\n\nIf you are using React, you need to use the [`@vitejs/plugin-react` plugin](https://www.npmjs.com/package/@vitejs/plugin-react).\n\n#### How your `vite.config.ts` looks like\n\nAdd a `vite.config.ts` file to the root of your app. If you are not using React, you can skip adding the `react` plugin, of course.\n\n```ts\n// eg. apps/my-app/vite.config.ts\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';\n\nexport default defineConfig({\n plugins: [\n react(),\n ViteTsConfigPathsPlugin({\n root: '../../',\n projects: ['tsconfig.base.json'],\n }),\n ],\n});\n```\n\n{% callout type=\"note\" title=\"The `root` path\" %}\nMake sure the `root` path in the `ViteTsConfigPathsPlugin` options is correct. It should be the path to the root of your workspace.\n{% /callout %}\n\nIn that config file, you can configure Vite.js as you would normally do. For more information, see the [Vite.js documentation](https://vitejs.dev/config/).\n\n#### Creating a root `vite.config.ts` file\n\nYou can create a `vite.config.ts` file to the root of your workspace, as well as at the root of each of your applications. This file is used to configure Vite. You can read more about the configuration options in the [Vite documentation](https://vitejs.dev/config/).\n\nThe root `vite.config.ts` file can be used for all applications, and you can place in there general configurations that would apply for all your apps using Vite in your workspace. The application-specific `vite.config.ts` files can be used to override the root configuration, or, for example, import framework-specific plugins (eg. the `'@vitejs/plugin-react'` for React apps). The application-specific configuration files extend (using [`mergeConfig`](https://vitejs.dev/guide/api-javascript.html#mergeconfig)) the root configuration file. You can adjust this behavior to your needs.\n\nSo, if you are using a root `vite.config.ts` file, you should adjust your code as follows:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n plugins: [],\n});\n```\n\nand then in your app's `vite.config.ts` file:\n\n```ts\n// eg. apps/my-app/vite.config.ts\nimport { mergeConfig } from 'vite';\nimport baseConfig from '../../vite.config';\nimport react from '@vitejs/plugin-react';\nimport ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';\n\nexport default mergeConfig(baseConfig, {\n plugins: [\n react(),\n ViteTsConfigPathsPlugin({\n root: '../../',\n projects: ['tsconfig.base.json'],\n }),\n ],\n});\n```\n\n### 3. Move `index.html` and point it to your app's entrypoint\n\nFirst of all, move your `index.html` file to the root of your app (eg. from `apps/my-app/src/index.html` to `apps/my-app/index.html`).\n\nThen, add a module `script` tag pointing to the `main.tsx` (or `main.ts`) file of your app:\n\n```html\n...\n \n
\n \n \n\n```\n\n### 4. Add a `public` folder\n\nYou can add a `public` folder to the root of your app. You can read more about the public folder in the [Vite.js documentation](https://vitejs.dev/guide/assets.html#the-public-directory).\n\n```treeview\nmyorg/\n├── apps/\n│ ├── my-app/\n│ │ ├── src/\n│ │ │ ├── app/\n│ │ │ ├── assets/\n│ │ │ ├── ...\n│ │ │ └── main.tsx\n│ │ ├── index.html\n│ │ ├── public/\n| . | . | ├── favicon.ico\n│ │ │ └── my-page.md\n│ │ ├── project.json\n│ │ ├── ...\n│ │ ├── tsconfig.app.json\n│ │ ├── tsconfig.json\n│ │ └── tsconfig.spec.json\n```\n\nYou 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.\n\n### 5. Adjust your app's tsconfig.json\n\nChange your app's `tsconfig.json` (eg. `apps/my-app/tsconfig.json`) `compilerOptions` to the following:\n\n#### For React apps\n\n```json\n...\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"allowJs\": false,\n \"esModuleInterop\": false,\n \"allowSyntheticDefaultImports\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"isolatedModules\": true,\n \"lib\": [\"DOM\", \"DOM.Iterable\", \"ESNext\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Node\",\n \"noEmit\": true,\n \"resolveJsonModule\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"target\": \"ESNext\",\n \"types\": [\"vite/client\"],\n \"useDefineForClassFields\": true\n },\n...\n```\n\n#### For Web apps\n\n```json\n...\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"useDefineForClassFields\": true,\n \"module\": \"ESNext\",\n \"lib\": [\"ESNext\", \"DOM\"],\n \"moduleResolution\": \"Node\",\n \"strict\": true,\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"esModuleInterop\": true,\n \"noEmit\": true,\n \"noUnusedLocals\": true,\n \"noUnusedParameters\": true,\n \"noImplicitReturns\": true,\n \"skipLibCheck\": true,\n \"types\": [\"vite/client\"]\n },\n \"include\": [\"src\"],\n...\n```\n\nYou can read more about the TypeScript compiler options in the [Vite.js documentation](https://vitejs.dev/guide/features.html#typescript-compiler-options).\n\n### 6. Use Vite.js!\n\nNow you can finally serve and build your app using Vite.js:\n\n#### Serve the app\n\n```\nnx serve my-app\n```\n\nor\n\n```\nnx run my-app:serve\n```\n\nNow, visit [http://localhost:4200](http://localhost:4200) to see your app running!\n\n#### Build the app\n\n```\nnx build my-app\n```\n\nor\n\n```\nnx run my-app:build\n```\n" + "content": "The Nx plugin for [Vite](https://vitejs.dev/) and [Vitest](https://vitest.dev/).\n\n[Vite.js](https://vitejs.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects.\n\nWhy should you use this plugin?\n\n- Instant dev server start\n- Lightning fast Hot-Module Reloading\n- _Fast_ builds using Vite.\n- Vite-powered tests with smart and instant watch mode\n\nRead more about Vite and Vitest in the [Vite documentation](https://vitejs.dev/).\n\n## Setting up Vite\n\nYou can create a new workspace that uses Vite with one of the following commands:\n\n- Generate a new monorepo with a Web Components app set up with Vite\n\n```shell\nnpx create-nx-workspace@latest --preset=web-components\n```\n\n- Generate a new standalone React app set up with Vite\n\n```shell\nnpx create-nx-workspace@latest --preset=react-standalone\n```\n\n### Add Vite to an existing workspace\n\nTo add the Vite plugin to an existing workspace, run the following:\n\n{% tabs %}\n{% tab label=\"npm\" %}\n\n```shell\nnpm install -D @nrwl/vite\n```\n\n{% /tab %}\n{% tab label=\"yarn\" %}\n\n```shell\nyarn add -D @nrwl/vite\n```\n\n{% /tab %}\n{% tab label=\"pnpm\" %}\n\n```shell\npnpm install -D @nrwl/vite\n```\n\n{% /tab %}\n{% /tabs %}\n\n### Initialize Vite.js\n\nAfter you install the plugin, you need to initialize Vite.js. You can do this by running the `init` executor. This executor will make sure to install all the necessary dependencies.\n\n```bash\nnx g @nrwl/vite:init\n```\n\n{% callout type=\"note\" title=\"Choosing a framework\" %}\nYou will notice that the executor will ask you of the framework you are planning to use. This is just to make sure that the right dependencies are installed. You can always install manually any other dependencies you need.\n{% /callout %}\n\n## Generate an application using Vite\n\nYou can generate a React or a Web application that uses Vite.js. The `@nrwl/react:app` and `@nrwl/web:app` generators accept the `bundler` option, where you can pass `vite`. This will generate a new application configured to use Vite.js, and it will also install all the necessary dependencies.\n\nTo generate a React application using Vite.js, run the following:\n\n```bash\nnx g @nrwl/react:app my-app --bundler=vite\n```\n\nTo generate a Web application using Vite.js, run the following:\n\n```bash\nnx g @nrwl/web:app my-app --bundler=vite\n```\n\n## Modify an existing React or Web application to use Vite.js\n\nYou can use the `@nrwl/vite:configuration` generator to change your React or Web application to use Vite.js. This generator will modify your application's configuration to use Vite.js, and it will also install all the necessary dependencies.\n\nYou can read more about this generator on the [`@nrwl/vite:configuration`](/packages/vite/generators/configuration) generator page.\n\n## Set up your apps to use Vite.js manually\n\nYou can use the `@nrwl/vite:dev-server` and the `@nrwl/vite:build` executors to serve and build your applications using Vite.js. To do this, you need to make a few adjustments to your application.\n\n{% github-repository url=\"https://github.com/mandarini/nx-recipes/tree/feat/react-vite-recipe/vite-example\" /%}\n\n### 1. Change the executors in your `project.json`\n\n#### The `serve` target\n\nIn your app's `project.json` file, change the executor of your `serve` target to use `@nrwl/vite:dev-server` and set it up with the following options:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"serve\": {\n \"executor\": \"@nrwl/vite:dev-server\",\n \"defaultConfiguration\": \"development\",\n \"options\": {\n \"buildTarget\": \"my-app:build\",\n \"port\": 4200,\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\n{% callout type=\"note\" title=\"Other options\" %}\nYou do not have to set the `port` here, necessarily. You can also specify the port in the `vite.config.ts` file (see **Step 2** below).\nThe same goes for all other Vite.js options that you can find the [Vite.js documentation](https://vitejs.dev/config/). All these can be added in your `vite.config.ts` file.\n{% /callout %}\n\n#### The `build` target\n\nIn your app's `project.json` file, change the executor of your `build` target to use `@nrwl/vite:build` and set it up with the following options:\n\n```json\n//...\n\"my-app\": {\n \"targets\": {\n //...\n \"build\": {\n \"executor\": \"@nrwl/vite:build\",\n ...\n \"options\": {\n \"outputPath\": \"dist/apps/my-app\"\n },\n \"configurations\": {\n ...\n }\n },\n }\n}\n```\n\n{% callout type=\"note\" title=\"Other options\" %}\nYou can specify more options in the `vite.config.ts` file (see **Step 2** below).\n{% /callout %}\n\n### 2. Configure Vite.js\n\n#### TypeScript paths\n\nYou need to use the [`vite-tsconfig-paths` plugin](https://www.npmjs.com/package/vite-tsconfig-paths) to make sure that your TypeScript paths are resolved correctly in your monorepo.\n\n#### React plugin\n\nIf you are using React, you need to use the [`@vitejs/plugin-react` plugin](https://www.npmjs.com/package/@vitejs/plugin-react).\n\n#### How your `vite.config.ts` looks like\n\nAdd a `vite.config.ts` file to the root of your app. If you are not using React, you can skip adding the `react` plugin, of course.\n\n```ts\n// eg. apps/my-app/vite.config.ts\nimport { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';\n\nexport default defineConfig({\n plugins: [\n react(),\n ViteTsConfigPathsPlugin({\n root: '../../',\n }),\n ],\n});\n```\n\n{% callout type=\"note\" title=\"The `root` path\" %}\nMake sure the `root` path in the `ViteTsConfigPathsPlugin` options is correct. It should be the path to the root of your workspace.\n{% /callout %}\n\nIn that config file, you can configure Vite.js as you would normally do. For more information, see the [Vite.js documentation](https://vitejs.dev/config/).\n\n#### Creating a root `vite.config.ts` file\n\nYou can create a `vite.config.ts` file to the root of your workspace, as well as at the root of each of your applications. This file is used to configure Vite. You can read more about the configuration options in the [Vite documentation](https://vitejs.dev/config/).\n\nThe root `vite.config.ts` file can be used for all applications, and you can place in there general configurations that would apply for all your apps using Vite in your workspace. The application-specific `vite.config.ts` files can be used to override the root configuration, or, for example, import framework-specific plugins (eg. the `'@vitejs/plugin-react'` for React apps). The application-specific configuration files extend (using [`mergeConfig`](https://vitejs.dev/guide/api-javascript.html#mergeconfig)) the root configuration file. You can adjust this behavior to your needs.\n\nSo, if you are using a root `vite.config.ts` file, you should adjust your code as follows:\n\n```ts\n// vite.config.ts\nimport { defineConfig } from 'vite';\n\nexport default defineConfig({\n plugins: [],\n});\n```\n\nand then in your app's `vite.config.ts` file:\n\n```ts\n// eg. apps/my-app/vite.config.ts\nimport { mergeConfig } from 'vite';\nimport baseConfig from '../../vite.config';\nimport react from '@vitejs/plugin-react';\nimport ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';\n\nexport default mergeConfig(baseConfig, {\n plugins: [\n react(),\n ViteTsConfigPathsPlugin({\n root: '../../',\n }),\n ],\n});\n```\n\n### 3. Move `index.html` and point it to your app's entrypoint\n\nFirst of all, move your `index.html` file to the root of your app (eg. from `apps/my-app/src/index.html` to `apps/my-app/index.html`).\n\nThen, add a module `script` tag pointing to the `main.tsx` (or `main.ts`) file of your app:\n\n```html\n...\n \n
\n \n \n\n```\n\n### 4. Add a `public` folder\n\nYou can add a `public` folder to the root of your app. You can read more about the public folder in the [Vite.js documentation](https://vitejs.dev/guide/assets.html#the-public-directory).\n\n```treeview\nmyorg/\n├── apps/\n│ ├── my-app/\n│ │ ├── src/\n│ │ │ ├── app/\n│ │ │ ├── assets/\n│ │ │ ├── ...\n│ │ │ └── main.tsx\n│ │ ├── index.html\n│ │ ├── public/\n| . | . | ├── favicon.ico\n│ │ │ └── my-page.md\n│ │ ├── project.json\n│ │ ├── ...\n│ │ ├── tsconfig.app.json\n│ │ ├── tsconfig.json\n│ │ └── tsconfig.spec.json\n```\n\nYou 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.\n\n### 5. Adjust your app's tsconfig.json\n\nChange your app's `tsconfig.json` (eg. `apps/my-app/tsconfig.json`) `compilerOptions` to the following:\n\n#### For React apps\n\n```json\n...\n \"compilerOptions\": {\n \"jsx\": \"react-jsx\",\n \"allowJs\": false,\n \"esModuleInterop\": false,\n \"allowSyntheticDefaultImports\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"isolatedModules\": true,\n \"lib\": [\"DOM\", \"DOM.Iterable\", \"ESNext\"],\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Node\",\n \"noEmit\": true,\n \"resolveJsonModule\": true,\n \"skipLibCheck\": true,\n \"strict\": true,\n \"target\": \"ESNext\",\n \"types\": [\"vite/client\"],\n \"useDefineForClassFields\": true\n },\n...\n```\n\n#### For Web apps\n\n```json\n...\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"useDefineForClassFields\": true,\n \"module\": \"ESNext\",\n \"lib\": [\"ESNext\", \"DOM\"],\n \"moduleResolution\": \"Node\",\n \"strict\": true,\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"esModuleInterop\": true,\n \"noEmit\": true,\n \"noUnusedLocals\": true,\n \"noUnusedParameters\": true,\n \"noImplicitReturns\": true,\n \"skipLibCheck\": true,\n \"types\": [\"vite/client\"]\n },\n \"include\": [\"src\"],\n...\n```\n\nYou can read more about the TypeScript compiler options in the [Vite.js documentation](https://vitejs.dev/guide/features.html#typescript-compiler-options).\n\n### 6. Use Vite.js!\n\nNow you can finally serve and build your app using Vite.js:\n\n#### Serve the app\n\n```\nnx serve my-app\n```\n\nor\n\n```\nnx run my-app:serve\n```\n\nNow, visit [http://localhost:4200](http://localhost:4200) to see your app running!\n\n#### Build the app\n\n```\nnx build my-app\n```\n\nor\n\n```\nnx run my-app:build\n```\n" } ], "generators": [ diff --git a/docs/shared/vite-plugin.md b/docs/shared/vite-plugin.md index b67d60bffd..3c2e4edc60 100644 --- a/docs/shared/vite-plugin.md +++ b/docs/shared/vite-plugin.md @@ -178,7 +178,6 @@ export default defineConfig({ react(), ViteTsConfigPathsPlugin({ root: '../../', - projects: ['tsconfig.base.json'], }), ], }); @@ -221,7 +220,6 @@ export default mergeConfig(baseConfig, { react(), ViteTsConfigPathsPlugin({ root: '../../', - projects: ['tsconfig.base.json'], }), ], }); diff --git a/packages/vite/migrations.json b/packages/vite/migrations.json index 0967ef424b..77a7f7b6fc 100644 --- a/packages/vite/migrations.json +++ b/packages/vite/migrations.json @@ -1 +1,21 @@ -{} +{ + "schematics": { + "update-vite-tsconfig-paths": { + "cli": "nx", + "version": "15.3.1-beta.0", + "description": "Update vite-tsconfig-paths to 4.0.1 and remove projects property from vite.config.ts.", + "factory": "./src/migrations/update-15-3-1/update-vite-tsconfig-paths" + } + }, + "packageJsonUpdates": { + "15.3.1-beta.0": { + "version": "15.3.1-beta.0", + "packages": { + "vite-tsconfig-paths": { + "version": "^4.0.1", + "alwaysAddToPackageJson": true + } + } + } + } +} diff --git a/packages/vite/migrations.spec.ts b/packages/vite/migrations.spec.ts new file mode 100644 index 0000000000..90b54f2c09 --- /dev/null +++ b/packages/vite/migrations.spec.ts @@ -0,0 +1,12 @@ +import path = require('path'); +import json = require('./migrations.json'); + +describe('Vite migrations', () => { + it('should have valid paths', () => { + Object.values(json.schematics).forEach((m) => { + expect(() => + require.resolve(path.join(__dirname, `${m.factory}.ts`)) + ).not.toThrow(); + }); + }); +}); diff --git a/packages/vite/src/generators/init/__snapshots__/init.spec.ts.snap b/packages/vite/src/generators/init/__snapshots__/init.spec.ts.snap index 95efd18dc9..c471401b47 100644 --- a/packages/vite/src/generators/init/__snapshots__/init.spec.ts.snap +++ b/packages/vite/src/generators/init/__snapshots__/init.spec.ts.snap @@ -13,7 +13,7 @@ Object { "jsdom": "~20.0.3", "vite": "^3.0.5", "vite-plugin-eslint": "^1.6.0", - "vite-tsconfig-paths": "^3.5.2", + "vite-tsconfig-paths": "^4.0.1", "vitest": "^0.25.1", }, "name": "test-name", diff --git a/packages/vite/src/generators/vitest/vitest.spec.ts b/packages/vite/src/generators/vitest/vitest.spec.ts index 3d750ccf80..bb12b3d4f2 100644 --- a/packages/vite/src/generators/vitest/vitest.spec.ts +++ b/packages/vite/src/generators/vitest/vitest.spec.ts @@ -106,7 +106,7 @@ describe('vitest generator', () => { /// import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; - import tsconfigPaths from 'vite-tsconfig-paths'; + import viteTsConfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ @@ -118,9 +118,8 @@ describe('vitest generator', () => { plugins: [ react(), - tsconfigPaths({ + viteTsConfigPaths({ root: '../../', - projects: ['tsconfig.base.json'], }), ], @@ -150,7 +149,7 @@ describe('vitest generator', () => { /// import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; - import tsconfigPaths from 'vite-tsconfig-paths'; + import viteTsConfigPaths from 'vite-tsconfig-paths'; export default defineConfig({ @@ -162,9 +161,8 @@ describe('vitest generator', () => { plugins: [ react(), - tsconfigPaths({ + viteTsConfigPaths({ root: '../../', - projects: ['tsconfig.base.json'], }), ], diff --git a/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.spec.ts b/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.spec.ts new file mode 100644 index 0000000000..c1ef66fa25 --- /dev/null +++ b/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.spec.ts @@ -0,0 +1,35 @@ +import { addDependenciesToPackageJson, Tree } from '@nrwl/devkit'; +import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; +import { mockViteReactAppGenerator } from '../../utils/test-utils'; +import { + getTsSourceFile, + removeProjectsFromViteTsConfigPaths, +} from './update-vite-tsconfig-paths'; + +describe('remove projects from vite-tsconfig-paths', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyV1Workspace(); + mockViteReactAppGenerator(tree); + const existing = 'existing'; + const existingVersion = '1.0.0'; + addDependenciesToPackageJson( + tree, + { 'vite-tsconfig-paths': '^3.6.0', [existing]: existingVersion }, + { [existing]: existingVersion } + ); + }); + + it('should remove the projects attribute from vite-tsconfig-paths', async () => { + await removeProjectsFromViteTsConfigPaths(tree); + + const file = getTsSourceFile( + tree, + 'apps/my-test-react-vite-app/vite.config.ts' + ); + + expect(file.getText().includes('tsconfig.base.json')).toBeFalsy(); + expect(file.getText().includes('projects')).toBeFalsy(); + }); +}); diff --git a/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.ts b/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.ts new file mode 100644 index 0000000000..5bddf0978e --- /dev/null +++ b/packages/vite/src/migrations/update-15-3-1/update-vite-tsconfig-paths.ts @@ -0,0 +1,100 @@ +import { + applyChangesToString, + ChangeType, + formatFiles, + joinPathFragments, + readProjectConfiguration, + Tree, + workspaceRoot, +} from '@nrwl/devkit'; + +import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; +import { findNodes } from 'nx/src/utils/typescript'; +import ts = require('typescript'); + +export async function removeProjectsFromViteTsConfigPaths(tree: Tree) { + findAllProjectsWithViteConfig(tree); + await formatFiles(tree); +} + +function findAllProjectsWithViteConfig(tree: Tree): void { + forEachExecutorOptions(tree, '@nrwl/vite:build', (options, project) => { + const projectConfiguration = readProjectConfiguration(tree, project); + const viteConfig = normalizeConfigFilePathWithTree( + tree, + projectConfiguration.root, + options?.['configFile'], + workspaceRoot + ); + if (viteConfig) { + const file = getTsSourceFile(tree, viteConfig); + const appFileContent = tree.read(viteConfig, 'utf-8'); + let newContents = appFileContent; + const defineConfig = findNodes(file, [ts.SyntaxKind.CallExpression]); + let startOfProjects, endOfProjects; + defineConfig.forEach((node) => { + if (node.getText().startsWith('defineConfig')) { + node.getChildren().forEach((defineConfigContentNode) => { + // Make sure it's the one we are looking for + // We cannot assume that it's called tsConfigPaths + // So make sure it includes `projects` and `root` + if ( + defineConfigContentNode.getText().includes('projects') && + defineConfigContentNode.getText().includes('root') + ) { + findNodes(defineConfigContentNode, [ + ts.SyntaxKind.PropertyAssignment, + ]).forEach((nodePA) => { + if (nodePA.getText().startsWith('projects')) { + startOfProjects = nodePA.getStart(); + endOfProjects = nodePA.getEnd(); + } + }); + } + }); + } + }); + if (startOfProjects && endOfProjects) { + newContents = applyChangesToString(newContents, [ + { + type: ChangeType.Delete, + start: startOfProjects, + length: endOfProjects - startOfProjects + 1, + }, + ]); + tree.write(viteConfig, newContents); + } + } + }); +} + +export function getTsSourceFile(host: Tree, path: string): ts.SourceFile { + const buffer = host.read(path); + if (!buffer) { + throw new Error(`Could not read TS file (${path}).`); + } + const content = buffer.toString(); + const source = ts.createSourceFile( + path, + content, + ts.ScriptTarget.Latest, + true + ); + + return source; +} + +function normalizeConfigFilePathWithTree( + tree: Tree, + projectRoot: string, + configFile?: string, + workspaceRoot?: string +): string { + return configFile + ? joinPathFragments(`${workspaceRoot}/${configFile}`) + : tree.exists(joinPathFragments(`${projectRoot}/vite.config.ts`)) + ? joinPathFragments(`${projectRoot}/vite.config.ts`) + : tree.exists(joinPathFragments(`${projectRoot}/vite.config.js`)) + ? joinPathFragments(`${projectRoot}/vite.config.js`) + : undefined; +} diff --git a/packages/vite/src/utils/generator-utils.ts b/packages/vite/src/utils/generator-utils.ts index 42a344a340..46adee9081 100644 --- a/packages/vite/src/utils/generator-utils.ts +++ b/packages/vite/src/utils/generator-utils.ts @@ -405,16 +405,13 @@ export function writeViteConfig(tree: Tree, options: Schema) { host: 'localhost', },`; - const projectsTsConfig = tree.exists('tsconfig.base.json') - ? "'tsconfig.base.json'" - : ''; switch (options.uiFramework) { case 'react': viteConfigContent = ` ${options.includeVitest ? '/// ' : ''} import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; - import tsconfigPaths from 'vite-tsconfig-paths'; + import viteTsConfigPaths from 'vite-tsconfig-paths'; ${ options.includeLib ? `import dts from 'vite-plugin-dts';\nimport { join } from 'path';` @@ -426,9 +423,8 @@ ${options.includeVitest ? '/// ' : ''} plugins: [ ${options.includeLib ? dtsPlugin : ''} react(), - tsconfigPaths({ + viteTsConfigPaths({ root: '${offsetFromRoot(projectConfig.root)}', - projects: [${projectsTsConfig}], }), ], ${buildOption} @@ -440,7 +436,7 @@ ${options.includeVitest ? '/// ' : ''} viteConfigContent = ` ${options.includeVitest ? '/// ' : ''} import { defineConfig } from 'vite'; - import tsconfigPaths from 'vite-tsconfig-paths'; + import viteTsConfigPaths from 'vite-tsconfig-paths'; ${ options.includeLib ? `import dts from 'vite-plugin-dts';\nimport { join } from 'path';` @@ -451,9 +447,8 @@ ${options.includeVitest ? '/// ' : ''} ${serverOption} plugins: [ ${options.includeLib ? dtsPlugin : ''} - tsconfigPaths({ + viteTsConfigPaths({ root: '${offsetFromRoot(projectConfig.root)}', - projects: [${projectsTsConfig}], }), ], ${buildOption} diff --git a/packages/vite/src/utils/options-utils.ts b/packages/vite/src/utils/options-utils.ts index cb878905ea..2357a36d4c 100644 --- a/packages/vite/src/utils/options-utils.ts +++ b/packages/vite/src/utils/options-utils.ts @@ -4,6 +4,7 @@ import { logger, parseTargetString, readTargetOptions, + Tree, } from '@nrwl/devkit'; import { existsSync } from 'fs'; import { join, relative } from 'path'; @@ -32,9 +33,9 @@ export async function getBuildAndSharedConfig( root: projectRoot, base: options.base, configFile: normalizeConfigFilePath( + projectRoot, options.configFile, - context.root, - projectRoot + context.root ), plugins: [replaceFiles(options.fileReplacements)], build: getViteBuildOptions( @@ -45,9 +46,9 @@ export async function getBuildAndSharedConfig( } export function normalizeConfigFilePath( - configFile: string, - workspaceRoot: string, - projectRoot: string + projectRoot: string, + configFile?: string, + workspaceRoot?: string ): string { return configFile ? joinPathFragments(`${workspaceRoot}/${configFile}`) diff --git a/packages/vite/src/utils/test-files/react-vite-project.config.json b/packages/vite/src/utils/test-files/react-vite-project.config.json new file mode 100644 index 0000000000..55d8478666 --- /dev/null +++ b/packages/vite/src/utils/test-files/react-vite-project.config.json @@ -0,0 +1,53 @@ +{ + "name": "my-test-react-vite-app", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "root": "apps/my-test-react-vite-app", + "sourceRoot": "apps/my-test-react-vite-app/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@nrwl/vite:build", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "production", + "options": { + "outputPath": "dist/apps/my-test-react-vite-app" + }, + "configurations": { + "development": {}, + "production": {} + } + }, + "serve": { + "executor": "@nrwl/vite:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "my-test-react-vite-app:build" + }, + "configurations": { + "development": { + "buildTarget": "my-test-react-vite-app:build:development", + "hmr": true + }, + "production": { + "buildTarget": "my-test-react-vite-app:build:production", + "hmr": false + } + } + }, + "test": { + "executor": "@nrwl/vite:test", + "outputs": ["{projectRoot}/coverage"], + "options": { + "passWithNoTests": true + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/my-test-react-vite-app/**/*.{ts,tsx,js,jsx}"] + } + } + }, + "tags": [] +} diff --git a/packages/vite/src/utils/test-utils.ts b/packages/vite/src/utils/test-utils.ts index a2b0a88923..4faf674f72 100644 --- a/packages/vite/src/utils/test-utils.ts +++ b/packages/vite/src/utils/test-utils.ts @@ -1,7 +1,139 @@ import { Tree, writeJson } from '@nrwl/devkit'; import * as reactAppConfig from './test-files/react-project.config.json'; +import * as reactViteConfig from './test-files/react-vite-project.config.json'; import * as webAppConfig from './test-files/web-project.config.json'; +export function mockViteReactAppGenerator(tree: Tree): Tree { + const appName = 'my-test-react-vite-app'; + + tree.write( + `apps/${appName}/src/main.tsx`, + `import ReactDOM from 'react-dom';\n` + ); + + tree.write( + `apps/${appName}/tsconfig.json`, + `{ + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": false, + "esModuleInterop": false, + "allowSyntheticDefaultImports": true, + "strict": true, + "types": ["vite/client"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" + } + ` + ); + tree.write( + `apps/${appName}/tsconfig.app.json`, + `{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "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/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] + } + ` + ); + + tree.write( + `apps/${appName}/index.html`, + ` + + + + Rv1 + + + + + + + +
+ + + ` + ); + + tree.write( + `apps/${appName}/vite.config.ts`, + `/// + import { defineConfig } from 'vite'; + import react from '@vitejs/plugin-react'; + import tsconfigPaths from 'vite-tsconfig-paths'; + + export default defineConfig({ + server: { + port: 4200, + host: 'localhost', + }, + plugins: [ + react(), + tsconfigPaths({ + root: '../../', + projects: ['tsconfig.base.json'], + }), + ], + + test: { + globals: true, + cache: { + dir: '../../node_modules/.vitest', + }, + environment: 'jsdom', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + }, + }); + ` + ); + + writeJson(tree, 'workspace.json', { + projects: { + 'my-test-react-vite-app': { + ...reactViteConfig, + root: `apps/${appName}`, + projectType: 'application', + }, + }, + }); + + writeJson(tree, `apps/${appName}/project.json`, { + ...reactViteConfig, + root: `apps/${appName}`, + projectType: 'application', + }); + + return tree; +} + export function mockReactAppGenerator(tree: Tree): Tree { const appName = 'my-test-react-app'; @@ -84,20 +216,15 @@ export function mockReactAppGenerator(tree: Tree): Tree { ` ); - writeJson( - tree, - 'workspace.json', - - { - projects: { - 'my-test-react-app': { - ...reactAppConfig, - root: `apps/${appName}`, - projectType: 'application', - }, + writeJson(tree, 'workspace.json', { + projects: { + 'my-test-react-app': { + ...reactAppConfig, + root: `apps/${appName}`, + projectType: 'application', }, - } - ); + }, + }); writeJson(tree, `apps/${appName}/project.json`, { ...reactAppConfig, diff --git a/packages/vite/src/utils/versions.ts b/packages/vite/src/utils/versions.ts index d164b976a3..00e0cebea1 100644 --- a/packages/vite/src/utils/versions.ts +++ b/packages/vite/src/utils/versions.ts @@ -6,7 +6,7 @@ export const vitestUiVersion = '^0.9.3'; export const vitePluginReactVersion = '^2.2.0'; export const vitePluginVueVersion = '^3.2.0'; export const vitePluginVueJsxVersion = '^2.1.1'; -export const viteTsConfigPathsVersion = '^3.5.2'; +export const viteTsConfigPathsVersion = '^4.0.1'; export const jsdomVersion = '~20.0.3'; export const vitePluginDtsVersion = '~1.7.1';