rollup-plugin-concurrent-top-level-await 0.0.8 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -1
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +50 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,16 @@ export default {
|
|
|
30
30
|
};
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
## Options
|
|
34
|
+
|
|
35
|
+
| Option | Type | Default | Description |
|
|
36
|
+
| ------------------------- | --------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `include` | `FilterPattern` | `undefined` | A pattern specifying which files to include. See [below](#which-modules-to-include) to determine which modules to include. |
|
|
38
|
+
| `exclude` | `FilterPattern` | `undefined` | A pattern specifying which files to exclude. Must still follow the [same considerations](#which-modules-to-include) as `include`. |
|
|
39
|
+
| `sourceMap` | `boolean` | `true` | Whether to generate source maps for transformed files. |
|
|
40
|
+
| `generatedVariablePrefix` | `string` | `"__tla"` | Prefix used for internal variables generated by the plugin. Change this if it conflicts with variable names in your code. |
|
|
41
|
+
|
|
42
|
+
### Which modules to include?
|
|
34
43
|
|
|
35
44
|
The plugin needs to handle not only modules that directly contain a top-level `await`, but also their ancestor modules up to the lowest common ancestor. Ancestor modules must be transformed to handle the asynchronous completion of their children concurrently. As an example, consider the following module structure:
|
|
36
45
|
|
package/dist/index.d.mts
CHANGED
|
@@ -7,6 +7,12 @@ declare function concurrentTopLevelAwait(options?: {
|
|
|
7
7
|
include?: FilterPattern;
|
|
8
8
|
exclude?: FilterPattern;
|
|
9
9
|
sourceMap?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Prefix used for internal variables generated by the plugin.
|
|
12
|
+
* Change this if it conflicts with variable names in your code.
|
|
13
|
+
* @default "__tla"
|
|
14
|
+
*/
|
|
15
|
+
generatedVariablePrefix?: string;
|
|
10
16
|
}): {
|
|
11
17
|
name: string;
|
|
12
18
|
apply: "build";
|
package/dist/index.mjs
CHANGED
|
@@ -128,57 +128,61 @@ var AsyncModuleTracker = class {
|
|
|
128
128
|
|
|
129
129
|
//#endregion
|
|
130
130
|
//#region src/transform.ts
|
|
131
|
-
function transform(s, ast, asyncImports, hasAwait) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
s
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
s = s.append("if (import.meta.useTla) await __todo;");
|
|
152
|
-
s = s.append("export function __tla_access() { return __tla; };");
|
|
153
|
-
return s;
|
|
131
|
+
function transform(s, ast, asyncImports, hasAwait, variablePrefix) {
|
|
132
|
+
const declarationsEnd = tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix);
|
|
133
|
+
s.appendRight(declarationsEnd, `async function ${variablePrefix}_initModuleExports() {\n`);
|
|
134
|
+
s.append("\n}\n");
|
|
135
|
+
const asyncDeps = `[${asyncImports.map((_, i) => `${variablePrefix}${i}`).join()}].flatMap(a => {
|
|
136
|
+
try {
|
|
137
|
+
const result = a();
|
|
138
|
+
if (Array.isArray(result)) {
|
|
139
|
+
return result
|
|
140
|
+
}
|
|
141
|
+
return [a];
|
|
142
|
+
} catch {
|
|
143
|
+
return []; // happens for cyclic dependencies
|
|
144
|
+
}
|
|
145
|
+
})`;
|
|
146
|
+
const initModuleExportsAfterDeps = asyncImports.length === 0 ? `${variablePrefix}_initModuleExports()` : `Promise.all(${asyncDeps}.map(e => e())).then(() => ${variablePrefix}_initModuleExports())`;
|
|
147
|
+
if (hasAwait) s.append(`const ${variablePrefix} = ${initModuleExportsAfterDeps};\nconst ${variablePrefix}_initPromise = ${variablePrefix};\n`);
|
|
148
|
+
else s.append(`const ${variablePrefix} = ${asyncDeps};\nconst ${variablePrefix}_initPromise = ${initModuleExportsAfterDeps};\n`);
|
|
149
|
+
s.append(`if (import.meta.useTla) await ${variablePrefix}_initPromise;\n`);
|
|
150
|
+
s.append(`export function ${variablePrefix}_access() { return ${variablePrefix}; };\n`);
|
|
154
151
|
}
|
|
155
|
-
function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports) {
|
|
152
|
+
function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix) {
|
|
156
153
|
let moduleScopeEnd = 0;
|
|
157
154
|
let i = 0;
|
|
158
155
|
for (const node of ast.body) {
|
|
159
156
|
if (asyncImports.includes(node)) {
|
|
160
|
-
const tlaImport =
|
|
161
|
-
s
|
|
157
|
+
const tlaImport = `\nimport { ${variablePrefix}_access as ${variablePrefix}${i}} from '${node.source.value}';`;
|
|
158
|
+
s.appendLeft(node.end, tlaImport);
|
|
162
159
|
i++;
|
|
163
160
|
}
|
|
164
161
|
if (node.type === "ExportNamedDeclaration") {
|
|
165
162
|
if (node.declaration?.type === "VariableDeclaration") {
|
|
166
|
-
s
|
|
167
|
-
s
|
|
168
|
-
|
|
163
|
+
s.appendLeft(moduleScopeEnd, "export ");
|
|
164
|
+
s.remove(node.start, node.declaration.start);
|
|
165
|
+
moveVariableDeclarationToModuleScope(s, node.declaration, moduleScopeEnd);
|
|
169
166
|
}
|
|
170
|
-
} else if (node.type === "VariableDeclaration") if (node.kind.endsWith("using"))
|
|
171
|
-
else
|
|
167
|
+
} else if (node.type === "VariableDeclaration") if (node.kind.endsWith("using")) moveVariableDeclarationWithUsingToModuleScope(s, node, moduleScopeEnd, variablePrefix);
|
|
168
|
+
else moveVariableDeclarationToModuleScope(s, node, moduleScopeEnd);
|
|
172
169
|
else visitScope(node, (n) => {
|
|
173
|
-
if (n.type === "VariableDeclaration" && n.kind === "var")
|
|
170
|
+
if (n.type === "VariableDeclaration" && n.kind === "var") moveVariableDeclarationToModuleScope(s, n, moduleScopeEnd);
|
|
174
171
|
return false;
|
|
175
172
|
});
|
|
176
|
-
if (
|
|
177
|
-
s
|
|
178
|
-
s
|
|
173
|
+
if (node.type === "ExportDefaultDeclaration" && !isDeclaration(node.declaration.type)) {
|
|
174
|
+
s.appendLeft(moduleScopeEnd, `let ${variablePrefix}_default;\nexport { ${variablePrefix}_default as default };\n`);
|
|
175
|
+
s.remove(node.start, node.declaration.start);
|
|
176
|
+
s.appendRight(node.declaration.start, `${variablePrefix}_default = (`);
|
|
177
|
+
s.appendLeft(node.declaration.end, ");");
|
|
178
|
+
}
|
|
179
|
+
if (isDeclaration(node.type) || node.type === "ImportDeclaration" || node.type === "ExportDefaultDeclaration" && isDeclaration(node.declaration.type) || node.type === "ExportNamedDeclaration" && isDeclaration(node.declaration?.type) || node.type === "ExportNamedDeclaration" && node.declaration == null || node.type === "ExportAllDeclaration") if (node.start > moduleScopeEnd) {
|
|
180
|
+
s.appendLeft(node.end, "\n");
|
|
181
|
+
s.move(node.start, node.end, moduleScopeEnd);
|
|
182
|
+
s.appendLeft(node.start, ";");
|
|
179
183
|
} else moduleScopeEnd = node.end;
|
|
180
184
|
}
|
|
181
|
-
return
|
|
185
|
+
return moduleScopeEnd;
|
|
182
186
|
}
|
|
183
187
|
function isDeclaration(type) {
|
|
184
188
|
return type === "ClassDeclaration" || type === "FunctionDeclaration";
|
|
@@ -186,20 +190,20 @@ function isDeclaration(type) {
|
|
|
186
190
|
function moveVariableDeclarationToModuleScope(s, node, declarationsEnd) {
|
|
187
191
|
const kind = replaceConstWithLet(node.kind);
|
|
188
192
|
const names = node.declarations.flatMap((decl) => getNames(decl.id)).join(", ");
|
|
189
|
-
s
|
|
190
|
-
s
|
|
191
|
-
s
|
|
192
|
-
s
|
|
193
|
+
s.appendRight(node.declarations[0].start, ";(");
|
|
194
|
+
s.appendLeft(node.declarations[node.declarations.length - 1].end, ")");
|
|
195
|
+
s.appendLeft(declarationsEnd, `${kind} ${names};\n`);
|
|
196
|
+
s.remove(node.start, node.declarations[0].start);
|
|
193
197
|
return s;
|
|
194
198
|
}
|
|
195
|
-
function moveVariableDeclarationWithUsingToModuleScope(s, node, declarationsEnd) {
|
|
199
|
+
function moveVariableDeclarationWithUsingToModuleScope(s, node, declarationsEnd, variablePrefix) {
|
|
196
200
|
node.declarations.forEach((declaration) => {
|
|
197
201
|
const id = declaration.id;
|
|
198
202
|
if (id.type !== "Identifier") throw new Error("'using' declarations may not have binding patterns.");
|
|
199
203
|
const name = id.name;
|
|
200
|
-
s
|
|
201
|
-
s
|
|
202
|
-
s
|
|
204
|
+
s.appendRight(id.start, `${variablePrefix}_using_`);
|
|
205
|
+
s.appendLeft(node.end, `\n${name} = ${variablePrefix}_using_${name};`);
|
|
206
|
+
s.appendLeft(declarationsEnd, `let ${name};\n`);
|
|
203
207
|
});
|
|
204
208
|
return s;
|
|
205
209
|
}
|
|
@@ -254,8 +258,8 @@ function concurrentTopLevelAwait(options = {}) {
|
|
|
254
258
|
return declaration;
|
|
255
259
|
}))).filter(Boolean);
|
|
256
260
|
if (!(asyncImports.length > 0 || hasAwait)) return;
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
const s = new MagicString(code);
|
|
262
|
+
transform(s, ast, asyncImports, hasAwait, options.generatedVariablePrefix ?? "__tla");
|
|
259
263
|
return {
|
|
260
264
|
code: s.toString(),
|
|
261
265
|
map: options.sourceMap !== false ? s.generateMap({ hires: true }) : null
|
package/package.json
CHANGED