rollup-plugin-concurrent-top-level-await 0.1.0 → 0.2.1

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 CHANGED
@@ -99,6 +99,14 @@ postponed until the subgraph is analyzed. This may lead to slower builds.
99
99
 
100
100
  If you notice significant performance degradation, please open an issue.
101
101
 
102
+ ### Exposed Module Structure
103
+
104
+ Because the execution of modules gets wrapped in functions, the bundled output will contain more information about the source module structure. This may be a consideration for projects where code obfuscation is important.
105
+
106
+ ### Tree Shaking
107
+
108
+ Wrapping code in functions may reduce tree shaking effectiveness. We mitigate this where possible, such as by not wrapping declarations.
109
+
102
110
  ### Changing Variable Types
103
111
 
104
112
  In the process of transforming the code, top level `const` declarations may get replaced with `let` declarations. This
@@ -106,7 +114,6 @@ can lead to `const` variables being assignable at runtime instead of throwing an
106
114
 
107
115
  Additionally, variable declarations may be hoisted, which removes temporal dead zone (TDZ) checks.
108
116
 
109
- ### Class Decorators
117
+ ### Default export class name
110
118
 
111
- Class declarations still get evaluated before any top level await expressions. This means that if a class decorator
112
- relies on a top level await expression, it may not work as expected.
119
+ When using `export default class {}`, the runtime `.name` of the exported value will be `<generatedVariablePrefix>_default` (e.g. `__tla_default`) instead of `default`.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { FilterPattern } from "@rollup/pluginutils";
2
2
  import * as magic_string0 from "magic-string";
3
3
  import * as rollup0 from "rollup";
4
+ import { TransformPluginContext } from "rollup";
4
5
 
5
6
  //#region src/index.d.ts
