rollup-plugin-iife-split 0.0.2 → 0.0.4
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 +23 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +218 -55
- package/package.json +13 -8
package/README.md
CHANGED
|
@@ -105,7 +105,8 @@ MyLib.Admin = (function (exports, shared) {
|
|
|
105
105
|
| `secondaryProps` | `Record<string, string>` | Yes | Maps secondary entry names to their property name on the primary global. Example: `{ admin: 'Admin' }` → `window.MyLib.Admin` |
|
|
106
106
|
| `sharedProp` | `string` | Yes | Property name on the global where shared exports are attached. Example: `'Shared'` → `window.MyLib.Shared` |
|
|
107
107
|
| `unshared` | `(id: string) => boolean` | No | Function that returns `true` for modules that should be duplicated instead of shared. See [Excluding Modules from Sharing](#excluding-modules-from-sharing). |
|
|
108
|
-
| `
|
|
108
|
+
| `debugDir` | `string` | No | Directory to write intermediate files for debugging. If set, writes ESM files before IIFE conversion to help diagnose issues. Example: `'./debug-output'` |
|
|
109
|
+
| `skipRequireGlobals` | `boolean` | No | If `true`, don't error when an external module is missing a `globals` mapping. Instead, let Rollup auto-generate a sanitized global name. Default: `false` |
|
|
109
110
|
|
|
110
111
|
## Excluding Modules from Sharing
|
|
111
112
|
|
|
@@ -135,6 +136,27 @@ With this configuration:
|
|
|
135
136
|
- They are **not** merged into the primary/shared chunk
|
|
136
137
|
- Each satellite entry is self-contained with its own copy of the locale data
|
|
137
138
|
|
|
139
|
+
## External Dependencies
|
|
140
|
+
|
|
141
|
+
When using external dependencies with IIFE output, you must specify `globals` in your Rollup output options to map module IDs to global variable names:
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
export default {
|
|
145
|
+
input: { /* ... */ },
|
|
146
|
+
external: ['lodash', '@fullcalendar/core'],
|
|
147
|
+
plugins: [iifeSplit({ /* ... */ })],
|
|
148
|
+
output: {
|
|
149
|
+
dir: 'dist',
|
|
150
|
+
globals: {
|
|
151
|
+
'lodash': '_',
|
|
152
|
+
'@fullcalendar/core': 'FullCalendar'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
By default, the plugin will error if an external is missing from `globals`—this prevents invalid JavaScript output. If you want Rollup to auto-generate global names instead, set `skipRequireGlobals: true`.
|
|
159
|
+
|
|
138
160
|
## How It Works
|
|
139
161
|
|
|
140
162
|
1. **Build phase**: Rollup builds with ESM format, using `manualChunks` to consolidate all shared modules into one chunk
|
package/dist/index.d.ts
CHANGED
|
@@ -39,9 +39,17 @@ interface IifeSplitOptions {
|
|
|
39
39
|
*/
|
|
40
40
|
unshared?: (id: string) => boolean;
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* Directory to write intermediate files for debugging.
|
|
43
|
+
* If set, writes ESM files before IIFE conversion to help diagnose issues.
|
|
44
|
+
* Example: './debug-output'
|
|
43
45
|
*/
|
|
44
|
-
|
|
46
|
+
debugDir?: string;
|
|
47
|
+
/**
|
|
48
|
+
* If true, don't error when an external module is missing a global mapping.
|
|
49
|
+
* Instead, let Rollup generate a sanitized global name automatically.
|
|
50
|
+
* Default: false (errors on missing globals)
|
|
51
|
+
*/
|
|
52
|
+
skipRequireGlobals?: boolean;
|
|
45
53
|
}
|
|
46
54
|
|
|
47
55
|
declare function iifeSplit(options: IifeSplitOptions): Plugin;
|
package/dist/index.js
CHANGED
|
@@ -158,19 +158,12 @@ function destructureSharedParameter(code, mappings, parse) {
|
|
|
158
158
|
return ms.toString();
|
|
159
159
|
}
|
|
160
160
|
async function convertToIife(options) {
|
|
161
|
-
const { code, globalName, globals, sharedGlobalPath, sharedChunkFileName, parse,
|
|
161
|
+
const { code, globalName, globals, sharedGlobalPath, sharedChunkFileName, parse, skipRequireGlobals } = options;
|
|
162
162
|
const importMappings = sharedGlobalPath ? extractSharedImportMappings(code, parse) : [];
|
|
163
|
-
if (debug && sharedGlobalPath) {
|
|
164
|
-
console.log("\n=== DEBUG convertToIife ===");
|
|
165
|
-
console.log("globalName:", globalName);
|
|
166
|
-
console.log("sharedGlobalPath:", sharedGlobalPath);
|
|
167
|
-
console.log("sharedChunkFileName:", sharedChunkFileName);
|
|
168
|
-
console.log("--- ESM code (first 500 chars) ---");
|
|
169
|
-
console.log(code.slice(0, 500));
|
|
170
|
-
console.log("--- Import mappings ---");
|
|
171
|
-
console.log(importMappings);
|
|
172
|
-
}
|
|
173
163
|
const rollupGlobals = (id) => {
|
|
164
|
+
if (globalName && (id === globalName || globalName.startsWith(id + "."))) {
|
|
165
|
+
return id;
|
|
166
|
+
}
|
|
174
167
|
if (sharedGlobalPath) {
|
|
175
168
|
if (id.includes(SHARED_CHUNK_NAME)) {
|
|
176
169
|
return sharedGlobalPath;
|
|
@@ -182,7 +175,16 @@ async function convertToIife(options) {
|
|
|
182
175
|
}
|
|
183
176
|
}
|
|
184
177
|
}
|
|
185
|
-
|
|
178
|
+
const global = globals[id];
|
|
179
|
+
if (global === void 0) {
|
|
180
|
+
if (skipRequireGlobals) {
|
|
181
|
+
return void 0;
|
|
182
|
+
}
|
|
183
|
+
throw new Error(
|
|
184
|
+
`[iife-split] Missing global for external "${id}". IIFE builds require all externals to have a global mapping. Add it to output.globals in your Rollup config, e.g.: globals: { '${id}': 'SomeGlobalName' }`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
return global;
|
|
186
188
|
};
|
|
187
189
|
const bundle = await rollup({
|
|
188
190
|
input: VIRTUAL_ENTRY,
|
|
@@ -194,23 +196,15 @@ async function convertToIife(options) {
|
|
|
194
196
|
const { output } = await bundle.generate({
|
|
195
197
|
format: "iife",
|
|
196
198
|
name: globalName,
|
|
199
|
+
// Cast needed: Rollup's types say string, but it handles undefined by using default name generation
|
|
197
200
|
globals: rollupGlobals,
|
|
198
201
|
exports: "named"
|
|
199
202
|
});
|
|
200
203
|
await bundle.close();
|
|
201
204
|
let result = output[0].code;
|
|
202
|
-
if (debug && sharedGlobalPath) {
|
|
203
|
-
console.log("--- IIFE before destructuring (first 800 chars) ---");
|
|
204
|
-
console.log(result.slice(0, 800));
|
|
205
|
-
}
|
|
206
205
|
if (sharedGlobalPath && importMappings.length > 0) {
|
|
207
206
|
result = stripNamespaceGuards(result);
|
|
208
207
|
result = destructureSharedParameter(result, importMappings, parse);
|
|
209
|
-
if (debug) {
|
|
210
|
-
console.log("--- IIFE after destructuring (first 800 chars) ---");
|
|
211
|
-
console.log(result.slice(0, 800));
|
|
212
|
-
console.log("=== END DEBUG ===\n");
|
|
213
|
-
}
|
|
214
208
|
} else if (globalName && !globalName.includes(".")) {
|
|
215
209
|
} else if (globalName) {
|
|
216
210
|
result = stripNamespaceGuards(result);
|
|
@@ -340,6 +334,117 @@ function stripExports(code, parse) {
|
|
|
340
334
|
});
|
|
341
335
|
return s.toString();
|
|
342
336
|
}
|
|
337
|
+
function extractExternalImports(code, parse) {
|
|
338
|
+
const ast = parse(code);
|
|
339
|
+
const imports = [];
|
|
340
|
+
walk2(ast, {
|
|
341
|
+
enter(node) {
|
|
342
|
+
if (node.type === "ImportDeclaration") {
|
|
343
|
+
const importNode = node;
|
|
344
|
+
const source = importNode.source.value;
|
|
345
|
+
if (typeof source === "string" && !source.startsWith(".") && !source.startsWith("/")) {
|
|
346
|
+
const specifiers = [];
|
|
347
|
+
for (const spec of importNode.specifiers) {
|
|
348
|
+
if (spec.type === "ImportDefaultSpecifier") {
|
|
349
|
+
specifiers.push({ type: "default", localName: spec.local.name });
|
|
350
|
+
} else if (spec.type === "ImportNamespaceSpecifier") {
|
|
351
|
+
specifiers.push({ type: "namespace", localName: spec.local.name });
|
|
352
|
+
} else if (spec.type === "ImportSpecifier" && spec.imported) {
|
|
353
|
+
specifiers.push({
|
|
354
|
+
type: "named",
|
|
355
|
+
localName: spec.local.name,
|
|
356
|
+
importedName: spec.imported.name
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
imports.push({
|
|
361
|
+
source,
|
|
362
|
+
specifiers,
|
|
363
|
+
fullStatement: code.slice(importNode.start, importNode.end),
|
|
364
|
+
start: importNode.start,
|
|
365
|
+
end: importNode.end
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return imports;
|
|
372
|
+
}
|
|
373
|
+
function removeOrRewriteDuplicateExternalImports(sharedCode, primaryImports, parse) {
|
|
374
|
+
const sharedImports = extractExternalImports(sharedCode, parse);
|
|
375
|
+
const s = new MagicString2(sharedCode);
|
|
376
|
+
const renameMap = /* @__PURE__ */ new Map();
|
|
377
|
+
const primaryBySource = /* @__PURE__ */ new Map();
|
|
378
|
+
for (const imp of primaryImports) {
|
|
379
|
+
const existing = primaryBySource.get(imp.source) || [];
|
|
380
|
+
existing.push(imp);
|
|
381
|
+
primaryBySource.set(imp.source, existing);
|
|
382
|
+
}
|
|
383
|
+
for (const sharedImp of sharedImports) {
|
|
384
|
+
const primaryImpsForSource = primaryBySource.get(sharedImp.source);
|
|
385
|
+
if (!primaryImpsForSource) continue;
|
|
386
|
+
const specifiersToKeep = [];
|
|
387
|
+
for (const sharedSpec of sharedImp.specifiers) {
|
|
388
|
+
let foundInPrimary = false;
|
|
389
|
+
for (const primaryImp of primaryImpsForSource) {
|
|
390
|
+
for (const primarySpec of primaryImp.specifiers) {
|
|
391
|
+
if (sharedSpec.type === primarySpec.type) {
|
|
392
|
+
if (sharedSpec.type === "named" && primarySpec.type === "named") {
|
|
393
|
+
if (sharedSpec.importedName === primarySpec.importedName) {
|
|
394
|
+
foundInPrimary = true;
|
|
395
|
+
if (sharedSpec.localName !== primarySpec.localName) {
|
|
396
|
+
renameMap.set(sharedSpec.localName, primarySpec.localName);
|
|
397
|
+
}
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
} else if (sharedSpec.type === "default" && primarySpec.type === "default") {
|
|
401
|
+
foundInPrimary = true;
|
|
402
|
+
if (sharedSpec.localName !== primarySpec.localName) {
|
|
403
|
+
renameMap.set(sharedSpec.localName, primarySpec.localName);
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
} else if (sharedSpec.type === "namespace" && primarySpec.type === "namespace") {
|
|
407
|
+
foundInPrimary = true;
|
|
408
|
+
if (sharedSpec.localName !== primarySpec.localName) {
|
|
409
|
+
renameMap.set(sharedSpec.localName, primarySpec.localName);
|
|
410
|
+
}
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (foundInPrimary) break;
|
|
416
|
+
}
|
|
417
|
+
if (!foundInPrimary) {
|
|
418
|
+
specifiersToKeep.push(sharedSpec);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (specifiersToKeep.length === 0) {
|
|
422
|
+
s.remove(sharedImp.start, sharedImp.end);
|
|
423
|
+
} else if (specifiersToKeep.length < sharedImp.specifiers.length) {
|
|
424
|
+
const parts = [];
|
|
425
|
+
const namedParts = [];
|
|
426
|
+
for (const spec of specifiersToKeep) {
|
|
427
|
+
if (spec.type === "default") {
|
|
428
|
+
parts.unshift(spec.localName);
|
|
429
|
+
} else if (spec.type === "namespace") {
|
|
430
|
+
parts.push(`* as ${spec.localName}`);
|
|
431
|
+
} else if (spec.type === "named") {
|
|
432
|
+
if (spec.importedName === spec.localName) {
|
|
433
|
+
namedParts.push(spec.localName);
|
|
434
|
+
} else {
|
|
435
|
+
namedParts.push(`${spec.importedName} as ${spec.localName}`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (namedParts.length > 0) {
|
|
440
|
+
parts.push(`{ ${namedParts.join(", ")} }`);
|
|
441
|
+
}
|
|
442
|
+
const newImport = `import ${parts.join(", ")} from '${sharedImp.source}';`;
|
|
443
|
+
s.overwrite(sharedImp.start, sharedImp.end, newImport);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return { code: s.toString(), renameMap };
|
|
447
|
+
}
|
|
343
448
|
function isSharedChunkSource(source, sharedChunkFileName) {
|
|
344
449
|
return source.includes(SHARED_CHUNK_NAME) || source.includes(sharedChunkFileName.replace(/\.js$/, ""));
|
|
345
450
|
}
|
|
@@ -347,6 +452,7 @@ function removeSharedImportsAndRewriteRefs(code, sharedChunkFileName, sharedExpo
|
|
|
347
452
|
const ast = parse(code);
|
|
348
453
|
const s = new MagicString2(code);
|
|
349
454
|
const namespaceNames = /* @__PURE__ */ new Set();
|
|
455
|
+
const namedImportRenames = /* @__PURE__ */ new Map();
|
|
350
456
|
walk2(ast, {
|
|
351
457
|
enter(node) {
|
|
352
458
|
if (node.type === "ImportDeclaration") {
|
|
@@ -356,6 +462,19 @@ function removeSharedImportsAndRewriteRefs(code, sharedChunkFileName, sharedExpo
|
|
|
356
462
|
for (const spec of importNode.specifiers) {
|
|
357
463
|
if (spec.type === "ImportNamespaceSpecifier") {
|
|
358
464
|
namespaceNames.add(spec.local.name);
|
|
465
|
+
} else if (spec.type === "ImportSpecifier" && spec.imported) {
|
|
466
|
+
const exportedName = spec.imported.name;
|
|
467
|
+
const localAlias = spec.local.name;
|
|
468
|
+
const actualLocal = sharedExportToLocal.get(exportedName) ?? exportedName;
|
|
469
|
+
if (localAlias !== actualLocal) {
|
|
470
|
+
namedImportRenames.set(localAlias, actualLocal);
|
|
471
|
+
}
|
|
472
|
+
} else if (spec.type === "ImportDefaultSpecifier") {
|
|
473
|
+
const localAlias = spec.local.name;
|
|
474
|
+
const actualLocal = sharedExportToLocal.get("default") ?? "__shared_default__";
|
|
475
|
+
if (localAlias !== actualLocal) {
|
|
476
|
+
namedImportRenames.set(localAlias, actualLocal);
|
|
477
|
+
}
|
|
359
478
|
}
|
|
360
479
|
}
|
|
361
480
|
}
|
|
@@ -369,6 +488,7 @@ function removeSharedImportsAndRewriteRefs(code, sharedChunkFileName, sharedExpo
|
|
|
369
488
|
const source = importNode.source.value;
|
|
370
489
|
if (typeof source === "string" && isSharedChunkSource(source, sharedChunkFileName)) {
|
|
371
490
|
s.remove(importNode.start, importNode.end);
|
|
491
|
+
this.skip();
|
|
372
492
|
}
|
|
373
493
|
}
|
|
374
494
|
if (node.type === "ExportNamedDeclaration") {
|
|
@@ -388,6 +508,7 @@ function removeSharedImportsAndRewriteRefs(code, sharedChunkFileName, sharedExpo
|
|
|
388
508
|
}
|
|
389
509
|
}
|
|
390
510
|
s.overwrite(exportNode.start, exportNode.end, `export { ${exportParts.join(", ")} };`);
|
|
511
|
+
this.skip();
|
|
391
512
|
}
|
|
392
513
|
}
|
|
393
514
|
}
|
|
@@ -397,6 +518,14 @@ function removeSharedImportsAndRewriteRefs(code, sharedChunkFileName, sharedExpo
|
|
|
397
518
|
const propertyName = memberNode.property.name;
|
|
398
519
|
const localName = sharedExportToLocal.get(propertyName) ?? propertyName;
|
|
399
520
|
s.overwrite(memberNode.start, memberNode.end, localName);
|
|
521
|
+
this.skip();
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (node.type === "Identifier" && namedImportRenames.size > 0) {
|
|
525
|
+
const id = node;
|
|
526
|
+
const newName = namedImportRenames.get(id.name);
|
|
527
|
+
if (newName) {
|
|
528
|
+
s.overwrite(id.start, id.end, newName);
|
|
400
529
|
}
|
|
401
530
|
}
|
|
402
531
|
}
|
|
@@ -494,7 +623,7 @@ function removeChunkImportsAndRewriteRefs(code, chunkFileName, exportToLocal, pa
|
|
|
494
623
|
function chunkImportsFrom(chunk, sourceChunkFileName) {
|
|
495
624
|
return chunk.imports.some((imp) => isChunkSource(imp, sourceChunkFileName));
|
|
496
625
|
}
|
|
497
|
-
function mergeUnsharedIntoImporters(unsharedChunk, entryChunks, parse
|
|
626
|
+
function mergeUnsharedIntoImporters(unsharedChunk, entryChunks, parse) {
|
|
498
627
|
const { exports: unsharedExports, hasDefault } = extractExports(unsharedChunk.code, parse);
|
|
499
628
|
const exportToLocal = /* @__PURE__ */ new Map();
|
|
500
629
|
for (const exp of unsharedExports) {
|
|
@@ -534,68 +663,79 @@ function mergeUnsharedIntoImporters(unsharedChunk, entryChunks, parse, debug) {
|
|
|
534
663
|
localExportToLocal,
|
|
535
664
|
parse
|
|
536
665
|
);
|
|
537
|
-
entry.code =
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
"",
|
|
541
|
-
debug && "// === Entry code ===",
|
|
542
|
-
entryWithoutImports.trim()
|
|
543
|
-
].filter((line) => line !== false).join("\n");
|
|
666
|
+
entry.code = `${codeToInline.trim()}
|
|
667
|
+
|
|
668
|
+
${entryWithoutImports.trim()}`;
|
|
544
669
|
}
|
|
545
670
|
}
|
|
546
|
-
function mergeSharedIntoPrimary(primaryChunk, sharedChunk, sharedProperty, neededExports, parse
|
|
671
|
+
function mergeSharedIntoPrimary(primaryChunk, sharedChunk, sharedProperty, neededExports, parse) {
|
|
547
672
|
const { exports: sharedExports, hasDefault } = extractExports(sharedChunk.code, parse);
|
|
673
|
+
const sharedExternalImports = extractExternalImports(sharedChunk.code, parse);
|
|
674
|
+
const { code: primaryCodeDeduped, renameMap: externalRenameMap } = removeOrRewriteDuplicateExternalImports(primaryChunk.code, sharedExternalImports, parse);
|
|
548
675
|
const sharedDeclarations = extractTopLevelDeclarations(sharedChunk.code, parse);
|
|
549
|
-
const primaryDeclarations = extractTopLevelDeclarations(
|
|
550
|
-
const
|
|
676
|
+
const primaryDeclarations = extractTopLevelDeclarations(primaryCodeDeduped, parse);
|
|
677
|
+
const collisionRenameMap = /* @__PURE__ */ new Map();
|
|
551
678
|
for (const name of sharedDeclarations) {
|
|
552
679
|
if (primaryDeclarations.has(name)) {
|
|
553
|
-
|
|
680
|
+
collisionRenameMap.set(name, `__shared$${name}`);
|
|
554
681
|
}
|
|
555
682
|
}
|
|
556
683
|
let processedSharedCode = sharedChunk.code;
|
|
557
|
-
if (
|
|
558
|
-
processedSharedCode = renameIdentifiers(processedSharedCode,
|
|
684
|
+
if (collisionRenameMap.size > 0) {
|
|
685
|
+
processedSharedCode = renameIdentifiers(processedSharedCode, collisionRenameMap, parse);
|
|
559
686
|
}
|
|
560
687
|
const strippedSharedCode = stripExports(processedSharedCode, parse);
|
|
561
688
|
const sharedExportToLocal = /* @__PURE__ */ new Map();
|
|
562
689
|
for (const exp of sharedExports) {
|
|
563
|
-
const renamedLocal =
|
|
690
|
+
const renamedLocal = collisionRenameMap.get(exp.localName) ?? exp.localName;
|
|
564
691
|
sharedExportToLocal.set(exp.exportedName, renamedLocal);
|
|
565
692
|
}
|
|
566
693
|
if (hasDefault) {
|
|
567
694
|
sharedExportToLocal.set("default", "__shared_default__");
|
|
568
695
|
}
|
|
569
|
-
|
|
570
|
-
|
|
696
|
+
let primaryWithoutSharedImports = removeSharedImportsAndRewriteRefs(
|
|
697
|
+
primaryCodeDeduped,
|
|
571
698
|
sharedChunk.fileName,
|
|
572
699
|
sharedExportToLocal,
|
|
573
700
|
parse
|
|
574
701
|
);
|
|
702
|
+
if (externalRenameMap.size > 0) {
|
|
703
|
+
primaryWithoutSharedImports = renameIdentifiers(primaryWithoutSharedImports, externalRenameMap, parse);
|
|
704
|
+
}
|
|
575
705
|
const sharedExportEntries = [
|
|
576
706
|
...sharedExports.filter((exp) => neededExports.has(exp.exportedName)).map((exp) => {
|
|
577
|
-
const renamedLocal =
|
|
707
|
+
const renamedLocal = collisionRenameMap.get(exp.localName) ?? exp.localName;
|
|
578
708
|
return exp.exportedName === renamedLocal ? renamedLocal : `${exp.exportedName}: ${renamedLocal}`;
|
|
579
709
|
}),
|
|
580
710
|
...hasDefault && neededExports.has("default") ? ["default: __shared_default__"] : []
|
|
581
711
|
];
|
|
582
|
-
const
|
|
583
|
-
primaryChunk.code = [
|
|
584
|
-
debug && "// === Shared code (merged by rollup-plugin-iife-split) ===",
|
|
712
|
+
const parts = [
|
|
585
713
|
strippedSharedCode.trim(),
|
|
586
714
|
"",
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
sharedExportObject,
|
|
592
|
-
|
|
593
|
-
|
|
715
|
+
primaryWithoutSharedImports.trim()
|
|
716
|
+
];
|
|
717
|
+
if (sharedExportEntries.length > 0) {
|
|
718
|
+
const sharedExportObject = `const ${sharedProperty} = { ${sharedExportEntries.join(", ")} };`;
|
|
719
|
+
parts.push("", sharedExportObject, `export { ${sharedProperty} };`);
|
|
720
|
+
}
|
|
721
|
+
primaryChunk.code = parts.join("\n");
|
|
594
722
|
}
|
|
595
723
|
|
|
596
724
|
// src/index.ts
|
|
725
|
+
import { writeFileSync, mkdirSync } from "fs";
|
|
726
|
+
import { join } from "path";
|
|
597
727
|
function iifeSplit(options) {
|
|
598
|
-
const { primary, primaryGlobal, secondaryProps, sharedProp, unshared,
|
|
728
|
+
const { primary, primaryGlobal, secondaryProps, sharedProp, unshared, debugDir, skipRequireGlobals } = options;
|
|
729
|
+
const sanitizeName = (name) => name.replace(/[/\\]/g, "-");
|
|
730
|
+
const writeDebugFile = (filename, content) => {
|
|
731
|
+
if (!debugDir) return;
|
|
732
|
+
try {
|
|
733
|
+
mkdirSync(debugDir, { recursive: true });
|
|
734
|
+
writeFileSync(join(debugDir, filename), content);
|
|
735
|
+
} catch (e) {
|
|
736
|
+
console.warn(`[iife-split] Failed to write debug file ${filename}:`, e);
|
|
737
|
+
}
|
|
738
|
+
};
|
|
599
739
|
let outputGlobals = {};
|
|
600
740
|
const manualChunks = (id, { getModuleInfo }) => {
|
|
601
741
|
const moduleInfo = getModuleInfo(id);
|
|
@@ -625,6 +765,18 @@ function iifeSplit(options) {
|
|
|
625
765
|
async generateBundle(outputOptions, bundle) {
|
|
626
766
|
const parse = this.parse.bind(this);
|
|
627
767
|
const analysis = analyzeChunks(bundle, primary);
|
|
768
|
+
if (debugDir) {
|
|
769
|
+
writeDebugFile("1-primary-original.js", analysis.primaryChunk.code);
|
|
770
|
+
if (analysis.sharedChunk) {
|
|
771
|
+
writeDebugFile("1-shared-original.js", analysis.sharedChunk.code);
|
|
772
|
+
}
|
|
773
|
+
for (const satellite of analysis.satelliteChunks) {
|
|
774
|
+
writeDebugFile(`1-satellite-${sanitizeName(satellite.name)}-original.js`, satellite.code);
|
|
775
|
+
}
|
|
776
|
+
for (const unshared2 of analysis.unsharedChunks) {
|
|
777
|
+
writeDebugFile(`1-unshared-${sanitizeName(unshared2.name)}-original.js`, unshared2.code);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
628
780
|
const sharedChunkFileName = analysis.sharedChunk?.fileName ?? null;
|
|
629
781
|
if (analysis.sharedChunk) {
|
|
630
782
|
const neededExports = /* @__PURE__ */ new Set();
|
|
@@ -634,21 +786,32 @@ function iifeSplit(options) {
|
|
|
634
786
|
neededExports.add(imp);
|
|
635
787
|
}
|
|
636
788
|
}
|
|
789
|
+
if (debugDir) {
|
|
790
|
+
writeDebugFile("2-needed-exports.json", JSON.stringify(Array.from(neededExports), null, 2));
|
|
791
|
+
}
|
|
637
792
|
mergeSharedIntoPrimary(
|
|
638
793
|
analysis.primaryChunk,
|
|
639
794
|
analysis.sharedChunk,
|
|
640
795
|
sharedProp,
|
|
641
796
|
neededExports,
|
|
642
|
-
parse
|
|
643
|
-
debug
|
|
797
|
+
parse
|
|
644
798
|
);
|
|
645
799
|
delete bundle[analysis.sharedChunk.fileName];
|
|
646
800
|
}
|
|
801
|
+
if (debugDir) {
|
|
802
|
+
writeDebugFile("2-primary-after-shared-merge.js", analysis.primaryChunk.code);
|
|
803
|
+
}
|
|
647
804
|
const allEntries = [analysis.primaryChunk, ...analysis.satelliteChunks];
|
|
648
805
|
for (const unsharedChunk of analysis.unsharedChunks) {
|
|
649
|
-
mergeUnsharedIntoImporters(unsharedChunk, allEntries, parse
|
|
806
|
+
mergeUnsharedIntoImporters(unsharedChunk, allEntries, parse);
|
|
650
807
|
delete bundle[unsharedChunk.fileName];
|
|
651
808
|
}
|
|
809
|
+
if (debugDir) {
|
|
810
|
+
writeDebugFile("3-primary-before-iife.js", analysis.primaryChunk.code);
|
|
811
|
+
for (const satellite of analysis.satelliteChunks) {
|
|
812
|
+
writeDebugFile(`3-satellite-${sanitizeName(satellite.name)}-before-iife.js`, satellite.code);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
652
815
|
const conversions = [];
|
|
653
816
|
conversions.push(
|
|
654
817
|
convertToIife({
|
|
@@ -659,7 +822,7 @@ function iifeSplit(options) {
|
|
|
659
822
|
// Primary doesn't need to import shared
|
|
660
823
|
sharedChunkFileName: null,
|
|
661
824
|
parse,
|
|
662
|
-
|
|
825
|
+
skipRequireGlobals
|
|
663
826
|
}).then((code) => {
|
|
664
827
|
analysis.primaryChunk.code = code;
|
|
665
828
|
})
|
|
@@ -681,7 +844,7 @@ function iifeSplit(options) {
|
|
|
681
844
|
sharedGlobalPath: `${primaryGlobal}.${sharedProp}`,
|
|
682
845
|
sharedChunkFileName,
|
|
683
846
|
parse,
|
|
684
|
-
|
|
847
|
+
skipRequireGlobals
|
|
685
848
|
}).then((code) => {
|
|
686
849
|
satellite.code = code;
|
|
687
850
|
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rollup-plugin-iife-split",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Rollup plugin for intelligent IIFE code-splitting",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
"rollup": "^3.0.0 || ^4.0.0"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"estree-walker": "^3.0.0",
|
|
16
|
+
"magic-string": "^0.30.0"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
+
"@types/node": "^20.0.0",
|
|
19
20
|
"rollup": "^4.0.0",
|
|
20
|
-
"typescript": "^5.0.0",
|
|
21
21
|
"tsup": "^8.0.0",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
22
|
+
"typescript": "^5.0.0",
|
|
23
|
+
"vitest": "^1.0.0"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"rollup",
|
|
@@ -30,11 +30,16 @@
|
|
|
30
30
|
"bundle"
|
|
31
31
|
],
|
|
32
32
|
"license": "MIT",
|
|
33
|
+
"homepage": "https://github.com/arshaw/rollup-plugin-iife-split",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/arshaw/rollup-plugin-iife-split.git"
|
|
37
|
+
},
|
|
33
38
|
"scripts": {
|
|
34
39
|
"clean": "rm -rf dist",
|
|
35
40
|
"build": "tsup src/index.ts --format esm --dts",
|
|
36
41
|
"typecheck": "tsc --noEmit",
|
|
37
|
-
"test": "vitest",
|
|
38
|
-
"test:
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:dev": "vitest"
|
|
39
44
|
}
|
|
40
45
|
}
|