Skip to content

Commit

Permalink
feat(bundling): vite plugin executors (#13032)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Nov 14, 2022
1 parent 2a671e7 commit 8d103f3
Show file tree
Hide file tree
Showing 23 changed files with 1,534 additions and 13 deletions.
225 changes: 223 additions & 2 deletions docs/generated/packages/vite.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/packages.json
Expand Up @@ -373,7 +373,7 @@
"packageName": "vite",
"description": "The Nx Plugin for building and testing applications using Vite (Early Release)",
"path": "generated/packages/vite.json",
"schemas": { "executors": [], "generators": ["init"] }
"schemas": { "executors": ["dev-server", "build"], "generators": ["init"] }
},
{
"name": "web",
Expand Down
208 changes: 207 additions & 1 deletion docs/shared/vite-plugin.md
Expand Up @@ -4,16 +4,22 @@ The Nx plugin for [Vite](https://vitejs.dev/) and [Vitest](https://vitest.dev/).
This Nx plugin is in active development and may not be ready for real-world use. The planned release date for the stable plugin is December, 2022.
{% /callout %}

[Vite.js](https://vitejs.dev/) is a build tool that aims to provide a faster and leaner development experience for modern web projects.

Why should you use this plugin?

- Instant dev server start
- Lightning fast Hot-Module Reloading
- _Fast_ builds using Vite.
- Vite-powered tests with smart and instant watch mode

Read more about Vite and Vitest in the [Vite documentation](https://vitejs.dev/).

## Setting up Vite

To create a new workspace, run `npx create-nx-workspace@latest --preset=npm`.
To create a new workspace, run `npx create-nx-workspace@latest --preset=vite`.

### Add Vite to an existing workspace

To add the Vite plugin to an existing workspace, run the following:

Expand All @@ -40,3 +46,203 @@ pnpm install -D @nrwl/vite

{% /tab %}
{% /tabs %}

### Initialize Vite.js

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

```bash
nx g @nrwl/vite:init
```

{% callout type="note" title="Choosing a framework" %}
You 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.
{% /callout %}

## Using Vite.js in a React application

You can use the `@nrwl/vite:dev-server` and the `@nrwl/vite:build` executors to serve and build your React applications using Vite.js. To do this, you need to make a few adjustments to your application.

{% github-repository url="https://github.com/mandarini/nx-recipes/tree/feat/react-vite-recipe/react-vite" /%}

### 1. Change the executors in your `project.json`

#### The `serve` target

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

```json
//...
"my-app": {
"targets": {
//...
"serve": {
"executor": "@nrwl/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "my-app:build",
"port": 4200,
},
"configurations": {
...
}
},
}
}
```

{% callout type="note" title="Other options" %}
You 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).
The 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.
{% /callout %}

#### The `build` target

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

```json
//...
"my-app": {
"targets": {
//...
"build": {
"executor": "@nrwl/vite:build",
...
"options": {
"outputPath": "dist/apps/my-app"
},
"configurations": {
...
}
},
}
}
```

{% callout type="note" title="Other options" %}
You can specify more options in the `vite.config.ts` file (see **Step 2** below).
{% /callout %}

### 2. Configure Vite.js

Add a `vite.config.ts` file to the root of your app, and add the `'@vitejs/plugin-react'` plugin to it:

```ts
// eg. apps/my-app/vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import ViteTsConfigPathsPlugin from 'vite-tsconfig-paths';

export default defineConfig({
plugins: [
react(),
ViteTsConfigPathsPlugin({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
});
```

{% callout type="note" title="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.
{% /callout %}

In 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/).

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

First 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`).

Then, add a module `script` tag pointing to the `main.tsx` file of your app:

```html
...
<body>
<div id="root"></div>
<script type="module" src="src/main.tsx"></script>
</body>
</html>
```

### 4. Add a `public` folder

You 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). Use that folder as you would normally do.

```treeview
myorg/
├── apps/
│ ├── my-app/
│ │ ├── src/
│ │ │ ├── app/
│ │ │ ├── assets/
│ │ │ ├── ...
│ │ │ └── main.tsx
│ │ ├── index.html
│ │ ├── public/
│ │ │ └── my-page.md
│ │ ├── project.json
│ │ ├── ...
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ └── tsconfig.spec.json
```

### 5. Adjust your app's tsconfig.json

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

```json
...
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"moduleResolution": "Node",
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ESNext",
"types": ["vite/client"],
"useDefineForClassFields": true
},
...
```

You can read more about the TypeScript compiler options in the [Vite.js documentation](https://vitejs.dev/guide/features.html#typescript-compiler-options).

### 6. Use Vite.js!

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

#### Serve the app

```
nx serve my-app
```

or

```
nx run my-app:serve
```

Now, visit [http://localhost:4200](http://localhost:4200) to see your app running!

#### Build the app

```
nx build my-app
```

or

```
nx run my-app:build
```
128 changes: 124 additions & 4 deletions e2e/vite/src/vite.test.ts
@@ -1,15 +1,135 @@
import { cleanupProject, newProject } from '@nrwl/e2e/utils';
import {
cleanupProject,
createFile,
killPorts,
newProject,
readFile,
rmDist,
runCLI,
runCommandUntil,
uniq,
updateFile,
updateProjectConfig,
} from '@nrwl/e2e/utils';

const myApp = uniq('my-app');

describe('Vite Plugin', () => {
let proj: string;

beforeEach(() => (proj = newProject()));
beforeEach(() => {
proj = newProject();
runCLI(`generate @nrwl/react:app ${myApp}`);
runCLI(`generate @nrwl/vite:init`);
updateFile(
`apps/${myApp}/index.html`,
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My App</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<div id="root"></div>
<script type="module" src="src/main.tsx"></script>
</body>
</html>
`
);

createFile(
`apps/${myApp}/vite.config.ts`,
`
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import plugin from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
react(),
plugin({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
});`
);

updateFile(
`apps/${myApp}/tsconfig.json`,
`
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"moduleResolution": "Node",
"noEmit": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ESNext",
"types": ["vite/client"],
"useDefineForClassFields": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
`
);

updateProjectConfig(myApp, (config) => {
config.targets.build.executor = '@nrwl/vite:build';
config.targets.serve.executor = '@nrwl/vite:dev-server';

config.targets.build.options = {
outputPath: `dist/apps/${myApp}`,
};

config.targets.serve.options = {
buildTarget: `${myApp}:build`,
};

return config;
});
});
afterEach(() => cleanupProject());

xit('should build applications', () => {});
it('should build applications', async () => {
runCLI(`build ${myApp}`);
expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined();
rmDist();
}, 200000);

describe('serve using Vite', () => {
afterEach(() => killPorts());

xit('should serve applications in dev mode', () => {});
it('should serve applications in dev mode', async () => {
const p = await runCommandUntil(`run ${myApp}:serve`, (output) => {
return output.includes('Local:');
});
p.kill();
}, 200000);
});

xit('should test applications', () => {});
});
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -240,6 +240,7 @@
"unzipper": "^0.10.11",
"url-loader": "^4.1.1",
"verdaccio": "^5.0.4",
"vite": "^3.2.3",
"webpack": "^5.58.1",
"webpack-dev-server": "^4.9.3",
"webpack-merge": "^5.8.0",
Expand Down

1 comment on commit 8d103f3

@vercel
Copy link

@vercel vercel bot commented on 8d103f3 Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx.dev

Please sign in to comment.