6
7
  declare function concurrentTopLevelAwait(options?: {
@@ -17,7 +18,10 @@ declare function concurrentTopLevelAwait(options?: {
17
18
  name: string;
18
19
  apply: "build";
19
20
  transform: {
20
- handler(this: rollup0.TransformPluginContext, code: string, id: string): Promise<{
21
+ handler(this: TransformPluginContext, code: string, id: string, transformOptions: {
22
+ ssr?: boolean | undefined;
23
+ attributes?: Record<string, string>;
24
+ } | undefined): Promise<{
21
25
  code: string;
22
26
  map: magic_string0.SourceMap | null;
23
27
  } | undefined>;
@@ -25,6 +29,7 @@ declare function concurrentTopLevelAwait(options?: {
25
29
  resolveImportMeta(this: rollup0.PluginContext, property: string | null, {
26
30
  moduleId
27
31
  }: {
32
+ attributes: Record<string, string>;
28
33
  chunkId: string;
29
34
  format: rollup0.InternalModuleFormat;
30
35
  moduleId: string;
package/dist/index.mjs CHANGED
@@ -129,7 +129,7 @@ var AsyncModuleTracker = class {
129
129
  //#endregion
130
130
  //#region src/transform.ts
131
131
  function transform(s, ast, asyncImports, hasAwait, variablePrefix) {
132
- const declarationsEnd = tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix);
132
+ const declarationsEnd = transformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix);
133
133
  s.appendRight(declarationsEnd, `async function ${variablePrefix}_initModuleExports() {\n`);
134
134
  s.append("\n}\n");
135
135
  const asyncDeps = `[${asyncImports.map((_, i) => `${variablePrefix}${i}`).join()}].flatMap(a => {
@@ -149,7 +149,7 @@ function transform(s, ast, asyncImports, hasAwait, variablePrefix) {
149
149
  s.append(`if (import.meta.useTla) await ${variablePrefix}_initPromise;\n`);
150
150
  s.append(`export function ${variablePrefix}_access() { return ${variablePrefix}; };\n`);
151
151
  }
152
- function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix) {
152
+ function transformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variablePrefix) {
153
153
  let moduleScopeEnd = 0;
154
154
  let i = 0;
155
155
  for (const node of ast.body) {
@@ -158,11 +158,20 @@ function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variable
158
158
  s.appendLeft(node.end, tlaImport);
159
159
  i++;
160
160
  }
161
+ if (node.type === "ClassDeclaration") {
162
+ s.appendLeft(moduleScopeEnd, `let ${node.id.name};\n`);
163
+ s.appendRight(node.start, `${node.id.name} = `);
164
+ }
161
165
  if (node.type === "ExportNamedDeclaration") {
162
166
  if (node.declaration?.type === "VariableDeclaration") {
163
167
  s.appendLeft(moduleScopeEnd, "export ");
164
168
  s.remove(node.start, node.declaration.start);
165
169
  moveVariableDeclarationToModuleScope(s, node.declaration, moduleScopeEnd);
170
+ } else if (node.declaration?.type === "ClassDeclaration") {
171
+ s.appendLeft(moduleScopeEnd, `export let ${node.declaration.id.name};\n`);
172
+ const declarationStart = getClassDeclarationStart(node.declaration);
173
+ s.remove(node.start, declarationStart);
174
+ s.appendRight(declarationStart, `${node.declaration.id.name} = `);
166
175
  }
167
176
  } else if (node.type === "VariableDeclaration") if (node.kind.endsWith("using")) moveVariableDeclarationWithUsingToModuleScope(s, node, moduleScopeEnd, variablePrefix);
168
177
  else moveVariableDeclarationToModuleScope(s, node, moduleScopeEnd);
@@ -170,13 +179,15 @@ function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variable
170
179
  if (n.type === "VariableDeclaration" && n.kind === "var") moveVariableDeclarationToModuleScope(s, n, moduleScopeEnd);
171
180
  return false;
172
181
  });
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 = (`);
182
+ if (node.type === "ExportDefaultDeclaration" && !isFunctionDeclaration(node.declaration.type)) {
183
+ const variableName = node.declaration.type === "ClassDeclaration" ? node.declaration.id?.name ?? `${variablePrefix}_default` : `${variablePrefix}_default`;
184
+ s.appendLeft(moduleScopeEnd, `let ${variableName};\nexport { ${variableName} as default };\n`);
185
+ const declarationStart = node.declaration.type === "ClassDeclaration" ? getClassDeclarationStart(node.declaration) : node.declaration.start;
186
+ s.remove(node.start, declarationStart);
187
+ s.appendRight(declarationStart, `${variableName} = (`);
177
188
  s.appendLeft(node.declaration.end, ");");
178
189
  }
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) {
190
+ if (isFunctionDeclaration(node.type) || node.type === "ImportDeclaration" || node.type === "ExportDefaultDeclaration" && isFunctionDeclaration(node.declaration.type) || node.type === "ExportNamedDeclaration" && isFunctionDeclaration(node.declaration?.type) || node.type === "ExportNamedDeclaration" && node.declaration == null || node.type === "ExportAllDeclaration") if (node.start > moduleScopeEnd) {
180
191
  s.appendLeft(node.end, "\n");
181
192
  s.move(node.start, node.end, moduleScopeEnd);
182
193
  s.appendLeft(node.start, ";");
@@ -184,8 +195,11 @@ function tansformAndMoveDeclarationsToModuleScope(s, ast, asyncImports, variable
184
195
  }
185
196
  return moduleScopeEnd;
186
197
  }
187
- function isDeclaration(type) {
188
- return type === "ClassDeclaration" || type === "FunctionDeclaration";
198
+ function isFunctionDeclaration(type) {
199
+ return type === "FunctionDeclaration";
200
+ }
201
+ function getClassDeclarationStart(node) {
202
+ return node.decorators[0]?.start ?? node.start;
189
203
  }
190
204
  function moveVariableDeclarationToModuleScope(s, node, declarationsEnd) {
191
205
  const kind = replaceConstWithLet(node.kind);
@@ -229,13 +243,20 @@ function getNames(pattern) {
229
243
 
230
244
  //#endregion
231
245
  //#region src/index.ts
246
+ function resolveDeclarationSource(context, id, importerAttributes = {}, declaration) {
247
+ return context.resolve(declaration.source.value, id, {
248
+ attributes: Object.fromEntries(declaration.attributes.map((attr) => [attr.key.type === "Identifier" ? attr.key.name : attr.key.value, attr.value.value])),
249
+ importerAttributes,
250
+ custom: {}
251
+ });
252
+ }
232
253
  function concurrentTopLevelAwait(options = {}) {
233
254
  const filter = createFilter(options.include, options.exclude);
234
255
  const asyncTracker = new AsyncModuleTracker();
235
256
  return {
236
257
  name: "rollup-plugin-concurrent-tla-plugin",
237
258
  apply: "build",
238
- transform: { async handler(code, id) {
259
+ transform: { async handler(code, id, transformOptions) {
239
260
  if (!filter(id)) return;
240
261
  const ast = this.parse(code);
241
262
  const importDeclarations = ast.body.filter((a) => a.type === "ImportDeclaration");
@@ -244,14 +265,14 @@ function concurrentTopLevelAwait(options = {}) {
244
265
  if (hasAwait) asyncTracker.setDependencies(id, []);
245
266
  else {
246
267
  const childrenIds = (await Promise.all(importDeclarations.map(async (declaration) => {
247
- const importId = await this.resolve(declaration.source.value, id);
268
+ const importId = await resolveDeclarationSource(this, id, transformOptions?.attributes, declaration);
248
269
  if (!importId || !filter(importId.id)) return null;
249
270
  return importId.id;
250
271
  }))).filter((a) => a != null);
251
272
  asyncTracker.setDependencies(id, childrenIds);
252
273
  }
253
274
  const asyncImports = (await Promise.all(importDeclarations.map(async (declaration) => {
254
- const importId = await this.resolve(declaration.source.value, id);
275
+ const importId = await resolveDeclarationSource(this, id, transformOptions?.attributes, declaration);
255
276
  if (!importId || !filter(importId.id)) return null;
256
277
  this.load(importId);
257
278
  if (!await asyncTracker.isAsync(importId.id)) return null;
@@ -268,9 +289,9 @@ function concurrentTopLevelAwait(options = {}) {
268
289
  resolveImportMeta(property, { moduleId }) {
269
290
  if (property !== "useTla") return;
270
291
  const moduleInfo = this.getModuleInfo(moduleId);
271
- const importers = moduleInfo?.importers;
272
- if (moduleInfo?.isEntry || !importers?.length) return "true";
273
- if (importers.some((id) => !filter(id))) return "true";
292
+ if (moduleInfo?.isEntry) return "true";
293
+ if (moduleInfo?.dynamicImporters.length) return "true";
294
+ if ((moduleInfo?.importers)?.some((id) => !filter(id))) return "true";
274
295
  return "false";
275
296
  }
276
297
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rollup-plugin-concurrent-top-level-await",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Rollup (and Vite) plugin enabling concurrent execution of modules that contain top level await.",
5
5
  "keywords": [
6
6
  "rollup-plugin",
@@ -46,7 +46,8 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/estree": "^1.0.8",
49
- "prettier": "3.7.4"
49
+ "prettier": "3.7.4",
50
+ "rollup": "^4.57.1"
50
51
  },
51
52
  "scripts": {
52
53
  "build": "tsdown --dts"