Skip to content

Commit

Permalink
feat: respect tsconfig options that affects compilation results (vite…
Browse files Browse the repository at this point in the history
  • Loading branch information
sodatea authored and aleclarson committed Nov 8, 2021
1 parent 0403b00 commit 803b1a6
Show file tree
Hide file tree
Showing 15 changed files with 256 additions and 1 deletion.
16 changes: 16 additions & 0 deletions packages/playground/tsconfig-json/__tests__/tsconfig-json.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
test('should respected each `tsconfig.json`s compilerOptions', () => {
// main side effect should be called (because of `"importsNotUsedAsValues": "preserve"`)
expect(browserLogs).toContain('main side effect')
// main base setter should not be called (because of `"useDefineForClassFields": true"`)
expect(browserLogs).not.toContain('data setter in MainBase')

// nested side effect should not be called (because "importsNotUsedAsValues" is not set, defaults to "remove")
expect(browserLogs).not.toContain('nested side effect')
// nested base setter should be called (because of `"useDefineForClassFields": false"`)
expect(browserLogs).toContain('data setter in NestedBase')

// nested-with-extends side effect should be called (because "importsNotUsedAsValues" is extended from the main tsconfig.json, which is "preserve")
expect(browserLogs).toContain('nested-with-extends side effect')
// nested-with-extends base setter should be called (because of `"useDefineForClassFields": false"`)
expect(browserLogs).toContain('data setter in NestedWithExtendsBase')
})
12 changes: 12 additions & 0 deletions packages/playground/tsconfig-json/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
17 changes: 17 additions & 0 deletions packages/playground/tsconfig-json/nested-with-extends/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @ts-nocheck
import { NestedWithExtendsTypeOnlyClass } from './not-used-type'

class NestedWithExtendsBase {
set data(value: string) {
console.log('data setter in NestedWithExtendsBase')
}
}
class NestedWithExtendsDerived extends NestedWithExtendsBase {
// No longer triggers a 'console.log'
// when using 'useDefineForClassFields'.
data = 10

foo?: NestedWithExtendsTypeOnlyClass
}

const d = new NestedWithExtendsDerived()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
console.log('nested-with-extends side effect')

export class NestedWithExtendsTypeOnlyClass {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../tsconfig.json",
"include": ["./"],
"compilerOptions": {
"useDefineForClassFields": false
}
}
17 changes: 17 additions & 0 deletions packages/playground/tsconfig-json/nested/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @ts-nocheck
import { NestedTypeOnlyClass } from './not-used-type'

class NestedBase {
set data(value: string) {
console.log('data setter in NestedBase')
}
}
class NestedDerived extends NestedBase {
// No longer triggers a 'console.log'
// when using 'useDefineForClassFields'.
data = 10

foo?: NestedTypeOnlyClass
}

const d = new NestedDerived()
3 changes: 3 additions & 0 deletions packages/playground/tsconfig-json/nested/not-used-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
console.log('nested side effect')

export class NestedTypeOnlyClass {}
19 changes: 19 additions & 0 deletions packages/playground/tsconfig-json/nested/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"include": ["./"],
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,

"useDefineForClassFields": false
}
}
11 changes: 11 additions & 0 deletions packages/playground/tsconfig-json/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "tsconfig-json",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"debug": "node --inspect-brk ../../vite/bin/vite",
"serve": "vite preview"
}
}
20 changes: 20 additions & 0 deletions packages/playground/tsconfig-json/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @ts-nocheck
import '../nested/main'
import '../nested-with-extends/main'

import { MainTypeOnlyClass } from './not-used-type'

class MainBase {
set data(value: string) {
console.log('data setter in MainBase')
}
}
class MainDerived extends MainBase {
// No longer triggers a 'console.log'
// when using 'useDefineForClassFields'.
data = 10

foo?: MainTypeOnlyClass
}

const d = new MainDerived()
3 changes: 3 additions & 0 deletions packages/playground/tsconfig-json/src/not-used-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
console.log('main side effect')

export class MainTypeOnlyClass {}
20 changes: 20 additions & 0 deletions packages/playground/tsconfig-json/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"moduleResolution": "Node",
"strict": true,
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,

