Skip to content

Commit 88231cd

Browse files
committed
refactor: drop virtual prefix
1 parent 52fa576 commit 88231cd

File tree

3 files changed

+71
-34
lines changed

3 files changed

+71
-34
lines changed

src/cache.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import fs from "node:fs";
22
import type { SFCDescriptor } from "vue/compiler-sfc";
33
import { type ResolvedConfig } from "vite";
4-
import { CompilerSfc, resolveCompiler } from "./compiler";
4+
import { resolveCompiler } from "./compiler";
55
import { pascalCase } from "./utils";
66

77
export default function createCache(config: ResolvedConfig) {
8-
const descriptorCache: Map<string, SFCDescriptor> = new Map();
9-
const compiler: CompilerSfc = resolveCompiler(config.root);
8+
const descriptorCache = new Map<string, SFCDescriptor>();
9+
const nestedComponentNames = new Set<string>();
10+
const compiler = resolveCompiler(config.root);
1011

1112
return {
1213
getDescriptor(filename: string) {
@@ -45,5 +46,17 @@ export default function createCache(config: ResolvedConfig) {
4546
hasFile(filename: string) {
4647
return descriptorCache.has(filename);
4748
},
49+
registerNestedComponent(filename: string, component: string) {
50+
if (filename.startsWith(config.root)) {
51+
filename = filename.slice(config.root.length);
52+
}
53+
nestedComponentNames.add(`${filename}/${component}.vue`);
54+
},
55+
isNestedComponent(filename: string) {
56+
if (filename.startsWith(config.root)) {
57+
filename = filename.slice(config.root.length);
58+
}
59+
return nestedComponentNames.has(filename);
60+
},
4861
};
4962
}

src/gen.ts

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
export function genComponentBlockCode(
2-
virtualFilename: string,
3-
component: string
4-
) {
1+
export function genComponentBlockCode(filename: string, component: string) {
52
return (
6-
`import ${component} from '${virtualFilename}/${component}.vue';\n` +
3+
`import ${component} from '${filename}/${component}.vue';\n` +
74
"export default function(Comp) {\n" +
85
" if (!Comp.components) {\n" +
96
" Comp.components = {};\n" +
@@ -14,7 +11,7 @@ export function genComponentBlockCode(
1411
}
1512

1613
export function genExportsCode(
17-
virtualFilename: string,
14+
filename: string,
1815
components: string[],
1916
mainCode: string
2017
) {
@@ -24,7 +21,7 @@ export function genExportsCode(
2421
"export { default as ",
2522
component,
2623
" } from '",
27-
virtualFilename,
24+
filename,
2825
"/",
2926
component,
3027
".vue';\n"

src/index.ts

+51-24
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1+
import path from "node:path";
12
import type { PluginOption, ResolvedConfig } from "vite";
23
import createCache from "./cache";
34
import { genComponentBlockCode, genExportsCode } from "./gen";
45
import { parseVueRequest, pascalCase } from "./utils";
56

67
export default function vueNestedSFC(): PluginOption {
7-
const prefix = "virtual:vue-nested-sfc";
8-
98
let config: ResolvedConfig;
109
let cache: ReturnType<typeof createCache>;
1110

1211
return {
13-
name: "vue-nested-sfc",
12+
name: "vite:vue-nested-sfc",
1413

1514
configResolved(resolvedConfig) {
1615
config = resolvedConfig;
@@ -20,19 +19,34 @@ export default function vueNestedSFC(): PluginOption {
2019
cache = createCache(config);
2120
},
2221

23-
resolveId(id) {
24-
if (id.startsWith(prefix)) {
22+
resolveId(id, importerFile) {
23+
if (cache.isNestedComponent(id)) {
2524
return id;
2625
}
26+
if (importerFile && cache.isNestedComponent(importerFile)) {
27+
let [, importerDir] = importerFile.match(/^(.*)(?:\/[^/]+){2}\.vue$/)!;
28+
if (!importerDir.startsWith(config.root)) {
29+
importerDir = config.root + importerDir;
30+
}
31+
return path.resolve(importerDir, id);
32+
}
2733
},
2834

2935
load(id) {
30-
if (!id.startsWith(prefix)) {
36+
if (!cache.isNestedComponent(id)) {
3137
return;
3238
}
3339

34-
const [, filename, component] =
35-
id.slice(prefix.length).match(/^(.*)\/([^/]+)\.vue$/) || [];
40+
const match = id.match(/^(.*)\/([^/]+)\.vue$/);
41+
if (!match) {
42+
return;
43+
}
44+
let filename = match[1];
45+
const component = match[2];
46+
47+
if (!filename.startsWith(config.root)) {
48+
filename = config.root + filename;
49+
}
3650

3751
const descriptor = cache.getDescriptor(filename);
3852

@@ -53,21 +67,27 @@ export default function vueNestedSFC(): PluginOption {
5367
transform(code, id) {
5468
const request = parseVueRequest(id);
5569

56-
if (request.filename.startsWith(prefix)) {
70+
if (cache.isNestedComponent(id)) {
5771
return;
5872
}
5973

6074
if (!request.query.vue && request.filename.endsWith(".vue")) {
61-
return genExportsCode(
62-
prefix + request.filename,
63-
cache.getNestedComponents(id),
64-
code
65-
);
75+
const components = cache.getNestedComponents(id);
76+
for (const componentName of components) {
77+
cache.registerNestedComponent(request.filename, componentName);
78+
}
79+
return {
80+
code: genExportsCode(request.filename, components, code),
81+
// eslint-disable-next-line unicorn/no-null
82+
map: null,
83+
};
6684
} else if (request.query.type === "component" && request.query.name) {
67-
return genComponentBlockCode(
68-
prefix + request.filename,
69-
pascalCase(request.query.name)
70-
);
85+
const componentName = pascalCase(request.query.name);
86+
cache.registerNestedComponent(request.filename, componentName);
87+
return {
88+
code: genComponentBlockCode(request.filename, componentName),
89+
map: { mappings: "" },
90+
};
7191
}
7292
},
7393

@@ -117,9 +137,11 @@ export default function vueNestedSFC(): PluginOption {
117137
if (!nextBlock || block.content === nextBlock.content) {
118138
continue;
119139
}
120-
const componentModule = server.moduleGraph.getModuleById(
121-
`${prefix}${file}/${name}.vue`
122-
);
140+
const componentModule =
141+
server.moduleGraph.getModuleById(`${file}/${name}.vue`) ||
142+
server.moduleGraph.getModuleById(
143+
`${file.replace(config.root, "")}/${name}.vue`
144+
);
123145
if (!componentModule) {
124146
continue;
125147
}
@@ -129,10 +151,15 @@ export default function vueNestedSFC(): PluginOption {
129151
m.url.includes("type=component") &&
130152
m.url.includes(`name=${nextBlock.attrs.name}`)
131153
);
132-
if (!blockModule) {
133-
continue;
154+
if (blockModule) {
155+
affectedModules.add(blockModule);
156+
}
157+
const subModules = [...componentModule.importedModules].filter((m) =>
158+
m.url.startsWith(componentModule.url)
159+
);
160+
for (const subModule of subModules) {
161+
affectedModules.add(subModule);
134162
}
135-
affectedModules.add(blockModule);
136163
}
137164

138165
return [...affectedModules];

0 commit comments

Comments
 (0)