-
Notifications
You must be signed in to change notification settings - Fork 29
/
pluginDevProxyModuleTopLevelAwait.ts
99 lines (89 loc) · 3.44 KB
/
pluginDevProxyModuleTopLevelAwait.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
* Solve the problem that dev mode dependency prebunding does not support top-level await syntax
*/
import { createFilter } from '@rollup/pluginutils';
import { walk } from 'estree-walker';
import MagicString from 'magic-string';
import { Plugin } from 'vite';
export function PluginDevProxyModuleTopLevelAwait(): Plugin {
const filterFunction = createFilter();
return {
name: 'dev-proxy-module-top-level-await',
apply: 'serve',
transform(code: string, id: string): { code: string; map: any } | null {
if (!code.includes('/*mf top-level-await placeholder replacement mf*/')) {
return null;
}
if (!filterFunction(id)) return null;
let ast: any;
try {
ast = (this as any).parse(code, {
allowReturnOutsideFunction: true,
});
} catch (e) {
throw new Error(`${id}: ${e}`);
}
const magicString = new MagicString(code);
walk(ast, {
enter(node: any) {
if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
const exportSpecifiers = node.specifiers.map(
(specifier: any) => specifier.exported.name
);
const proxyStatements = exportSpecifiers
.map(
(name: string) => `
const __mfproxy__await${name} = await ${name}();
const __mfproxy__${name} = () => __mfproxy__await${name};
`
)
.join('\n');
const exportStatements = exportSpecifiers
.map((name: string) => `__mfproxy__${name} as ${name}`)
.join(', ');
const start = node.start;
const end = node.end;
const replacement = `${proxyStatements}\nexport { ${exportStatements} };`;
magicString.overwrite(start, end, replacement);
}
if (node.type === 'ExportDefaultDeclaration') {
const declaration = node.declaration;
const start = node.start;
const end = node.end;
let proxyStatement;
let exportStatement = 'default';
if (declaration.type === 'Identifier') {
// example: export default foo;
proxyStatement = `
const __mfproxy__awaitdefault = await ${declaration.name}();
const __mfproxy__default = __mfproxy__awaitdefault;
`;
} else if (
declaration.type === 'CallExpression' ||
declaration.type === 'FunctionDeclaration'
) {
// example: export default someFunction();
const declarationCode = code.slice(declaration.start, declaration.end);
proxyStatement = `
const __mfproxy__awaitdefault = await (${declarationCode});
const __mfproxy__default = __mfproxy__awaitdefault;
`;
} else {
// other
proxyStatement = `
const __mfproxy__awaitdefault = await (${code.slice(declaration.start, declaration.end)});
const __mfproxy__default = __mfproxy__awaitdefault;
`;
}
const replacement = `${proxyStatement}\nexport { __mfproxy__default as ${exportStatement} };`;
magicString.overwrite(start, end, replacement);
}
},
});
return {
code: magicString.toString(),
map: magicString.generateMap({ hires: true }),
};
},
};
}