diff --git a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
index 3d238748199..dd47344277c 100644
--- a/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
@@ -685,6 +685,34 @@ describe('resolveType', () => {
expect(deps && [...deps]).toStrictEqual(['/user.ts'])
})
+ test('ts module resolve w/ path aliased vue file', () => {
+ const files = {
+ '/tsconfig.json': JSON.stringify({
+ compilerOptions: {
+ include: ['**/*.ts', '**/*.vue'],
+ paths: {
+ '@/*': ['./src/*']
+ }
+ }
+ }),
+ '/src/Foo.vue':
+ ''
+ }
+
+ const { props, deps } = resolve(
+ `
+ import { P } from '@/Foo.vue'
+ defineProps
()
+ `,
+ files
+ )
+
+ expect(props).toStrictEqual({
+ bar: ['String']
+ })
+ expect(deps && [...deps]).toStrictEqual(['/src/Foo.vue'])
+ })
+
test('global types', () => {
const files = {
// ambient
diff --git a/packages/compiler-sfc/src/script/context.ts b/packages/compiler-sfc/src/script/context.ts
index 9a3d2eccd3c..af2dee16568 100644
--- a/packages/compiler-sfc/src/script/context.ts
+++ b/packages/compiler-sfc/src/script/context.ts
@@ -70,6 +70,11 @@ export class ScriptCompileContext {
*/
deps?: Set
+ /**
+ * cache for resolved fs
+ */
+ fs?: NonNullable
+
constructor(
public descriptor: SFCDescriptor,
public options: Partial
diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts
index 35a80e1b186..83d4fbfc887 100644
--- a/packages/compiler-sfc/src/script/resolveType.ts
+++ b/packages/compiler-sfc/src/script/resolveType.ts
@@ -62,7 +62,9 @@ export type SimpleTypeResolveContext = Pick<
// required
'source' | 'filename' | 'error' | 'options'
> &
- Partial> & {
+ Partial<
+ Pick
+ > & {
ast: Statement[]
}
@@ -693,7 +695,7 @@ function qualifiedNameToPath(node: Identifier | TSQualifiedName): string[] {
function resolveGlobalScope(ctx: TypeResolveContext): TypeScope[] | undefined {
if (ctx.options.globalTypeFiles) {
- const fs: FS = ctx.options.fs || ts?.sys
+ const fs = resolveFS(ctx)
if (!fs) {
throw new Error('[vue/compiler-sfc] globalTypeFiles requires fs access.')
}
@@ -714,6 +716,30 @@ export function registerTS(_ts: any) {
type FS = NonNullable
+function resolveFS(ctx: TypeResolveContext): FS | undefined {
+ if (ctx.fs) {
+ return ctx.fs
+ }
+ const fs = ctx.options.fs || ts.sys
+ if (!fs) {
+ return
+ }
+ return (ctx.fs = {
+ fileExists(file) {
+ if (file.endsWith('.vue.ts')) {
+ file = file.replace(/\.ts$/, '')
+ }
+ return fs.fileExists(file)
+ },
+ readFile(file) {
+ if (file.endsWith('.vue.ts')) {
+ file = file.replace(/\.ts$/, '')
+ }
+ return fs.readFile(file)
+ }
+ })
+}
+
function resolveTypeFromImport(
ctx: TypeResolveContext,
node: ReferenceTypes,
@@ -731,9 +757,9 @@ function importSourceToScope(
scope: TypeScope,
source: string
): TypeScope {
- const fs: FS = ctx.options.fs || ts?.sys
+ const fs = resolveFS(ctx)
if (!fs) {
- ctx.error(
+ return ctx.error(
`No fs option provided to \`compileScript\` in non-Node environment. ` +
`File system access is required for resolving imported types.`,
node,
@@ -881,7 +907,11 @@ function resolveWithTS(
)
if (res.resolvedModule) {
- return res.resolvedModule.resolvedFileName
+ let filename = res.resolvedModule.resolvedFileName
+ if (filename.endsWith('.vue.ts')) {
+ filename = filename.replace(/\.ts$/, '')
+ }
+ return filename
}
}
@@ -936,7 +966,7 @@ export function fileToScope(
return cached
}
// fs should be guaranteed to exist here
- const fs = ctx.options.fs || ts?.sys
+ const fs = resolveFS(ctx)!
const source = fs.readFile(filename) || ''
const body = parseFile(filename, source, ctx.options.babelParserPlugins)
const scope = new TypeScope(filename, source, 0, recordImports(body))