Skip to content

Commit 4144781

Browse files
authored
fix(scanner): respect experimentalDecorators: true (#15206)
1 parent 2888457 commit 4144781

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

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

+17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
import type { PluginContainer } from '../server/pluginContainer'
3939
import { createPluginContainer } from '../server/pluginContainer'
4040
import { transformGlobImport } from '../plugins/importMetaGlob'
41+
import { loadTsconfigJsonForFile } from '../plugins/esbuild'
4142

4243
type ResolveIdOptions = Parameters<PluginContainer['resolveId']>[2]
4344

@@ -217,6 +218,21 @@ async function prepareEsbuildScanner(
217218
const { plugins = [], ...esbuildOptions } =
218219
config.optimizeDeps?.esbuildOptions ?? {}
219220

221+
// The plugin pipeline automatically loads the closest tsconfig.json.
222+
// But esbuild doesn't support reading tsconfig.json if the plugin has resolved the path (https://github.com/evanw/esbuild/issues/2265).
223+
// Due to syntax incompatibilities between the experimental decorators in TypeScript and TC39 decorators,
224+
// we cannot simply set `"experimentalDecorators": true` or `false`. (https://github.com/vitejs/vite/pull/15206#discussion_r1417414715)
225+
// Therefore, we use the closest tsconfig.json from the root to make it work in most cases.
226+
let tsconfigRaw = esbuildOptions.tsconfigRaw
227+
if (!tsconfigRaw && !esbuildOptions.tsconfig) {
228+
const tsconfigResult = await loadTsconfigJsonForFile(
229+
path.join(config.root, '_dummy.js'),
230+
)
231+
if (tsconfigResult.compilerOptions?.experimentalDecorators) {
232+
tsconfigRaw = { compilerOptions: { experimentalDecorators: true } }
233+
}
234+
}
235+
220236
return await esbuild.context({
221237
absWorkingDir: process.cwd(),
222238
write: false,
@@ -229,6 +245,7 @@ async function prepareEsbuildScanner(
229245
logLevel: 'silent',
230246
plugins: [...plugins, plugin],
231247
...esbuildOptions,
248+
tsconfigRaw,
232249
})
233250
}
234251

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ function prettifyMessage(m: Message, code: string): string {
440440

441441
let tsconfckCache: TSConfckCache<TSConfckParseResult> | undefined
442442

443-
async function loadTsconfigJsonForFile(
443+
export async function loadTsconfigJsonForFile(
444444
filename: string,
445445
): Promise<TSConfigJSON> {
446446
try {

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import path from 'node:path'
22
import fs from 'node:fs'
33
import { transformWithEsbuild } from 'vite'
44
import { describe, expect, test } from 'vitest'
5-
import { browserLogs } from '~utils'
5+
import { browserLogs, isServe, serverLogs } from '~utils'
66

77
test('should respected each `tsconfig.json`s compilerOptions', () => {
88
// main side effect should be called (because of `"importsNotUsedAsValues": "preserve"`)
@@ -21,6 +21,16 @@ test('should respected each `tsconfig.json`s compilerOptions', () => {
2121
expect(browserLogs).toContain('data setter in NestedWithExtendsBase')
2222
})
2323

24+
test.runIf(isServe)('scanner should not error with decorators', () => {
25+
expect(serverLogs).not.toStrictEqual(
26+
expect.arrayContaining([
27+
expect.stringContaining(
28+
'Parameter decorators only work when experimental decorators are enabled',
29+
),
30+
]),
31+
)
32+
})
33+
2434
describe('transformWithEsbuild', () => {
2535
test('merge tsconfigRaw object', async () => {
2636
const main = path.resolve(__dirname, '../src/main.ts')
+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
// @ts-nocheck playground/tsconfig.json does not have decorators enabled
12
function first() {
23
return function (...args: any[]) {}
34
}
45

56
export class Foo {
67
@first()
7-
// @ts-expect-error we intentionally not enable `experimentalDecorators` to test esbuild compat
8-
method(@first test: string) {
8+
method(@first() test: string) {
99
return test
1010
}
1111
}

0 commit comments

Comments
 (0)