Skip to content

Commit

Permalink
fix(scanner): respect experimentalDecorators: true (#15206)
Browse files Browse the repository at this point in the history
  • Loading branch information
sapphi-red committed Feb 21, 2024
1 parent 2888457 commit 4144781
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 4 deletions.
17 changes: 17 additions & 0 deletions packages/vite/src/node/optimizer/scan.ts
Expand Up @@ -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]

Expand Down Expand Up @@ -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,
Expand All @@ -229,6 +245,7 @@ async function prepareEsbuildScanner(
logLevel: 'silent',
plugins: [...plugins, plugin],
...esbuildOptions,
tsconfigRaw,
})
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/node/plugins/esbuild.ts
Expand Up @@ -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 {
Expand Down
12 changes: 11 additions & 1 deletion playground/tsconfig-json/__tests__/tsconfig-json.spec.ts
Expand Up @@ -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"`)
Expand All @@ -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')
Expand Down
4 changes: 2 additions & 2 deletions playground/tsconfig-json/src/decorator.ts
@@ -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
}
}

0 comments on commit 4144781

Please sign in to comment.