Skip to content

Commit 7234021

Browse files
authored
refactor(esbuild)!: remove esbuild 0.17 -> 0.18 compat (#14804)
1 parent 4f71ae8 commit 7234021

File tree

8 files changed

+65
-80
lines changed

8 files changed

+65
-80
lines changed

docs/guide/features.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ Some configuration fields under `compilerOptions` in `tsconfig.json` require spe
5757

5858
#### `isolatedModules`
5959

60+
- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#isolatedModules)
61+
6062
Should be set to `true`.
6163

6264
It is because `esbuild` only performs transpilation without type information, it doesn't support certain features like const enum and implicit type-only imports.
@@ -67,8 +69,12 @@ However, some libraries (e.g. [`vue`](https://github.com/vuejs/core/issues/1228)
6769

6870
#### `useDefineForClassFields`
6971

72+
- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#useDefineForClassFields)
73+
7074
Starting from Vite 2.5.0, the default value will be `true` if the TypeScript target is `ESNext` or `ES2022` or newer. It is consistent with the [behavior of `tsc` 4.3.2 and later](https://github.com/microsoft/TypeScript/pull/42663). It is also the standard ECMAScript runtime behavior.
7175

76+
Other TypeScript targets will default to `false`.
77+
7278
But it may be counter-intuitive for those coming from other programming languages or older versions of TypeScript.
7379
You can read more about the transition in the [TypeScript 3.7 release notes](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#the-usedefineforclassfields-flag-and-the-declare-property-modifier).
7480

@@ -78,13 +84,32 @@ Most libraries expect `"useDefineForClassFields": true`, such as [MobX](https://
7884

7985
But a few libraries haven't transitioned to this new default yet, including [`lit-element`](https://github.com/lit/lit-element/issues/1030). Please explicitly set `useDefineForClassFields` to `false` in these cases.
8086

87+
#### `target`
88+
89+
- [TypeScript documentation](https://www.typescriptlang.org/tsconfig#target)
90+
91+
Vite does not transpile TypeScript with the configured `target` value by default, following the same behaviour as `esbuild`.
92+
93+
The [`esbuild.target`](/config/shared-options.html#esbuild) option can be used instead, which defaults to `esnext` for minimal transpilation. In builds, the [`build.target`](/config/build-options.html#build-target) option takes higher priority and can also be set if needed.
94+
95+
::: warning `useDefineForClassFields`
96+
If `target` is not `ESNext` or `ES2022` or newer, or if there's no `tsconfig.json` file, `useDefineForClassFields` will default to `false` which can be problematic with the default `esbuild.target` value of `esnext`. It may transpile to [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility) which may not be supported in your browser.
97+
98+
As such, it is recommended to set `target` to `ESNext` or `ES2022` or newer, or set `useDefineForClassFields` to `true` explicitly when configuring `tsconfig.json`.
99+
:::
100+
81101
#### Other Compiler Options Affecting the Build Result
82102

83103
- [`extends`](https://www.typescriptlang.org/tsconfig#extends)
84104
- [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues)
85105
- [`preserveValueImports`](https://www.typescriptlang.org/tsconfig#preserveValueImports)
106+
- [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax)
107+
- [`jsx`](https://www.typescriptlang.org/tsconfig#jsx)
86108
- [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory)
87109
- [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory)
110+
- [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource)
111+
- [`experimentalDecorators`](https://www.typescriptlang.org/tsconfig#experimentalDecorators)
112+
- [`alwaysStrict`](https://www.typescriptlang.org/tsconfig#alwaysStrict)
88113

89114
If migrating your codebase to `"isolatedModules": true` is an insurmountable effort, you may be able to get around it with a third-party plugin such as [rollup-plugin-friendly-type-imports](https://www.npmjs.com/package/rollup-plugin-friendly-type-imports). However, this approach is not officially supported by Vite.
90115

docs/guide/migration.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,31 @@ CLI shortcuts, like `r` to restart the dev server, now require an additional `En
136136

137137
This change prevents Vite from swallowing and controlling OS-specific shortcuts, allowing better compatibility when combining the Vite dev server with other processes, and avoids the [previous caveats](https://github.com/vitejs/vite/pull/14342).
138138

139+
### Update `experimentalDecorators` and `useDefineForClassFields` TypeScript behaviour
140+
141+
Vite 5 uses esbuild 0.19 and removes the compatibility layer for esbuild 0.18, which changes how `experimentalDecorators` and `useDefineForClassFields` are handled.
142+
143+
- **`experimentalDecorators` is not enabled by default**
144+
145+
You need to set `compilerOptions.experimentalDecorators` to `true` in `tsconfig.json` to use decorators.
146+
147+
- **`useDefineForClassFields` defaults depend on the TypeScript `target` value**
148+
149+
If `target` is not `ESNext` or `ES2022` or newer, or if there's no `tsconfig.json` file, `useDefineForClassFields` will default to `false` which can be problematic with the default `esbuild.target` value of `esnext`. It may transpile to [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility) which may not be supported in your browser.
150+
151+
As such, it is recommended to set `target` to `ESNext` or `ES2022` or newer, or set `useDefineForClassFields` to `true` explicitly when configuring `tsconfig.json`.
152+
153+
```jsonc
154+
{
155+
"compilerOptions": {
156+
// Set true if you use decorators
157+
"experimentalDecorators": true,
158+
// Set true if you see parsing errors in your browser
159+
"useDefineForClassFields": true
160+
}
161+
}
162+
```
163+
139164
### Remove `--https` flag and `https: true`
140165

141166
`--https` flag sets `https: true`. This config was meant to be used together with the automatic https certification generation feature which [was dropped in Vite 3](https://v3.vitejs.dev/guide/migration.html#automatic-https-certificate-generation). This config no longer makes sense as it will make Vite start a HTTPS server without a certificate.

packages/vite/src/node/__tests__/plugins/esbuild.spec.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -383,21 +383,6 @@ describe('transformWithEsbuild', () => {
383383
const actual = await transformClassCode('es2022', {})
384384
expect(actual).toBe(defineForClassFieldsFalseTransformedCode)
385385
})
386-
387-
test('useDefineForClassFields: false and static property should not be transpile to static block', async () => {
388-
const result = await transformWithEsbuild(
389-
`
390-
class foo {
391-
static bar = 'bar'
392-
}
393-
`,
394-
'bar.ts',
395-
{
396-
target: 'esnext',
397-
},
398-
)
399-
expect(result?.code).not.toContain('static {')
400-
})
401386
})
402387
})
403388

packages/vite/src/node/optimizer/index.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
import { transformWithEsbuild } from '../plugins/esbuild'
2828
import { ESBUILD_MODULES_TARGET } from '../constants'
2929
import { esbuildCjsExternalPlugin, esbuildDepPlugin } from './esbuildDepPlugin'
30-
import { resolveTsconfigRaw, scanImports } from './scan'
30+
import { scanImports } from './scan'
3131
import { createOptimizeDepsIncludeResolver, expandGlobIds } from './resolve'
3232
export {
3333
initDepsOptimizer,
@@ -730,12 +730,8 @@ async function prepareEsbuildOptimizerRun(
730730

731731
const optimizeDeps = getDepOptimizationConfig(config, ssr)
732732

733-
const {
734-
plugins: pluginsFromConfig = [],
735-
tsconfig,
736-
tsconfigRaw,
737-
...esbuildOptions
738-
} = optimizeDeps?.esbuildOptions ?? {}
733+
const { plugins: pluginsFromConfig = [], ...esbuildOptions } =
734+
optimizeDeps?.esbuildOptions ?? {}
739735

740736
await Promise.all(
741737
Object.keys(depsInfo).map(async (id) => {
@@ -826,8 +822,6 @@ async function prepareEsbuildOptimizerRun(
826822
metafile: true,
827823
plugins,
828824
charset: 'utf8',
829-
tsconfig,
830-
tsconfigRaw: resolveTsconfigRaw(tsconfig, tsconfigRaw),
831825
...esbuildOptions,
832826
supported: {
833827
'dynamic-import': true,

packages/vite/src/node/optimizer/scan.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { performance } from 'node:perf_hooks'
55
import glob from 'fast-glob'
66
import type {
77
BuildContext,
8-
BuildOptions,
98
Loader,
109
OnLoadArgs,
1110
OnLoadResult,
@@ -214,12 +213,8 @@ async function prepareEsbuildScanner(
214213

215214
const plugin = esbuildScanPlugin(config, container, deps, missing, entries)
216215

217-
const {
218-
plugins = [],
219-
tsconfig,
220-
tsconfigRaw,
221-
...esbuildOptions
222-
} = config.optimizeDeps?.esbuildOptions ?? {}
216+
const { plugins = [], ...esbuildOptions } =
217+
config.optimizeDeps?.esbuildOptions ?? {}
223218

224219
return await esbuild.context({
225220
absWorkingDir: process.cwd(),
@@ -232,8 +227,6 @@ async function prepareEsbuildScanner(
232227
format: 'esm',
233228
logLevel: 'silent',
234229
plugins: [...plugins, plugin],
235-
tsconfig,
236-
tsconfigRaw: resolveTsconfigRaw(tsconfig, tsconfigRaw),
237230
...esbuildOptions,
238231
})
239232
}
@@ -684,22 +677,3 @@ function isScannable(id: string, extensions: string[] | undefined): boolean {
684677
false
685678
)
686679
}
687-
688-
// esbuild v0.18 only transforms decorators when `experimentalDecorators` is set to `true`.
689-
// To preserve compat with the esbuild breaking change, we set `experimentalDecorators` to
690-
// `true` by default if it's unset.
691-
// TODO: Remove this in Vite 5 and check https://github.com/vitejs/vite/pull/13805#issuecomment-1633612320
692-
export function resolveTsconfigRaw(
693-
tsconfig: string | undefined,
694-
tsconfigRaw: BuildOptions['tsconfigRaw'],
695-
): BuildOptions['tsconfigRaw'] {
696-
return tsconfig || typeof tsconfigRaw === 'string'
697-
? tsconfigRaw
698-
: {
699-
...tsconfigRaw,
700-
compilerOptions: {
701-
experimentalDecorators: true,
702-
...tsconfigRaw?.compilerOptions,
703-
},
704-
}
705-
}

packages/vite/src/node/plugins/esbuild.ts

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ export async function transformWithEsbuild(
9393
}
9494

9595
let tsconfigRaw = options?.tsconfigRaw
96-
const fallbackSupported: Record<string, boolean> = {}
9796

9897
// if options provide tsconfigRaw in string, it takes highest precedence
9998
if (typeof tsconfigRaw !== 'string') {
@@ -140,23 +139,6 @@ export async function transformWithEsbuild(
140139
compilerOptions.useDefineForClassFields = false
141140
}
142141

143-
// esbuild v0.18 only transforms decorators when `experimentalDecorators` is set to `true`.
144-
// To preserve compat with the esbuild breaking change, we set `experimentalDecorators` to
145-
// `true` by default if it's unset.
146-
// TODO: Remove this in Vite 5
147-
if (compilerOptions.experimentalDecorators === undefined) {
148-
compilerOptions.experimentalDecorators = true
149-
}
150-
151-
// Compat with esbuild 0.17 where static properties are transpiled to
152-
// static blocks when `useDefineForClassFields` is false. Its support
153-
// is not great yet, so temporarily disable it for now.
154-
// TODO: Remove this in Vite 5, don't pass hardcoded `esnext` target
155-
// to `transformWithEsbuild` in the esbuild plugin.
156-
if (compilerOptions.useDefineForClassFields !== true) {
157-
fallbackSupported['class-static-blocks'] = false
158-
}
159-
160142
// esbuild uses tsconfig fields when both the normal options and tsconfig was set
161143
// but we want to prioritize the normal options
162144
if (options) {
@@ -179,10 +161,6 @@ export async function transformWithEsbuild(
179161
...options,
180162
loader,
181163
tsconfigRaw,
182-
supported: {
183-
...fallbackSupported,
184-
...options?.supported,
185-
},
186164
}
187165

188166
// Some projects in the ecosystem are calling this function with an ESBuildOptions
@@ -220,9 +198,13 @@ export async function transformWithEsbuild(
220198
if (e.errors) {
221199
e.frame = ''
222200
e.errors.forEach((m: Message) => {
223-
if (m.text === 'Experimental decorators are not currently enabled') {
201+
if (
202+
m.text === 'Experimental decorators are not currently enabled' ||
203+
m.text ===
204+
'Parameter decorators only work when experimental decorators are enabled'
205+
) {
224206
m.text +=
225-
'. Vite 4.4+ now uses esbuild 0.18 and you need to enable them by adding "experimentalDecorators": true in your "tsconfig.json" file.'
207+
'. Vite 5 now uses esbuild 0.18 and you need to enable them by adding "experimentalDecorators": true in your "tsconfig.json" file.'
226208
}
227209
e.frame += `\n` + prettifyMessage(m, code)
228210
})

playground/tsconfig-json/__tests__/tsconfig-json.spec.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,8 @@ describe('transformWithEsbuild', () => {
7171
test('experimentalDecorators', async () => {
7272
const main = path.resolve(__dirname, '../src/decorator.ts')
7373
const mainContent = fs.readFileSync(main, 'utf-8')
74-
// Should not error when transpiling decorators
75-
// TODO: In Vite 5, this should require setting `tsconfigRaw.experimentalDecorators`
76-
// or via the closest `tsconfig.json`
74+
// Should not error when transpiling decorators as nearest tsconfig.json
75+
// has "experimentalDecorators": true
7776
const result = await transformWithEsbuild(mainContent, main, {
7877
target: 'es2020',
7978
})

playground/tsconfig-json/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"noImplicitReturns": true,
1515

1616
"useDefineForClassFields": true,
17-
"importsNotUsedAsValues": "preserve"
17+
"importsNotUsedAsValues": "preserve",
18+
"experimentalDecorators": true
1819
},
1920
"include": ["./src"]
2021
}

0 commit comments

Comments
 (0)