Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: update to tsconfck3 with lazy cache #14234

Merged
merged 8 commits into from
Sep 15, 2023
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@
"source-map-support": "^0.5.21",
"strip-ansi": "^7.1.0",
"strip-literal": "^1.3.0",
"tsconfck": "^2.1.2",
"tsconfck": "^3.0.0-next.8",
"tslib": "^2.6.1",
"types": "link:./types",
"ufo": "^1.2.0",
Expand Down
72 changes: 20 additions & 52 deletions packages/vite/src/node/plugins/esbuild.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import path from 'node:path'
import { performance } from 'node:perf_hooks'
import colors from 'picocolors'
import type {
Loader,
Expand All @@ -10,21 +9,19 @@ import type {
import { transform } from 'esbuild'
import type { RawSourceMap } from '@ampproject/remapping'
import type { InternalModuleFormat, SourceMap } from 'rollup'
import type { TSConfckParseOptions } from 'tsconfck'
import { TSConfckParseError, findAll, parse } from 'tsconfck'
import type { TSConfckParseResult } from 'tsconfck'
import { TSConfckCache, TSConfckParseError, parse } from 'tsconfck'
import {
cleanUrl,
combineSourcemaps,
createDebugger,
createFilter,
ensureWatchedFile,
generateCodeFrame,
timeFrom,
} from '../utils'
import type { ViteDevServer } from '../server'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { searchForWorkspaceRoot } from '../server/searchRoot'

const debug = createDebugger('vite:esbuild')

Expand Down Expand Up @@ -257,8 +254,6 @@ export function esbuildPlugin(config: ResolvedConfig): Plugin {
keepNames: false,
}

initTSConfck(config.root)

return {
name: 'vite:esbuild',
configureServer(_server) {
Expand Down Expand Up @@ -311,8 +306,6 @@ const rollupToEsbuildFormatMap: Record<
}

export const buildEsbuildPlugin = (config: ResolvedConfig): Plugin => {
initTSConfck(config.root)

return {
name: 'vite:esbuild-transpile',
async renderChunk(code, chunk, opts) {
Expand Down Expand Up @@ -469,53 +462,28 @@ function prettifyMessage(m: Message, code: string): string {
return res + `\n`
}

let tsconfckRoot: string | undefined
let tsconfckParseOptions: TSConfckParseOptions | Promise<TSConfckParseOptions> =
{ resolveWithEmptyIfConfigNotFound: true }

function initTSConfck(root: string, force = false) {
// bail if already cached
if (!force && root === tsconfckRoot) return

const workspaceRoot = searchForWorkspaceRoot(root)

tsconfckRoot = root
tsconfckParseOptions = initTSConfckParseOptions(workspaceRoot)

// cached as the options value itself when promise is resolved
tsconfckParseOptions.then((options) => {
if (root === tsconfckRoot) {
tsconfckParseOptions = options
}
})
}

async function initTSConfckParseOptions(workspaceRoot: string) {
const start = debug ? performance.now() : 0

const options: TSConfckParseOptions = {
cache: new Map(),
root: workspaceRoot,
tsConfigPaths: new Set(
await findAll(workspaceRoot, {
skip: (dir) => dir === 'node_modules' || dir === '.git',
}),
),
resolveWithEmptyIfConfigNotFound: true,
}

debug?.(timeFrom(start), 'tsconfck init', colors.dim(workspaceRoot))

return options
}
let tsconfckCache: TSConfckCache<TSConfckParseResult>

async function loadTsconfigJsonForFile(
filename: string,
): Promise<TSConfigJSON> {
try {
const result = await parse(filename, await tsconfckParseOptions)
if (tsconfckCache) {
// shortcut, the cache stores resolved TSConfckParseResult
// so getting it from the cache directly we bypass aysnc fn call wrapping it in a promise again
if (tsconfckCache.hasParseResult(filename)) {
const result = await tsconfckCache.getParseResult(filename)
return result.tsconfig
}
} else {
tsconfckCache = new TSConfckCache<TSConfckParseResult>()
}
const result = await parse(filename, {
cache: tsconfckCache,
ignoreNodeModules: true,
})
// tsconfig could be out of root, make sure it is watched on dev
if (server && result.tsconfigFile !== 'no_tsconfig_file_found') {
if (server && result.tsconfigFile) {
ensureWatchedFile(server.watcher, result.tsconfigFile, server.config.root)
}
return result.tsconfig
Expand All @@ -538,7 +506,7 @@ async function reloadOnTsconfigChange(changedFile: string) {
if (
path.basename(changedFile) === 'tsconfig.json' ||
(changedFile.endsWith('.json') &&
(await tsconfckParseOptions)?.cache?.has(changedFile))
tsconfckCache?.hasParseResult(changedFile))
) {
server.config.logger.info(
`changed tsconfig file detected: ${changedFile} - Clearing cache and forcing full-reload to ensure TypeScript is compiled with updated config values.`,
Expand All @@ -549,7 +517,7 @@ async function reloadOnTsconfigChange(changedFile: string) {
server.moduleGraph.invalidateAll()

// reset tsconfck so that recompile works with up2date configs
initTSConfck(server.config.root, true)
tsconfckCache.clear()

// server may not be available if vite config is updated at the same time
if (server) {
Expand Down
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.