"useDefineForClassFields": true,
"importsNotUsedAsValues": "preserve"
},
"include": ["./src"]
}
3 changes: 2 additions & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"!/src/**/__tests__/"
],
"engines": {
"node": ">=12.0.0"
"node": ">=12.2.0"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -118,6 +118,7 @@
"source-map-support": "^0.5.19",
"strip-ansi": "^6.0.0",
"terser": "^5.7.1",
"tsconfig": "^7.0.0",
"tslib": "^2.3.0",
"types": "link:./types",
"ws": "^7.5.3"
Expand Down
81 changes: 81 additions & 0 deletions packages/vite/src/node/plugins/esbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { SourceMap } from 'rollup'
import { ResolvedConfig } from '..'
import { createFilter } from '@rollup/pluginutils'
import { combineSourcemaps } from '../utils'
import { find as findTSConfig, readFile as readTSConfig } from 'tsconfig'
import { createRequire } from 'module'

const debug = createDebugger('vite:esbuild')

Expand All @@ -27,6 +29,56 @@ export type ESBuildTransformResult = Omit<TransformResult, 'map'> & {
map: SourceMap
}

type TSConfigJSON = {
extends?: string
compilerOptions?: {
target?: string
jsxFactory?: string
jsxFragmentFactory?: string
useDefineForClassFields?: boolean
importsNotUsedAsValues?: 'remove' | 'preserve' | 'error'
}
[key: string]: any
}
type TSCompilerOptions = NonNullable<TSConfigJSON['compilerOptions']>

const tsconfigCache = new Map<string, TSConfigJSON>()
async function loadTsconfigJsonForFile(
filename: string
): Promise<TSConfigJSON> {
const directory = path.dirname(filename)

const cached = tsconfigCache.get(directory)
if (cached) {
return cached
}

let configPath = await findTSConfig(directory)
let tsconfig: TSConfigJSON = {}

if (configPath) {
tsconfig = (await readTSConfig(configPath)) as TSConfigJSON
while (tsconfig.extends) {
const configRequire = createRequire(configPath)

const extendsPath = configRequire.resolve(tsconfig.extends)
const extendedConfig = (await readTSConfig(extendsPath)) as TSConfigJSON

tsconfig = {
extends: extendedConfig.extends,
compilerOptions: {
...extendedConfig.compilerOptions,
...tsconfig.compilerOptions
}
}
configPath = extendsPath
}
}

tsconfigCache.set(directory, tsconfig)
return tsconfig
}

export async function transformWithEsbuild(
code: string,
filename: string,
Expand All @@ -44,11 +96,40 @@ export async function transformWithEsbuild(
loader = 'js'
}

// these fields would affect the compilation result
// https://esbuild.github.io/content-types/#tsconfig-json
const meaningfulFields: Array<keyof TSCompilerOptions> = [
'jsxFactory',
'jsxFragmentFactory',
'useDefineForClassFields',
'importsNotUsedAsValues'
]
const compilerOptionsForFile: TSCompilerOptions = {}
if (loader === 'ts' || loader === 'tsx') {
const loadedTsconfig = await loadTsconfigJsonForFile(filename)
const loadedCompilerOptions = loadedTsconfig.compilerOptions ?? {}

for (const field of meaningfulFields) {
if (field in loadedCompilerOptions) {
// @ts-ignore TypeScript can't tell they are of the same type
compilerOptionsForFile[field] = loadedCompilerOptions[field]
}
}

// align with TypeScript 4.3
// https://github.com/microsoft/TypeScript/pull/42663
if (loadedCompilerOptions.target?.toLowerCase() === 'esnext') {
compilerOptionsForFile.useDefineForClassFields =
loadedCompilerOptions.useDefineForClassFields ?? true
}
}

const resolvedOptions = {
loader: loader as Loader,
sourcemap: true,
// ensure source file name contains full query
sourcefile: filename,
tsconfigRaw: { compilerOptions: compilerOptionsForFile },
...options
} as ESBuildOptions

Expand Down
25 changes: 25 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,16 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==

"@types/strip-bom@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=

"@types/strip-json-comments@0.0.30":
version "0.0.30"
resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1"
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==

"@types/stylus@^0.48.36":
version "0.48.36"
resolved "https://registry.yarnpkg.com/@types/stylus/-/stylus-0.48.36.tgz#a6103fa8414ad8a37d46966cde44ad88757ed42c"
Expand Down Expand Up @@ -7190,6 +7200,11 @@ strip-indent@^3.0.0:
dependencies:
min-indent "^1.0.0"

strip-json-comments@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=

strip-json-comments@^3.1.0, strip-json-comments@^3.1.1, strip-json-comments@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
Expand Down Expand Up @@ -7514,6 +7529,16 @@ ts-node@^10.1.0:
source-map-support "^0.5.17"
yn "3.1.1"

tsconfig@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7"
integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==
dependencies:
"@types/strip-bom" "^3.0.0"
"@types/strip-json-comments" "0.0.30"
strip-bom "^3.0.0"
strip-json-comments "^2.0.0"

tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
Expand Down

0 comments on commit 803b1a6

Please sign in to comment.