From 271df09470c61d073185ba6cf3cf50358713c500 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 17 Apr 2023 20:59:03 +0800 Subject: [PATCH] fix(compiler-sfc): normalize windows paths when resolving types --- .../compiler-sfc/src/script/resolveType.ts | 21 +++++++++++-------- packages/compiler-sfc/src/script/utils.ts | 8 +++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts index 8efa04579f8..247bac3a3be 100644 --- a/packages/compiler-sfc/src/script/resolveType.ts +++ b/packages/compiler-sfc/src/script/resolveType.ts @@ -25,7 +25,8 @@ import { UNKNOWN_TYPE, createGetCanonicalFileName, getId, - getImportedName + getImportedName, + normalizePath } from './utils' import { ScriptCompileContext, resolveParserPlugins } from './context' import { ImportBinding, SFCScriptCompileOptions } from '../compileScript' @@ -34,7 +35,7 @@ import { parse as babelParse } from '@babel/parser' import { parse } from '../parse' import { createCache } from '../cache' import type TS from 'typescript' -import { join, extname, dirname } from 'path' +import path from 'path' /** * TypeResolveContext is compatible with ScriptCompileContext @@ -577,8 +578,7 @@ function resolveGlobalScope(ctx: TypeResolveContext): TypeScope[] | undefined { throw new Error('[vue/compiler-sfc] globalTypeFiles requires fs access.') } return ctx.options.globalTypeFiles.map(file => - // TODO: differentiate ambient vs non-ambient module - fileToScope(file, fs, ctx.options.babelParserPlugins, true) + fileToScope(normalizePath(file), fs, ctx.options.babelParserPlugins, true) ) } } @@ -616,7 +616,7 @@ function resolveTypeFromImport( if (source.startsWith('.')) { // relative import - fast path - const filename = join(containingFile, '..', source) + const filename = path.join(containingFile, '..', source) resolved = resolveExt(filename, fs) } else { // module or aliased import - use full TS resolution, only supported in Node @@ -642,6 +642,8 @@ function resolveTypeFromImport( } if (resolved) { + resolved = normalizePath(resolved) + // (hmr) register dependency file on ctx ;(ctx.deps || (ctx.deps = new Set())).add(resolved) @@ -694,7 +696,8 @@ function resolveWithTS( let options: TS.CompilerOptions let cache: TS.ModuleResolutionCache | undefined if (configPath) { - const cached = tsConfigCache.get(configPath) + const normalizedConfigPath = normalizePath(configPath) + const cached = tsConfigCache.get(normalizedConfigPath) if (!cached) { // The only case where `fs` is NOT `ts.sys` is during tests. // parse config host requires an extra `readDirectory` method @@ -709,7 +712,7 @@ function resolveWithTS( const parsed = ts.parseJsonConfigFileContent( ts.readConfigFile(configPath, fs.readFile).config, parseConfigHost, - dirname(configPath), + path.dirname(configPath), undefined, configPath ) @@ -719,7 +722,7 @@ function resolveWithTS( createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames), options ) - tsConfigCache.set(configPath, { options, cache }) + tsConfigCache.set(normalizedConfigPath, { options, cache }) } else { ;({ options, cache } = cached) } @@ -777,7 +780,7 @@ function parseFile( content: string, parserPlugins?: SFCScriptCompileOptions['babelParserPlugins'] ): Statement[] { - const ext = extname(filename) + const ext = path.extname(filename) if (ext === '.ts' || ext === '.tsx') { return babelParse(content, { plugins: resolveParserPlugins(ext.slice(1), parserPlugins), diff --git a/packages/compiler-sfc/src/script/utils.ts b/packages/compiler-sfc/src/script/utils.ts index 6d874f8a6db..04df22a2b64 100644 --- a/packages/compiler-sfc/src/script/utils.ts +++ b/packages/compiler-sfc/src/script/utils.ts @@ -8,6 +8,7 @@ import { Node, StringLiteral } from '@babel/types' +import path from 'path' import { TS_NODE_TYPES } from '@vue/compiler-dom' export const UNKNOWN_TYPE = 'Unknown' @@ -97,3 +98,10 @@ function toFileNameLowerCase(x: string) { export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean) { return useCaseSensitiveFileNames ? identity : toFileNameLowerCase } + +const windowsSlashRE = /\\/g +export function normalizePath(p: string) { + // in the browser build, the polyfill doesn't expose posix, but defualts to + // posix behavior. + return (path.posix || path).normalize(p.replace(windowsSlashRE, '/')) +}