perf(compiler-sfc): lazy require typescript

This commit is contained in:
Evan You 2023-06-15 16:38:44 +08:00
parent 6f45f76df2
commit d2c3d8b70b
3 changed files with 30 additions and 18 deletions

View File

@ -10,7 +10,7 @@ import {
} from '../../src/script/resolveType' } from '../../src/script/resolveType'
import ts from 'typescript' import ts from 'typescript'
registerTS(ts) registerTS(() => ts)
describe('resolveType', () => { describe('resolveType', () => {
test('type literal', () => { test('type literal', () => {

View File

@ -708,13 +708,14 @@ function resolveGlobalScope(ctx: TypeResolveContext): TypeScope[] | undefined {
} }
} }
let ts: typeof TS let ts: typeof TS | undefined
let loadTS: (() => typeof TS) | undefined
/** /**
* @private * @private
*/ */
export function registerTS(_ts: any) { export function registerTS(_loadTS: () => typeof TS) {
ts = _ts loadTS = _loadTS
} }
type FS = NonNullable<SFCScriptCompileOptions['fs']> type FS = NonNullable<SFCScriptCompileOptions['fs']>
@ -723,7 +724,10 @@ function resolveFS(ctx: TypeResolveContext): FS | undefined {
if (ctx.fs) { if (ctx.fs) {
return ctx.fs return ctx.fs
} }
const fs = ctx.options.fs || ts.sys if (!ts && loadTS) {
ts = loadTS()
}
const fs = ctx.options.fs || ts?.sys
if (!fs) { if (!fs) {
return return
} }
@ -779,22 +783,25 @@ function importSourceToScope(
} else { } else {
// module or aliased import - use full TS resolution, only supported in Node // module or aliased import - use full TS resolution, only supported in Node
if (!__NODE_JS__) { if (!__NODE_JS__) {
ctx.error( return ctx.error(
`Type import from non-relative sources is not supported in the browser build.`, `Type import from non-relative sources is not supported in the browser build.`,
node, node,
scope scope
) )
} }
if (!ts) { if (!ts) {
ctx.error( if (loadTS) ts = loadTS()
`Failed to resolve import source ${JSON.stringify(source)}. ` + if (!ts) {
`typescript is required as a peer dep for vue in order ` + return ctx.error(
`to support resolving types from module imports.`, `Failed to resolve import source ${JSON.stringify(source)}. ` +
node, `typescript is required as a peer dep for vue in order ` +
scope `to support resolving types from module imports.`,
) node,
scope
)
}
} }
resolved = resolveWithTS(scope.filename, source, fs) resolved = resolveWithTS(scope.filename, source, ts, fs)
} }
if (resolved) { if (resolved) {
resolved = scope.resolvedImportSources[source] = normalizePath(resolved) resolved = scope.resolvedImportSources[source] = normalizePath(resolved)
@ -839,6 +846,7 @@ const tsConfigRefMap = new Map<string, string>()
function resolveWithTS( function resolveWithTS(
containingFile: string, containingFile: string,
source: string, source: string,
ts: typeof TS,
fs: FS fs: FS
): string | undefined { ): string | undefined {
if (!__NODE_JS__) return if (!__NODE_JS__) return
@ -853,7 +861,7 @@ function resolveWithTS(
const normalizedConfigPath = normalizePath(configPath) const normalizedConfigPath = normalizePath(configPath)
const cached = tsConfigCache.get(normalizedConfigPath) const cached = tsConfigCache.get(normalizedConfigPath)
if (!cached) { if (!cached) {
configs = loadTSConfig(configPath, fs).map(config => ({ config })) configs = loadTSConfig(configPath, ts, fs).map(config => ({ config }))
tsConfigCache.set(normalizedConfigPath, configs) tsConfigCache.set(normalizedConfigPath, configs)
} else { } else {
configs = cached configs = cached
@ -918,7 +926,11 @@ function resolveWithTS(
} }
} }
function loadTSConfig(configPath: string, fs: FS): TS.ParsedCommandLine[] { function loadTSConfig(
configPath: string,
ts: typeof TS,
fs: FS
): TS.ParsedCommandLine[] {
// The only case where `fs` is NOT `ts.sys` is during tests. // The only case where `fs` is NOT `ts.sys` is during tests.
// parse config host requires an extra `readDirectory` method // parse config host requires an extra `readDirectory` method
// during tests, which is stubbed. // during tests, which is stubbed.
@ -940,7 +952,7 @@ function loadTSConfig(configPath: string, fs: FS): TS.ParsedCommandLine[] {
if (config.projectReferences) { if (config.projectReferences) {
for (const ref of config.projectReferences) { for (const ref of config.projectReferences) {
tsConfigRefMap.set(ref.path, configPath) tsConfigRefMap.set(ref.path, configPath)
res.unshift(...loadTSConfig(ref.path, fs)) res.unshift(...loadTSConfig(ref.path, ts, fs))
} }
} }
return res return res

View File

@ -1,5 +1,5 @@
if (typeof require !== 'undefined') { if (typeof require !== 'undefined') {
try { try {
require('@vue/compiler-sfc').registerTS(require('typescript')) require('@vue/compiler-sfc').registerTS(() => require('typescript'))
} catch (e) {} } catch (e) {}
} }