Skip to content

Commit 42976d8

Browse files
authored
fix: derive useDefineForClassFields value from tsconfig.compilerOptions.target (fixes #10296) (#11301)
1 parent 9c2b1c0 commit 42976d8

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

docs/guide/features.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ However, some libraries (e.g. [`vue`](https://github.com/vuejs/core/issues/1228)
5757

5858
#### `useDefineForClassFields`
5959

60-
Starting from Vite 2.5.0, the default value will be `true` if the TypeScript target is `ESNext`. 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.
60+
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.
6161

6262
But it may be counter-intuitive for those coming from other programming languages or older versions of TypeScript.
6363
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).

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

+75-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { describe, expect, test } from 'vitest'
22
import type { ResolvedConfig, UserConfig } from '../../config'
33
import {
4-
ESBuildTransformResult,
54
resolveEsbuildTranspileOptions,
65
transformWithEsbuild,
76
} from '../../plugins/esbuild'
@@ -305,6 +304,81 @@ describe('transformWithEsbuild', () => {
305304
`/* @__PURE__ */ ${jsxFactory}(${jsxFragment}, null)`,
306305
)
307306
})
307+
308+
describe('useDefineForClassFields', async () => {
309+
const transformClassCode = async (
310+
target: string,
311+
tsconfigCompilerOptions: {
312+
target?: string
313+
useDefineForClassFields?: boolean
314+
},
315+
) => {
316+
const result = await transformWithEsbuild(
317+
`
318+
class foo {
319+
bar = 'bar'
320+
}
321+
`,
322+
'bar.ts',
323+
{
324+
target,
325+
tsconfigRaw: { compilerOptions: tsconfigCompilerOptions },
326+
},
327+
)
328+
return result?.code
329+
}
330+
331+
const [
332+
defineForClassFieldsTrueTransformedCode,
333+
defineForClassFieldsTrueLowerTransformedCode,
334+
defineForClassFieldsFalseTransformedCode,
335+
] = await Promise.all([
336+
transformClassCode('esnext', {
337+
useDefineForClassFields: true,
338+
}),
339+
transformClassCode('es2021', {
340+
useDefineForClassFields: true,
341+
}),
342+
transformClassCode('esnext', {
343+
useDefineForClassFields: false,
344+
}),
345+
])
346+
347+
test('target: esnext and tsconfig.target: esnext => true', async () => {
348+
const actual = await transformClassCode('esnext', {
349+
target: 'esnext',
350+
})
351+
expect(actual).toBe(defineForClassFieldsTrueTransformedCode)
352+
})
353+
354+
test('target: es2021 and tsconfig.target: esnext => true', async () => {
355+
const actual = await transformClassCode('es2021', {
356+
target: 'esnext',
357+
})
358+
expect(actual).toBe(defineForClassFieldsTrueLowerTransformedCode)
359+
})
360+
361+
test('target: es2021 and tsconfig.target: es2021 => false', async () => {
362+
const actual = await transformClassCode('es2021', {
363+
target: 'es2021',
364+
})
365+
expect(actual).toBe(defineForClassFieldsFalseTransformedCode)
366+
})
367+
368+
test('target: esnext and tsconfig.target: es2021 => false', async () => {
369+
const actual = await transformClassCode('esnext', {
370+
target: 'es2021',
371+
})
372+
expect(actual).toBe(defineForClassFieldsFalseTransformedCode)
373+
})
374+
375+
test('target: es2022 and tsconfig.target: es2022 => true', async () => {
376+
const actual = await transformClassCode('es2022', {
377+
target: 'es2022',
378+
})
379+
expect(actual).toBe(defineForClassFieldsTrueTransformedCode)
380+
})
381+
})
308382
})
309383

310384
/**

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

+17
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,23 @@ export async function transformWithEsbuild(
125125
...tsconfigRaw?.compilerOptions,
126126
},
127127
}
128+
129+
const { compilerOptions } = tsconfigRaw
130+
if (compilerOptions) {
131+
// esbuild derives `useDefineForClassFields` from `target` instead of `tsconfig.compilerOptions.target`
132+
// https://github.com/evanw/esbuild/issues/2584
133+
// but we want `useDefineForClassFields` to be derived from `tsconfig.compilerOptions.target`
134+
if (compilerOptions.useDefineForClassFields === undefined) {
135+
const lowercaseTarget = compilerOptions.target?.toLowerCase() ?? 'es3'
136+
if (lowercaseTarget.startsWith('es')) {
137+
const esVersion = lowercaseTarget.slice(2)
138+
compilerOptions.useDefineForClassFields =
139+
esVersion === 'next' || +esVersion >= 2022
140+
} else {
141+
compilerOptions.useDefineForClassFields = false
142+
}
143+
}
144+
}
128145
}
129146

130147
const resolvedOptions = {

0 commit comments

Comments
 (0)