Skip to content

Commit

Permalink
Merge branch 'main' into fix/13
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored Oct 26, 2023
2 parents ec2c0ce + bca91c8 commit c3fac74
Show file tree
Hide file tree
Showing 40 changed files with 860 additions and 287 deletions.
4 changes: 4 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ export default defineConfig({
text: 'Troubleshooting',
link: '/guide/troubleshooting',
},
{
text: 'Performance',
link: '/guide/performance',
},
{
text: 'Philosophy',
link: '/guide/philosophy',
Expand Down
16 changes: 5 additions & 11 deletions docs/config/server-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,26 +177,20 @@ The error that appears in the Browser when the fallback happens can be ignored.
## server.warmup

- **Type:** `{ clientFiles?: string[], ssrFiles?: string[] }`
- **Related:** [Warm Up Frequently Used Files](/guide/performance.html#warm-up-frequently-used-files)

Warm up files to transform and cache the results in advance. This improves the initial page load during server starts and prevents transform waterfalls.

The `clientFiles` and `ssrFiles` options accept an array of file paths or glob patterns relative to the `root`. Make sure to only add files that are hot code, as otherwise adding too many may slow down the transform process.
`clientFiles` are files that are used in the client only, while `ssrFiles` are files that are used in SSR only. They accept an array of file paths or [`fast-glob`](https://github.com/mrmlnc/fast-glob) patterns relative to the `root`.

To understand why warmup can be useful, here's an example. Given this module graph where the left file imports the right file:

```
main.js -> Component.vue -> big-file.js -> large-data.json
```

The imported ids can only be known after the file is transformed, so if `Component.vue` takes some time to transform, `big-file.js` has to wait for it's turn, and so on. This causes an internal waterfall.

By warming up `big-file.js`, or any files that you know is hot path in your app, they'll be cached and can be served immediately.
Make sure to only add files that are frequently used to not overload the Vite dev server on startup.

```js
export default defineConfig({
server: {
warmup: {
clientFiles: ['./src/big-file.js', './src/components/*.vue'],
clientFiles: ['./src/components/*.vue', './src/utils/big-utils.js'],
ssrFiles: ['./src/server/modules/*.js'],
},
},
})
Expand Down
45 changes: 11 additions & 34 deletions docs/config/shared-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,18 @@ See [Env Variables and Modes](/guide/env-and-mode) for more details.

Define global constant replacements. Entries will be defined as globals during dev and statically replaced during build.

- String values will be used as raw expressions, so if defining a string constant, **it needs to be explicitly quoted** (e.g. with `JSON.stringify`).
Vite uses [esbuild defines](https://esbuild.github.io/api/#define) to perform replacements, so value expressions must be a string that contains a JSON-serializable value (null, boolean, number, string, array, or object) or a single identifier. For non-string values, Vite will automatically convert it to a string with `JSON.stringify`.

- To be consistent with [esbuild behavior](https://esbuild.github.io/api/#define), expressions must either be a JSON object (null, boolean, number, string, array, or object) or a single identifier.

- Replacements are performed only when the match isn't surrounded by other letters, numbers, `_` or `$`.

::: warning
Because it's implemented as straightforward text replacements without any syntax analysis, we recommend using `define` for CONSTANTS only.
**Example:**

For example, `process.env.FOO` and `__APP_VERSION__` are good fits. But `process` or `global` should not be put into this option. Variables can be shimmed or polyfilled instead.
:::
```js
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify('v1.0.0'),
__API_URL__: 'window.__backend_api_url',
},
})
```

::: tip NOTE
For TypeScript users, make sure to add the type declarations in the `env.d.ts` or `vite-env.d.ts` file to get type checks and Intellisense.
Expand All @@ -61,20 +62,6 @@ declare const __APP_VERSION__: string
:::
::: tip NOTE
Since dev and build implement `define` differently, we should avoid some use cases to avoid inconsistency.
Example:
```js
const obj = {
__NAME__, // Don't define object shorthand property names
__KEY__: value, // Don't define object key
}
```

:::

## plugins
- **Type:** `(Plugin | Plugin[] | Promise<Plugin | Plugin[]>)[]`
Expand Down Expand Up @@ -154,20 +141,10 @@ Export keys ending with "/" is deprecated by Node and may not work well. Please
## resolve.mainFields

- **Type:** `string[]`
- **Default:** `['module', 'jsnext:main', 'jsnext']`
- **Default:** `['browser', 'module', 'jsnext:main', 'jsnext']`

List of fields in `package.json` to try when resolving a package's entry point. Note this takes lower precedence than conditional exports resolved from the `exports` field: if an entry point is successfully resolved from `exports`, the main field will be ignored.

## resolve.browserField

- **Type:** `boolean`
- **Default:** `true`
- **Deprecated**

Whether to enable resolving to `browser` field.

In future, `resolve.mainFields`'s default value will be `['browser', 'module', 'jsnext:main', 'jsnext']` and this option will be removed.

## resolve.extensions

- **Type:** `string[]`
Expand Down
40 changes: 40 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,42 @@ For other projects, there are a few general approaches:

See the [troubleshooting guide](/guide/troubleshooting.html#vite-cjs-node-api-deprecated) for more information.

## Rework `define` and `import.meta.env.*` replacement strategy

In Vite 4, the `define` and `import.meta.env.*` features use different replacement strategies in dev and build:

- In dev, both features are injected as global variables to `globalThis` and `import.meta` respectively.
- In build, both features are statically replaced with a regex.

This results in a dev and build inconsistency when trying to access the variables, and sometimes even caused failed builds. For example:

```js
// vite.config.js
export default defineConfig({
define: {
__APP_VERSION__: JSON.stringify('1.0.0'),
},
})
```

```js
const data = { __APP_VERSION__ }
// dev: { __APP_VERSION__: "1.0.0" } ✅
// build: { "1.0.0" } ❌

const docs = 'I like import.meta.env.MODE'
// dev: "I like import.meta.env.MODE" ✅
// build: "I like "production"" ❌
```

Vite 5 fixes this by using `esbuild` to handle the replacements in builds, aligning with the dev behaviour.

This change should not affect most setups, as it's already documented that `define` values should follow esbuild's syntax:

> To be consistent with esbuild behavior, expressions must either be a JSON object (null, boolean, number, string, array, or object) or a single identifier.
However, if you prefer to keep statically replacing values directly, you can use [`@rollup/plugin-replace`](https://github.com/rollup/plugins/tree/master/packages/replace).

## General Changes

### SSR externalized modules value now matches production
Expand Down Expand Up @@ -133,6 +169,10 @@ Also there are other breaking changes which only affect few users.
- Renamed `ResolveWorkerOptions` type to `ResolvedWorkerOptions`
- [[#5657] fix: return 404 for resources requests outside the base path](https://github.com/vitejs/vite/pull/5657)
- In the past, Vite responded to requests outside the base path without `Accept: text/html`, as if they were requested with the base path. Vite no longer does that and responds with 404 instead.
- [[#14723] fix(resolve)!: remove special .mjs handling](https://github.com/vitejs/vite/pull/14723)
- In the past, when a library `"exports"` field maps to an `.mjs` file, Vite will still try to match the `"browser"` and `"module"` fields to fix compatibility with certain libraries. This behavior is now removed to align with the exports resolution algorithm.
- [[#14733] feat(resolve)!: remove `resolve.browserField`](https://github.com/vitejs/vite/pull/14733)
- `resolve.browserField` has been deprecated since Vite 3 in favour of an updated default of `['browser', 'module', 'jsnext:main', 'jsnext']` for `resolve.mainFields`.

## Migration from v3

Expand Down
102 changes: 102 additions & 0 deletions docs/guide/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Performance

While Vite is fast by default, performance issues can creep in as the project's requirements grow. This guide aims to help you identify and fix common performance issues, such as:

- Slow server starts
- Slow page loads
- Slow builds

## Audit Configured Vite Plugins

Vite's internal and official plugins are optimized to do the least amount of work possible while providing compatibility with the broader ecosystem. For example, code transformations use regex in dev, but do a complete parse in build to ensure correctness.

However, the performance of community plugins is out of Vite's control, which may affect the developer experience. Here are a few things you can look out for when using additional Vite plugins:

1. The `buildStart`, `config`, and `configResolved` hooks should not run long and extensive operations. These hooks are awaited during dev server startup, which delays when you can access the site in the browser.

2. The `resolveId`, `load`, and `transform` hooks may cause some files to load slower than others. While sometimes unavoidable, it's still worth checking for possible areas to optimize. For example, checking if the `code` contains a specific keyword, or the `id` matches a specific extension, before doing the full transformation.

The longer it takes to transform a file, the more significant the request waterfall will be when loading the site in the browser.

You can inspect the duration it takes to transform a file using `DEBUG="vite:plugin-transform" vite` or [vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect). Note that as asynchronous operations tend to provide inaccurate timings, you should treat the numbers as a rough estimate, but it should still reveal the more expensive operations.

::: tip Profiling
You can run `vite --profile`, visit the site, and press `p + enter` in your terminal to record a `.cpuprofile`. A tool like [speedscope](https://www.speedscope.app) can then be used to inspect the profile and identify the bottlenecks. You can also [share the profiles](https://chat.vitejs.dev) with the Vite team to help us identify performance issues.
:::

## Reduce Resolve Operations

Resolving import paths can be an expensive operation when hitting its worst case often. For example, Vite supports "guessing" import paths with the [`resolve.extensions`](/config/shared-options.md#resolve-extensions) option, which defaults to `['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']`.

When you try to import `./Component.jsx` with `import './Component'`, Vite will run these steps to resolve it:

1. Check if `./Component` exists, no.
2. Check if `./Component.mjs` exists, no.
3. Check if `./Component.js` exists, no.
4. Check if `./Component.mts` exists, no.
5. Check if `./Component.ts` exists, no.
6. Check if `./Component.jsx` exists, yes!

As shown, a total of 6 filesystem checks is required to resolve an import path. The more implicit imports you have, the more time it adds up to resolve the paths.

Hence, it's usually better to be explicit with your import paths, e.g. `import './Component.jsx'`. You can also narrow down the list for `resolve.extensions` to reduce the general filesystem checks, but you have to make sure it works for files in `node_modules` too.

If you're a plugin author, make sure to only call [`this.resolve`](https://rollupjs.org/plugin-development/#this-resolve) when needed to reduce the number of checks above.

::: tip TypeScript
If you are using TypeScript, enable `"moduleResolution": "bundler"` and `"allowImportingTsExtensions": true` in your `tsconfig.json`'s `compilerOptions` to use `.ts` and `.tsx` extensions directly in your code.
:::

## Avoid Barrel Files

Barrel files are files that re-export the APIs of other files in the same directory. For example:

```js
// src/utils/index.js
export * from './color'
export * from './dom'
export * from './string'
```

When you only import an individual API, e.g. `import { slash } from './utils'`, all the files in that barrel file need to be fetched and transformed as they may contain the `slash` API and may also contain side-effects that run on initialization. This means you're loading more files than required on the initial page load, resulting in a slower page load.

If possible, you should avoid barrel files and import the individual APIs directly, e.g. `import { slash } from './utils/slash'`. You can read [issue #8237](https://github.com/vitejs/vite/issues/8237) for more information.

## Warm Up Frequently Used Files

The Vite dev server only transforms files as requested by the browser, which allows it to start up quickly and only apply transformations for used files. It can also pre-transform files if it anticipates certain files will be requested shortly. However, request waterfalls may still happen if some files take longer to transform than others. For example:

Given an import graph where the left file imports the right file:

```
main.js -> BigComponent.vue -> big-utils.js -> large-data.json
```

The import relationship can only be known after the file is transformed. If `BigComponent.vue` takes some time to transform, `big-utils.js` has to wait for its turn, and so on. This causes an internal waterfall even with pre-transformation built-in.

Vite allows you to warm up files that you know are frequently used, e.g. `big-utils.js`, using the [`server.warmup`](/config/server-options.md#server-warmup) option. This way `big-utils.js` will be ready and cached to be served immediately when requested.

You can find files that are frequently used by running `DEBUG="vite:transform" vite` and inspect the logs:

```bash
vite:transform 28.72ms /@vite/client +1ms
vite:transform 62.95ms /src/components/BigComponent.vue +1ms
vite:transform 102.54ms /src/utils/big-utils.js +1ms
```

```js
export default defineConfig({
server: {
warmup: {
clientFiles: [
'./src/components/BigComponent.vue',
'./src/utils/big-utils.js',
],
},
},
})
```

Note that you should only warm up files that are frequently used to not overload the Vite dev server on startup. Check the [`server.warmup`](/config/server-options.md#server-warmup) option for more information.

Using [`--open` or `server.open`](/config/server-options.html#server-open) also provides a performance boost, as Vite will automatically warm up the entry point of your app or the provided URL to open.
6 changes: 3 additions & 3 deletions docs/guide/static-deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Now the `preview` command will launch the server at `http://localhost:8080`.
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v3
with:
Expand All @@ -109,13 +109,13 @@ Now the `preview` command will launch the server at `http://localhost:8080`.
- name: Setup Pages
uses: actions/configure-pages@v3
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v2
with:
# Upload dist repository
path: './dist'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v2
```
## GitLab Pages and GitLab CI
Expand Down
11 changes: 11 additions & 0 deletions packages/vite/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## 5.0.0-beta.12 (2023-10-23)

* fix(resolve)!: remove special .mjs handling (#14723) ([2141d31](https://github.com/vitejs/vite/commit/2141d31)), closes [#14723](https://github.com/vitejs/vite/issues/14723)
* fix(assets): fix svg inline in css url (#14714) ([eef4aaa](https://github.com/vitejs/vite/commit/eef4aaa)), closes [#14714](https://github.com/vitejs/vite/issues/14714)
* fix(resolve): make directory package.json check best effort (#14626) ([d520388](https://github.com/vitejs/vite/commit/d520388)), closes [#14626](https://github.com/vitejs/vite/issues/14626)
* docs: port 4.4.10 to 4.5 changelog to main (#14732) ([2728a31](https://github.com/vitejs/vite/commit/2728a31)), closes [#14732](https://github.com/vitejs/vite/issues/14732)
* refactor(ssr): remove unused metadata code (#14711) ([c5f2d60](https://github.com/vitejs/vite/commit/c5f2d60)), closes [#14711](https://github.com/vitejs/vite/issues/14711)
* chore: link migration guide to changelog (#14699) ([4cedcdc](https://github.com/vitejs/vite/commit/4cedcdc)), closes [#14699](https://github.com/vitejs/vite/issues/14699)



## 5.0.0-beta.11 (2023-10-19)

Learn more at the [Vite 5 Migration guide](https://main.vitejs.dev/guide/migration) and help us test the beta!
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vite",
"version": "5.0.0-beta.11",
"version": "5.0.0-beta.12",
"type": "module",
"license": "MIT",
"author": "Evan You",
Expand Down
23 changes: 11 additions & 12 deletions packages/vite/src/node/__tests__/plugins/define.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ async function createDefinePluginTransform(
build = true,
ssr = false,
) {
const config = await resolveConfig({ define }, build ? 'build' : 'serve')
const config = await resolveConfig(
{ configFile: false, define },
build ? 'build' : 'serve',
)
const instance = definePlugin(config)
return async (code: string) => {
const result = await (instance.transform as any).call({}, code, 'foo.ts', {
ssr,
})
// @ts-expect-error transform should exist
const result = await instance.transform.call({}, code, 'foo.ts', { ssr })
return result?.code || result
}
}
Expand All @@ -23,35 +25,32 @@ describe('definePlugin', () => {
__APP_VERSION__: JSON.stringify('1.0'),
})
expect(await transform('const version = __APP_VERSION__ ;')).toBe(
'const version = "1.0" ;',
'const version = "1.0";\n',
)
expect(await transform('const version = __APP_VERSION__;')).toBe(
'const version = "1.0";',
'const version = "1.0";\n',
)
})

test('replaces import.meta.env.SSR with false', async () => {
const transform = await createDefinePluginTransform()
expect(await transform('const isSSR = import.meta.env.SSR ;')).toBe(
'const isSSR = false ;',
)
expect(await transform('const isSSR = import.meta.env.SSR;')).toBe(
'const isSSR = false;',
'const isSSR = false;\n',
)
})

test('preserve import.meta.hot with override', async () => {
// assert that the default behavior is to replace import.meta.hot with undefined
const transform = await createDefinePluginTransform()
expect(await transform('const hot = import.meta.hot;')).toBe(
'const hot = undefined;',
'const hot = void 0;\n',
)
// assert that we can specify a user define to preserve import.meta.hot
const overrideTransform = await createDefinePluginTransform({
'import.meta.hot': 'import.meta.hot',
})
expect(await overrideTransform('const hot = import.meta.hot;')).toBe(
'const hot = import.meta.hot;',
undefined,
)
})
})
9 changes: 9 additions & 0 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,15 @@ export function onRollupWarning(
return
}

// Rollup tracks the build phase slightly earlier before `buildEnd` is called,
// so there's a chance we can call `this.addWatchFile` in the invalid phase. Skip for now.
if (
warning.plugin === 'vite:worker-import-meta-url' &&
warning.pluginCode === 'INVALID_ROLLUP_PHASE'
) {
return
}

if (warningIgnoreList.includes(warning.code!)) {
return
}
Expand Down
Loading

0 comments on commit c3fac74

Please sign in to comment.