fix(scanner): respect experimentalDecorators: true (#15206)

This commit is contained in:
翠 / green 2024-02-21 22:32:29 +09:00 committed by GitHub
parent 2888457569
commit 4144781fbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 4 deletions

View File

@ -38,6 +38,7 @@ import {
import type { PluginContainer } from '../server/pluginContainer'
import { createPluginContainer } from '../server/pluginContainer'
import { transformGlobImport } from '../plugins/importMetaGlob'
import { loadTsconfigJsonForFile } from '../plugins/esbuild'
type ResolveIdOptions = Parameters<PluginContainer['resolveId']>[2]
@ -217,6 +218,21 @@ async function prepareEsbuildScanner(
const { plugins = [], ...esbuildOptions } =
config.optimizeDeps?.esbuildOptions ?? {}
// The plugin pipeline automatically loads the closest tsconfig.json.
// But esbuild doesn't support reading tsconfig.json if the plugin has resolved the path (https://github.com/evanw/esbuild/issues/2265).
// Due to syntax incompatibilities between the experimental decorators in TypeScript and TC39 decorators,
// we cannot simply set `"experimentalDecorators": true` or `false`. (https://github.com/vitejs/vite/pull/15206#discussion_r1417414715)
// Therefore, we use the closest tsconfig.json from the root to make it work in most cases.
let tsconfigRaw = esbuildOptions.tsconfigRaw
if (!tsconfigRaw && !esbuildOptions.tsconfig) {
const tsconfigResult = await loadTsconfigJsonForFile(
path.join(config.root, '_dummy.js'),
)
if (tsconfigResult.compilerOptions?.experimentalDecorators) {
tsconfigRaw = { compilerOptions: { experimentalDecorators: true } }
}
}
return await esbuild.context({
absWorkingDir: process.cwd(),
write: false,
@ -229,6 +245,7 @@ async function prepareEsbuildScanner(
logLevel: 'silent',
plugins: [...plugins, plugin],
...esbuildOptions,
tsconfigRaw,
})
}

View File

@ -440,7 +440,7 @@ function prettifyMessage(m: Message, code: string): string {
let tsconfckCache: TSConfckCache<TSConfckParseResult> | undefined
async function loadTsconfigJsonForFile(
export async function loadTsconfigJsonForFile(
filename: string,
): Promise<TSConfigJSON> {
try {

View File

@ -2,7 +2,7 @@ import path from 'node:path'
import fs from 'node:fs'
import { transformWithEsbuild } from 'vite'
import { describe, expect, test } from 'vitest'
import { browserLogs } from '~utils'
import { browserLogs, isServe, serverLogs } from '~utils'
test('should respected each `tsconfig.json`s compilerOptions', () => {
// main side effect should be called (because of `"importsNotUsedAsValues": "preserve"`)
@ -21,6 +21,16 @@ test('should respected each `tsconfig.json`s compilerOptions', () => {
expect(browserLogs).toContain('data setter in NestedWithExtendsBase')
})
test.runIf(isServe)('scanner should not error with decorators', () => {
expect(serverLogs).not.toStrictEqual(
expect.arrayContaining([
expect.stringContaining(
'Parameter decorators only work when experimental decorators are enabled',
),
]),
)
})
describe('transformWithEsbuild', () => {
test('merge tsconfigRaw object', async () => {
const main = path.resolve(__dirname, '../src/main.ts')

View File

@ -1,11 +1,11 @@
// @ts-nocheck playground/tsconfig.json does not have decorators enabled
function first() {
return function (...args: any[]) {}
}
export class Foo {
@first()
// @ts-expect-error we intentionally not enable `experimentalDecorators` to test esbuild compat
method(@first test: string) {
method(@first() test: string) {
return test
}
}