@atlaspack/packager-js 2.14.5-canary.33 → 2.14.5-canary.330
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/CHANGELOG.md +485 -0
- package/dist/CJSOutputFormat.js +34 -0
- package/dist/DevPackager.js +201 -0
- package/dist/ESMOutputFormat.js +102 -0
- package/dist/GlobalOutputFormat.js +18 -0
- package/dist/ScopeHoistingPackager.js +1401 -0
- package/dist/helpers.js +170 -0
- package/dist/index.js +117 -0
- package/dist/utils.js +60 -0
- package/lib/DevPackager.js +28 -4
- package/lib/ESMOutputFormat.js +1 -1
- package/lib/ScopeHoistingPackager.js +304 -111
- package/lib/dev-prelude.js +6 -6
- package/lib/helpers.js +38 -3
- package/lib/index.js +28 -9
- package/lib/types/CJSOutputFormat.d.ts +7 -0
- package/lib/types/DevPackager.d.ts +15 -0
- package/lib/types/ESMOutputFormat.d.ts +7 -0
- package/lib/types/GlobalOutputFormat.d.ts +7 -0
- package/lib/types/ScopeHoistingPackager.d.ts +73 -0
- package/lib/types/helpers.d.ts +12 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/utils.d.ts +6 -0
- package/package.json +18 -13
- package/src/{CJSOutputFormat.js → CJSOutputFormat.ts} +0 -1
- package/src/{DevPackager.js → DevPackager.ts} +34 -8
- package/src/{ESMOutputFormat.js → ESMOutputFormat.ts} +3 -4
- package/src/{GlobalOutputFormat.js → GlobalOutputFormat.ts} +0 -1
- package/src/{ScopeHoistingPackager.js → ScopeHoistingPackager.ts} +472 -184
- package/src/dev-prelude.js +6 -6
- package/src/{helpers.js → helpers.ts} +37 -3
- package/src/{index.js → index.ts} +63 -39
- package/src/{utils.js → utils.ts} +2 -3
- package/tsconfig.json +30 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
1
|
import type {
|
|
4
2
|
Asset,
|
|
5
3
|
BundleGraph,
|
|
@@ -15,8 +13,10 @@ import {
|
|
|
15
13
|
relativeBundlePath,
|
|
16
14
|
countLines,
|
|
17
15
|
normalizeSeparators,
|
|
16
|
+
debugTools,
|
|
17
|
+
globToRegex,
|
|
18
18
|
} from '@atlaspack/utils';
|
|
19
|
-
import SourceMap from '@
|
|
19
|
+
import SourceMap from '@atlaspack/source-map';
|
|
20
20
|
import nullthrows from 'nullthrows';
|
|
21
21
|
import invariant, {AssertionError} from 'assert';
|
|
22
22
|
import ThrowableDiagnostic, {
|
|
@@ -25,11 +25,18 @@ import ThrowableDiagnostic, {
|
|
|
25
25
|
import globals from 'globals';
|
|
26
26
|
import path from 'path';
|
|
27
27
|
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
28
|
+
import {outdent} from 'outdent';
|
|
28
29
|
|
|
29
30
|
import {ESMOutputFormat} from './ESMOutputFormat';
|
|
30
31
|
import {CJSOutputFormat} from './CJSOutputFormat';
|
|
31
32
|
import {GlobalOutputFormat} from './GlobalOutputFormat';
|
|
32
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
preludeOld,
|
|
35
|
+
preludeNew,
|
|
36
|
+
helpers,
|
|
37
|
+
bundleQueuePrelude,
|
|
38
|
+
fnExpr,
|
|
39
|
+
} from './helpers';
|
|
33
40
|
import {
|
|
34
41
|
replaceScriptDependencies,
|
|
35
42
|
getSpecifier,
|
|
@@ -39,7 +46,6 @@ import {
|
|
|
39
46
|
|
|
40
47
|
// General regex used to replace imports with the resolved code, references with resolutions,
|
|
41
48
|
// and count the number of newlines in the file for source maps.
|
|
42
|
-
//
|
|
43
49
|
// For conditional bundling the only difference in this regex is adding `importCond` where we have `importAsync` etc..
|
|
44
50
|
const REPLACEMENT_RE_CONDITIONAL =
|
|
45
51
|
/\n|import\s+"([0-9a-f]{16,20}:.+?)";|(?:\$[0-9a-f]{16,20}\$exports)|(?:\$[0-9a-f]{16,20}\$(?:import|importAsync|require|importCond)\$[0-9a-f]+(?:\$[0-9a-f]+)?)/g;
|
|
@@ -55,6 +61,7 @@ const GLOBALS_BY_CONTEXT = {
|
|
|
55
61
|
...Object.keys(globals.serviceworker),
|
|
56
62
|
]),
|
|
57
63
|
worklet: new Set([...BUILTINS]),
|
|
64
|
+
tesseract: new Set([...BUILTINS, ...Object.keys(globals.worker)]),
|
|
58
65
|
node: new Set([...BUILTINS, ...Object.keys(globals.node)]),
|
|
59
66
|
'electron-main': new Set([...BUILTINS, ...Object.keys(globals.node)]),
|
|
60
67
|
'electron-renderer': new Set([
|
|
@@ -62,19 +69,28 @@ const GLOBALS_BY_CONTEXT = {
|
|
|
62
69
|
...Object.keys(globals.node),
|
|
63
70
|
...Object.keys(globals.browser),
|
|
64
71
|
]),
|
|
65
|
-
};
|
|
72
|
+
} as const;
|
|
66
73
|
|
|
67
74
|
const OUTPUT_FORMATS = {
|
|
68
75
|
esmodule: ESMOutputFormat,
|
|
69
76
|
commonjs: CJSOutputFormat,
|
|
70
77
|
global: GlobalOutputFormat,
|
|
71
|
-
};
|
|
78
|
+
} as const;
|
|
72
79
|
|
|
73
80
|
export interface OutputFormat {
|
|
74
81
|
buildBundlePrelude(): [string, number];
|
|
75
82
|
buildBundlePostlude(): [string, number];
|
|
76
83
|
}
|
|
77
84
|
|
|
85
|
+
export type PackageResult = {
|
|
86
|
+
contents: string;
|
|
87
|
+
map: SourceMap | null | undefined;
|
|
88
|
+
scopeHoistingStats?: {
|
|
89
|
+
totalAssets: number;
|
|
90
|
+
wrappedAssets: number;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
78
94
|
export class ScopeHoistingPackager {
|
|
79
95
|
options: PluginOptions;
|
|
80
96
|
bundleGraph: BundleGraph<NamedBundle>;
|
|
@@ -83,27 +99,39 @@ export class ScopeHoistingPackager {
|
|
|
83
99
|
useAsyncBundleRuntime: boolean;
|
|
84
100
|
outputFormat: OutputFormat;
|
|
85
101
|
isAsyncBundle: boolean;
|
|
86
|
-
globalNames:
|
|
87
|
-
|
|
102
|
+
globalNames: ReadonlySet<string>;
|
|
103
|
+
manualStaticBindingExports: RegExp[] | null;
|
|
104
|
+
assetOutputs: Map<
|
|
105
|
+
Asset,
|
|
106
|
+
{
|
|
107
|
+
code: string;
|
|
108
|
+
map: Buffer | null | undefined;
|
|
109
|
+
}
|
|
110
|
+
> = new Map();
|
|
88
111
|
exportedSymbols: Map<
|
|
89
112
|
string,
|
|
90
|
-
{
|
|
91
|
-
asset: Asset
|
|
92
|
-
exportSymbol: string
|
|
93
|
-
local: string
|
|
94
|
-
exportAs: Array<string
|
|
95
|
-
|
|
113
|
+
{
|
|
114
|
+
asset: Asset;
|
|
115
|
+
exportSymbol: string;
|
|
116
|
+
local: string;
|
|
117
|
+
exportAs: Array<string>;
|
|
118
|
+
}
|
|
96
119
|
> = new Map();
|
|
97
120
|
externals: Map<string, Map<string, string>> = new Map();
|
|
98
121
|
topLevelNames: Map<string, number> = new Map();
|
|
99
|
-
seenAssets: Set<
|
|
100
|
-
wrappedAssets: Set<
|
|
101
|
-
|
|
122
|
+
seenAssets: Set<Asset> = new Set();
|
|
123
|
+
wrappedAssets: Set<Asset> = new Set();
|
|
124
|
+
constantAssets: Set<Asset> = new Set();
|
|
125
|
+
hoistedRequires: Map<Dependency, Map<Asset, string>> = new Map();
|
|
126
|
+
seenHoistedRequires: Set<string> = new Set();
|
|
102
127
|
needsPrelude: boolean = false;
|
|
103
128
|
usedHelpers: Set<string> = new Set();
|
|
104
129
|
externalAssets: Set<Asset> = new Set();
|
|
105
|
-
forceSkipWrapAssets: Array<string> = [];
|
|
106
130
|
logger: PluginLogger;
|
|
131
|
+
useBothScopeHoistingImprovements: boolean =
|
|
132
|
+
getFeatureFlag('applyScopeHoistingImprovementV2') ||
|
|
133
|
+
getFeatureFlag('applyScopeHoistingImprovement');
|
|
134
|
+
referencedAssetsCache: Map<string, Set<Asset>> = new Map();
|
|
107
135
|
|
|
108
136
|
constructor(
|
|
109
137
|
options: PluginOptions,
|
|
@@ -111,7 +139,7 @@ export class ScopeHoistingPackager {
|
|
|
111
139
|
bundle: NamedBundle,
|
|
112
140
|
parcelRequireName: string,
|
|
113
141
|
useAsyncBundleRuntime: boolean,
|
|
114
|
-
|
|
142
|
+
manualStaticBindingExports: string[] | null,
|
|
115
143
|
logger: PluginLogger,
|
|
116
144
|
) {
|
|
117
145
|
this.options = options;
|
|
@@ -119,7 +147,8 @@ export class ScopeHoistingPackager {
|
|
|
119
147
|
this.bundle = bundle;
|
|
120
148
|
this.parcelRequireName = parcelRequireName;
|
|
121
149
|
this.useAsyncBundleRuntime = useAsyncBundleRuntime;
|
|
122
|
-
this.
|
|
150
|
+
this.manualStaticBindingExports =
|
|
151
|
+
manualStaticBindingExports?.map((glob) => globToRegex(glob)) ?? null;
|
|
123
152
|
this.logger = logger;
|
|
124
153
|
|
|
125
154
|
let OutputFormat = OUTPUT_FORMATS[this.bundle.env.outputFormat];
|
|
@@ -128,13 +157,14 @@ export class ScopeHoistingPackager {
|
|
|
128
157
|
this.isAsyncBundle =
|
|
129
158
|
this.bundleGraph.hasParentBundleOfType(this.bundle, 'js') &&
|
|
130
159
|
!this.bundle.env.isIsolated() &&
|
|
131
|
-
this.bundle.bundleBehavior !== 'isolated'
|
|
160
|
+
this.bundle.bundleBehavior !== 'isolated' &&
|
|
161
|
+
this.bundle.bundleBehavior !== 'inlineIsolated';
|
|
132
162
|
|
|
133
163
|
this.globalNames = GLOBALS_BY_CONTEXT[bundle.env.context];
|
|
134
164
|
}
|
|
135
165
|
|
|
136
|
-
async package(): Promise<
|
|
137
|
-
|
|
166
|
+
async package(): Promise<PackageResult> {
|
|
167
|
+
await this.loadAssets();
|
|
138
168
|
this.buildExportedSymbols();
|
|
139
169
|
|
|
140
170
|
// If building a library, the target is actually another bundler rather
|
|
@@ -155,9 +185,11 @@ export class ScopeHoistingPackager {
|
|
|
155
185
|
|
|
156
186
|
let res = '';
|
|
157
187
|
let lineCount = 0;
|
|
158
|
-
let sourceMap = null;
|
|
159
|
-
let processAsset = (asset) => {
|
|
188
|
+
let sourceMap: SourceMap | null | undefined = null;
|
|
189
|
+
let processAsset = (asset: Asset) => {
|
|
190
|
+
this.seenHoistedRequires.clear();
|
|
160
191
|
let [content, map, lines] = this.visitAsset(asset);
|
|
192
|
+
|
|
161
193
|
if (sourceMap && map) {
|
|
162
194
|
sourceMap.addSourceMap(map, lineCount);
|
|
163
195
|
} else if (this.bundle.env.sourceMap) {
|
|
@@ -168,10 +200,22 @@ export class ScopeHoistingPackager {
|
|
|
168
200
|
lineCount += lines + 1;
|
|
169
201
|
};
|
|
170
202
|
|
|
203
|
+
if (
|
|
204
|
+
getFeatureFlag('inlineConstOptimisationFix') ||
|
|
205
|
+
this.useBothScopeHoistingImprovements
|
|
206
|
+
) {
|
|
207
|
+
// Write out all constant modules used by this bundle
|
|
208
|
+
for (let asset of this.constantAssets) {
|
|
209
|
+
if (!this.seenAssets.has(asset)) {
|
|
210
|
+
processAsset(asset);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
171
215
|
// Hoist wrapped asset to the top of the bundle to ensure that they are registered
|
|
172
216
|
// before they are used.
|
|
173
|
-
for (let asset of wrappedAssets) {
|
|
174
|
-
if (!this.seenAssets.has(asset
|
|
217
|
+
for (let asset of this.wrappedAssets) {
|
|
218
|
+
if (!this.seenAssets.has(asset)) {
|
|
175
219
|
processAsset(asset);
|
|
176
220
|
}
|
|
177
221
|
}
|
|
@@ -179,7 +223,7 @@ export class ScopeHoistingPackager {
|
|
|
179
223
|
// Add each asset that is directly connected to the bundle. Dependencies will be handled
|
|
180
224
|
// by replacing `import` statements in the code.
|
|
181
225
|
this.bundle.traverseAssets((asset, _, actions) => {
|
|
182
|
-
if (this.seenAssets.has(asset
|
|
226
|
+
if (this.seenAssets.has(asset)) {
|
|
183
227
|
actions.skipChildren();
|
|
184
228
|
return;
|
|
185
229
|
}
|
|
@@ -191,14 +235,28 @@ export class ScopeHoistingPackager {
|
|
|
191
235
|
let [prelude, preludeLines] = this.buildBundlePrelude();
|
|
192
236
|
res = prelude + res;
|
|
193
237
|
lineCount += preludeLines;
|
|
238
|
+
// @ts-expect-error TS2339 - offsetLines method exists but missing from @parcel/source-map type definitions
|
|
194
239
|
sourceMap?.offsetLines(1, preludeLines);
|
|
195
240
|
|
|
196
241
|
let entries = this.bundle.getEntryAssets();
|
|
197
242
|
let mainEntry = this.bundle.getMainEntry();
|
|
198
243
|
if (this.isAsyncBundle) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
244
|
+
if (
|
|
245
|
+
this.useBothScopeHoistingImprovements ||
|
|
246
|
+
getFeatureFlag('supportWebpackChunkName')
|
|
247
|
+
) {
|
|
248
|
+
// Generally speaking, async bundles should not be executed on load, as
|
|
249
|
+
// they're just collections of assets that other assets require.
|
|
250
|
+
// However, there are some special cases where a runtime asset needs to be
|
|
251
|
+
// injected, but no other asset will require it (mostly the bundle
|
|
252
|
+
// manifest).
|
|
253
|
+
// In this case, those assets need to be required on load.
|
|
254
|
+
entries = entries.filter(
|
|
255
|
+
(a) => a.meta?.runtimeAssetRequiringExecutionOnLoad,
|
|
256
|
+
);
|
|
257
|
+
} else {
|
|
258
|
+
entries = entries.filter((a) => a.id !== mainEntry?.id);
|
|
259
|
+
}
|
|
202
260
|
mainEntry = null;
|
|
203
261
|
}
|
|
204
262
|
|
|
@@ -206,7 +264,7 @@ export class ScopeHoistingPackager {
|
|
|
206
264
|
|
|
207
265
|
// If any of the entry assets are wrapped, call parcelRequire so they are executed.
|
|
208
266
|
for (let entry of entries) {
|
|
209
|
-
if (this.wrappedAssets.has(entry
|
|
267
|
+
if (this.wrappedAssets.has(entry) && !this.isScriptEntry(entry)) {
|
|
210
268
|
let parcelRequire = `parcelRequire(${JSON.stringify(
|
|
211
269
|
this.bundleGraph.getAssetPublicId(entry),
|
|
212
270
|
)});\n`;
|
|
@@ -250,9 +308,7 @@ export class ScopeHoistingPackager {
|
|
|
250
308
|
lineCount++;
|
|
251
309
|
|
|
252
310
|
let mainEntry = nullthrows(this.bundle.getMainEntry());
|
|
253
|
-
let {code, map: mapBuffer} = nullthrows(
|
|
254
|
-
this.assetOutputs.get(mainEntry.id),
|
|
255
|
-
);
|
|
311
|
+
let {code, map: mapBuffer} = nullthrows(this.assetOutputs.get(mainEntry));
|
|
256
312
|
let map;
|
|
257
313
|
if (mapBuffer) {
|
|
258
314
|
map = new SourceMap(this.options.projectRoot, mapBuffer);
|
|
@@ -265,14 +321,21 @@ export class ScopeHoistingPackager {
|
|
|
265
321
|
this.parcelRequireName,
|
|
266
322
|
);
|
|
267
323
|
if (sourceMap && map) {
|
|
324
|
+
// @ts-expect-error TS2339 - addSourceMap method exists but missing from @parcel/source-map type definitions
|
|
268
325
|
sourceMap.addSourceMap(map, lineCount);
|
|
269
326
|
}
|
|
270
327
|
}
|
|
271
328
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
329
|
+
const result: PackageResult = {contents: res, map: sourceMap};
|
|
330
|
+
|
|
331
|
+
if (debugTools['scope-hoisting-stats']) {
|
|
332
|
+
result.scopeHoistingStats = {
|
|
333
|
+
totalAssets: this.assetOutputs.size,
|
|
334
|
+
wrappedAssets: this.wrappedAssets.size,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return result;
|
|
276
339
|
}
|
|
277
340
|
|
|
278
341
|
shouldBundleQueue(bundle: NamedBundle): boolean {
|
|
@@ -281,10 +344,7 @@ export class ScopeHoistingPackager {
|
|
|
281
344
|
|
|
282
345
|
let hasConditionalReference = false;
|
|
283
346
|
let isConditionalBundle = false;
|
|
284
|
-
if (
|
|
285
|
-
getFeatureFlag('conditionalBundlingApi') &&
|
|
286
|
-
getFeatureFlag('conditionalBundlingAsyncRuntime')
|
|
287
|
-
) {
|
|
347
|
+
if (getFeatureFlag('conditionalBundlingApi')) {
|
|
288
348
|
// If the bundle has a conditional bundle reference (has an importCond)
|
|
289
349
|
hasConditionalReference =
|
|
290
350
|
this.bundleGraph.getReferencedConditionalBundles(bundle).length > 0;
|
|
@@ -296,6 +356,7 @@ export class ScopeHoistingPackager {
|
|
|
296
356
|
this.useAsyncBundleRuntime &&
|
|
297
357
|
bundle.type === 'js' &&
|
|
298
358
|
bundle.bundleBehavior !== 'inline' &&
|
|
359
|
+
bundle.bundleBehavior !== 'inlineIsolated' &&
|
|
299
360
|
bundle.env.outputFormat === 'esmodule' &&
|
|
300
361
|
!bundle.env.isIsolated() &&
|
|
301
362
|
bundle.bundleBehavior !== 'isolated' &&
|
|
@@ -309,11 +370,8 @@ export class ScopeHoistingPackager {
|
|
|
309
370
|
.filter((b) => this.shouldBundleQueue(b))
|
|
310
371
|
.map((b) => b.publicId);
|
|
311
372
|
|
|
312
|
-
const conditions = [];
|
|
313
|
-
if (
|
|
314
|
-
getFeatureFlag('conditionalBundlingApi') &&
|
|
315
|
-
getFeatureFlag('conditionalBundlingAsyncRuntime')
|
|
316
|
-
) {
|
|
373
|
+
const conditions: Array<string> = [];
|
|
374
|
+
if (getFeatureFlag('conditionalBundlingApi')) {
|
|
317
375
|
const conditionSet = this.bundleGraph
|
|
318
376
|
.getConditionalBundleMapping()
|
|
319
377
|
.get(bundle.id);
|
|
@@ -354,22 +412,64 @@ export class ScopeHoistingPackager {
|
|
|
354
412
|
return `$parcel$global.rwr(${params.join(', ')});`;
|
|
355
413
|
}
|
|
356
414
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
415
|
+
// Helper to check if an asset is referenced, with cache-first + fast-check hybrid approach
|
|
416
|
+
isAssetReferencedInBundle(bundle: NamedBundle, asset: Asset): boolean {
|
|
417
|
+
// STEP 1: Check expensive computation cache first (fastest when it hits)
|
|
418
|
+
if (getFeatureFlag('precomputeReferencedAssets')) {
|
|
419
|
+
let bundleId = bundle.id;
|
|
420
|
+
let referencedAssets = this.referencedAssetsCache.get(bundleId);
|
|
421
|
+
|
|
422
|
+
if (referencedAssets) {
|
|
423
|
+
// Cache hit - fastest path (~0.001ms)
|
|
424
|
+
return referencedAssets.has(asset);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// STEP 2: Cache miss - try fast checks (~0.01ms)
|
|
429
|
+
let fastCheckResult = this.bundleGraph.isAssetReferencedFastCheck(
|
|
430
|
+
bundle,
|
|
431
|
+
asset,
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
if (fastCheckResult === true) {
|
|
435
|
+
// Fast check succeeded - asset is referenced
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// STEP 3: Need expensive computation (~20-2000ms)
|
|
440
|
+
if (getFeatureFlag('precomputeReferencedAssets')) {
|
|
441
|
+
// Compute and cache expensive results for this bundle
|
|
442
|
+
let bundleId = bundle.id;
|
|
443
|
+
let referencedAssets = this.bundleGraph.getReferencedAssets(bundle);
|
|
444
|
+
this.referencedAssetsCache.set(bundleId, referencedAssets);
|
|
445
|
+
|
|
446
|
+
return referencedAssets.has(asset);
|
|
447
|
+
} else {
|
|
448
|
+
// No caching - fall back to original expensive method
|
|
449
|
+
return this.bundleGraph.isAssetReferenced(bundle, asset);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async loadAssets() {
|
|
454
|
+
type QueueItem = [Asset, {code: string; map: Buffer | undefined | null}];
|
|
455
|
+
let queue = new PromiseQueue<QueueItem>({
|
|
456
|
+
maxConcurrent: 32,
|
|
457
|
+
});
|
|
458
|
+
|
|
360
459
|
this.bundle.traverseAssets((asset) => {
|
|
361
460
|
queue.add(async () => {
|
|
362
461
|
let [code, map] = await Promise.all([
|
|
363
462
|
asset.getCode(),
|
|
364
463
|
this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
|
|
365
464
|
]);
|
|
366
|
-
|
|
465
|
+
|
|
466
|
+
return [asset, {code, map}];
|
|
367
467
|
});
|
|
368
468
|
|
|
369
469
|
if (
|
|
370
470
|
asset.meta.shouldWrap ||
|
|
371
471
|
this.bundle.env.sourceType === 'script' ||
|
|
372
|
-
this.
|
|
472
|
+
this.isAssetReferencedInBundle(this.bundle, asset) ||
|
|
373
473
|
this.bundleGraph
|
|
374
474
|
.getIncomingDependencies(asset)
|
|
375
475
|
.some((dep) => dep.meta.shouldWrap && dep.specifierType !== 'url')
|
|
@@ -381,52 +481,113 @@ export class ScopeHoistingPackager {
|
|
|
381
481
|
.getIncomingDependencies(asset)
|
|
382
482
|
.some((dep) => dep.priority === 'lazy')
|
|
383
483
|
) {
|
|
384
|
-
this.wrappedAssets.add(asset
|
|
385
|
-
|
|
484
|
+
this.wrappedAssets.add(asset);
|
|
485
|
+
} else if (
|
|
486
|
+
(getFeatureFlag('inlineConstOptimisationFix') ||
|
|
487
|
+
this.useBothScopeHoistingImprovements) &&
|
|
488
|
+
asset.meta.isConstantModule
|
|
489
|
+
) {
|
|
490
|
+
this.constantAssets.add(asset);
|
|
386
491
|
}
|
|
387
492
|
}
|
|
388
493
|
});
|
|
389
494
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
495
|
+
if (this.useBothScopeHoistingImprovements) {
|
|
496
|
+
// Tracks which assets have been assigned to a wrap group
|
|
497
|
+
let assignedAssets = new Set<Asset>();
|
|
498
|
+
|
|
499
|
+
// In V2 scope hoisting, we iterate from the main entry, rather than
|
|
500
|
+
// wrapping the entry assets
|
|
501
|
+
if (!getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
502
|
+
// Make all entry assets wrapped, to avoid any top level hoisting
|
|
503
|
+
for (let entryAsset of this.bundle.getEntryAssets()) {
|
|
504
|
+
if (!this.wrappedAssets.has(entryAsset)) {
|
|
505
|
+
this.wrappedAssets.add(entryAsset);
|
|
506
|
+
}
|
|
394
507
|
}
|
|
508
|
+
}
|
|
395
509
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
this.forceSkipWrapAssets.length > 0 &&
|
|
407
|
-
this.forceSkipWrapAssets.some(
|
|
408
|
-
(p) =>
|
|
409
|
-
p === path.relative(this.options.projectRoot, asset.filePath),
|
|
410
|
-
)
|
|
411
|
-
) {
|
|
412
|
-
this.logger.verbose({
|
|
413
|
-
message: `Force skipping wrapping of ${path.relative(
|
|
414
|
-
this.options.projectRoot,
|
|
415
|
-
asset.filePath,
|
|
416
|
-
)}`,
|
|
417
|
-
});
|
|
418
|
-
actions.skipChildren();
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
if (!asset.meta.isConstantModule) {
|
|
422
|
-
this.wrappedAssets.add(asset.id);
|
|
423
|
-
wrapped.push(asset);
|
|
510
|
+
// We need to make a new copy here so that we can add to the list and
|
|
511
|
+
// iterate the newly added items, without mutating the wrappedAssets set
|
|
512
|
+
let moduleGroupParents = [...this.wrappedAssets.values()];
|
|
513
|
+
|
|
514
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
515
|
+
// The main entry needs to be check to find assets that would have gone in
|
|
516
|
+
// the top level scope
|
|
517
|
+
let mainEntry = this.bundle.getMainEntry();
|
|
518
|
+
if (mainEntry && !this.wrappedAssets.has(mainEntry)) {
|
|
519
|
+
moduleGroupParents.unshift(mainEntry);
|
|
424
520
|
}
|
|
425
|
-
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
for (let moduleGroupParentAsset of moduleGroupParents) {
|
|
524
|
+
this.bundle.traverseAssets((asset, _, actions) => {
|
|
525
|
+
if (asset === moduleGroupParentAsset) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (this.wrappedAssets.has(asset)) {
|
|
530
|
+
actions.skipChildren();
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (
|
|
535
|
+
!asset.meta.isConstantModule &&
|
|
536
|
+
(assignedAssets.has(asset) || this.isReExported(asset))
|
|
537
|
+
) {
|
|
538
|
+
this.wrappedAssets.add(asset);
|
|
539
|
+
|
|
540
|
+
// This also needs to be added to the traversal so that we iterate
|
|
541
|
+
// it during this check.
|
|
542
|
+
moduleGroupParents.push(asset);
|
|
543
|
+
|
|
544
|
+
actions.skipChildren();
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
assignedAssets.add(asset);
|
|
549
|
+
}, moduleGroupParentAsset);
|
|
550
|
+
}
|
|
551
|
+
} else {
|
|
552
|
+
for (let wrappedAssetRoot of this.wrappedAssets) {
|
|
553
|
+
this.bundle.traverseAssets((asset, _, actions) => {
|
|
554
|
+
if (asset === wrappedAssetRoot) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (this.wrappedAssets.has(asset)) {
|
|
559
|
+
actions.skipChildren();
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (!asset.meta.isConstantModule) {
|
|
564
|
+
this.wrappedAssets.add(asset);
|
|
565
|
+
}
|
|
566
|
+
}, wrappedAssetRoot);
|
|
567
|
+
}
|
|
426
568
|
}
|
|
427
569
|
|
|
428
570
|
this.assetOutputs = new Map(await queue.run());
|
|
429
|
-
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
isReExported(asset: Asset): boolean {
|
|
574
|
+
let parentSymbols = this.bundleGraph
|
|
575
|
+
.getIncomingDependencies(asset)
|
|
576
|
+
.map((dep) => this.bundleGraph.getAssetWithDependency(dep))
|
|
577
|
+
.flatMap((parent) => {
|
|
578
|
+
if (parent == null) {
|
|
579
|
+
return [];
|
|
580
|
+
}
|
|
581
|
+
return this.bundleGraph.getExportedSymbols(parent, this.bundle);
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
|
|
585
|
+
|
|
586
|
+
return assetSymbols.some((assetSymbol) =>
|
|
587
|
+
parentSymbols.some(
|
|
588
|
+
(parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
|
|
589
|
+
),
|
|
590
|
+
);
|
|
430
591
|
}
|
|
431
592
|
|
|
432
593
|
buildExportedSymbols() {
|
|
@@ -439,7 +600,7 @@ export class ScopeHoistingPackager {
|
|
|
439
600
|
|
|
440
601
|
// TODO: handle ESM exports of wrapped entry assets...
|
|
441
602
|
let entry = this.bundle.getMainEntry();
|
|
442
|
-
if (entry && !this.wrappedAssets.has(entry
|
|
603
|
+
if (entry && !this.wrappedAssets.has(entry)) {
|
|
443
604
|
let hasNamespace = entry.symbols.hasExportSymbol('*');
|
|
444
605
|
|
|
445
606
|
for (let {
|
|
@@ -464,6 +625,7 @@ export class ScopeHoistingPackager {
|
|
|
464
625
|
symbols = [];
|
|
465
626
|
this.exportedSymbols.set(symbol, {
|
|
466
627
|
asset,
|
|
628
|
+
|
|
467
629
|
exportSymbol,
|
|
468
630
|
local: symbol,
|
|
469
631
|
exportAs: symbols,
|
|
@@ -519,20 +681,24 @@ export class ScopeHoistingPackager {
|
|
|
519
681
|
return `${obj}[${JSON.stringify(property)}]`;
|
|
520
682
|
}
|
|
521
683
|
|
|
522
|
-
visitAsset(asset: Asset): [string,
|
|
523
|
-
invariant(!this.seenAssets.has(asset
|
|
524
|
-
this.seenAssets.add(asset
|
|
684
|
+
visitAsset(asset: Asset): [string, SourceMap | null | undefined, number] {
|
|
685
|
+
invariant(!this.seenAssets.has(asset), 'Already visited asset');
|
|
686
|
+
this.seenAssets.add(asset);
|
|
525
687
|
|
|
526
|
-
let {code, map} = nullthrows(this.assetOutputs.get(asset
|
|
688
|
+
let {code, map} = nullthrows(this.assetOutputs.get(asset));
|
|
527
689
|
return this.buildAsset(asset, code, map);
|
|
528
690
|
}
|
|
529
691
|
|
|
692
|
+
getAssetFilePath(asset: Asset): string {
|
|
693
|
+
return path.relative(this.options.projectRoot, asset.filePath);
|
|
694
|
+
}
|
|
695
|
+
|
|
530
696
|
buildAsset(
|
|
531
697
|
asset: Asset,
|
|
532
698
|
code: string,
|
|
533
|
-
map
|
|
534
|
-
): [string,
|
|
535
|
-
let shouldWrap = this.wrappedAssets.has(asset
|
|
699
|
+
map?: Buffer | null,
|
|
700
|
+
): [string, SourceMap | null | undefined, number] {
|
|
701
|
+
let shouldWrap = this.wrappedAssets.has(asset);
|
|
536
702
|
let deps = this.bundleGraph.getDependencies(asset);
|
|
537
703
|
|
|
538
704
|
let sourceMap =
|
|
@@ -559,16 +725,29 @@ export class ScopeHoistingPackager {
|
|
|
559
725
|
continue;
|
|
560
726
|
}
|
|
561
727
|
|
|
562
|
-
if (
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
728
|
+
if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved)) {
|
|
729
|
+
if (
|
|
730
|
+
this.useBothScopeHoistingImprovements &&
|
|
731
|
+
this.wrappedAssets.has(resolved)
|
|
732
|
+
) {
|
|
733
|
+
if (this.wrappedAssets.has(asset)) {
|
|
734
|
+
// If both the asset and the dep are wrapped there's no need to
|
|
735
|
+
// drop a side-effect require. This is an extremely rare case.
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// When the dep is wrapped then we just need to drop a side effect
|
|
740
|
+
// require instead of inlining
|
|
741
|
+
depCode += `parcelRequire("${this.bundleGraph.getAssetPublicId(resolved)}");\n`;
|
|
742
|
+
lineCount += 1;
|
|
743
|
+
} else {
|
|
744
|
+
let [code, map, lines] = this.visitAsset(resolved);
|
|
745
|
+
depCode += code + '\n';
|
|
746
|
+
if (sourceMap && map) {
|
|
747
|
+
sourceMap.addSourceMap(map, lineCount);
|
|
748
|
+
}
|
|
749
|
+
lineCount += lines + 1;
|
|
570
750
|
}
|
|
571
|
-
lineCount += lines + 1;
|
|
572
751
|
}
|
|
573
752
|
}
|
|
574
753
|
|
|
@@ -602,7 +781,7 @@ export class ScopeHoistingPackager {
|
|
|
602
781
|
code += append;
|
|
603
782
|
|
|
604
783
|
let lineCount = 0;
|
|
605
|
-
let depContent = [];
|
|
784
|
+
let depContent: Array<[string, SourceMap | null | undefined, number]> = [];
|
|
606
785
|
if (depMap.size === 0 && replacements.size === 0) {
|
|
607
786
|
// If there are no dependencies or replacements, use a simple function to count the number of lines.
|
|
608
787
|
lineCount = countLines(code) - 1;
|
|
@@ -647,27 +826,68 @@ export class ScopeHoistingPackager {
|
|
|
647
826
|
// after the dependency is declared. This handles the case where the resulting asset
|
|
648
827
|
// is wrapped, but the dependency in this asset is not marked as wrapped. This means
|
|
649
828
|
// that it was imported/required at the top-level, so its side effects should run immediately.
|
|
650
|
-
let
|
|
651
|
-
|
|
652
|
-
dep,
|
|
653
|
-
resolved,
|
|
654
|
-
);
|
|
829
|
+
let res = '';
|
|
830
|
+
let lines = 0;
|
|
655
831
|
let map;
|
|
832
|
+
|
|
833
|
+
if (!getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
834
|
+
[res, lines] = this.getHoistedParcelRequires(
|
|
835
|
+
asset,
|
|
836
|
+
dep,
|
|
837
|
+
resolved,
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
|
|
656
841
|
if (
|
|
657
842
|
this.bundle.hasAsset(resolved) &&
|
|
658
|
-
!this.seenAssets.has(resolved
|
|
843
|
+
!this.seenAssets.has(resolved)
|
|
659
844
|
) {
|
|
660
845
|
// If this asset is wrapped, we need to hoist the code for the dependency
|
|
661
846
|
// outside our parcelRequire.register wrapper. This is safe because all
|
|
662
847
|
// assets referenced by this asset will also be wrapped. Otherwise, inline the
|
|
663
848
|
// asset content where the import statement was.
|
|
664
|
-
if (
|
|
665
|
-
|
|
849
|
+
if (this.useBothScopeHoistingImprovements) {
|
|
850
|
+
if (
|
|
851
|
+
!resolved.meta.isConstantModule &&
|
|
852
|
+
!this.wrappedAssets.has(resolved)
|
|
853
|
+
) {
|
|
854
|
+
let [depCode, depMap, depLines] =
|
|
855
|
+
this.visitAsset(resolved);
|
|
856
|
+
if (debugTools['asset-file-names-in-output']) {
|
|
857
|
+
let resolvedPath = this.getAssetFilePath(resolved);
|
|
858
|
+
res = outdent`
|
|
859
|
+
/* Scope hoisted asset: ${resolvedPath} */
|
|
860
|
+
${depCode}
|
|
861
|
+
/* End: ${resolvedPath} */
|
|
862
|
+
${res}
|
|
863
|
+
`;
|
|
864
|
+
lines += 3 + depLines;
|
|
865
|
+
} else {
|
|
866
|
+
res = depCode + '\n' + res;
|
|
867
|
+
lines += 1 + depLines;
|
|
868
|
+
}
|
|
869
|
+
map = depMap;
|
|
870
|
+
}
|
|
666
871
|
} else {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
872
|
+
if (shouldWrap) {
|
|
873
|
+
depContent.push(this.visitAsset(resolved));
|
|
874
|
+
} else {
|
|
875
|
+
let [depCode, depMap, depLines] =
|
|
876
|
+
this.visitAsset(resolved);
|
|
877
|
+
res = depCode + '\n' + res;
|
|
878
|
+
lines += 1 + depLines;
|
|
879
|
+
map = depMap;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
885
|
+
let [requiresCode, requiresLines] =
|
|
886
|
+
this.getHoistedParcelRequires(asset, dep, resolved);
|
|
887
|
+
|
|
888
|
+
if (requiresCode) {
|
|
889
|
+
res = requiresCode + '\n' + res;
|
|
890
|
+
lines += requiresLines + 1;
|
|
671
891
|
}
|
|
672
892
|
}
|
|
673
893
|
|
|
@@ -726,6 +946,11 @@ ${code}
|
|
|
726
946
|
|
|
727
947
|
lineCount += 2;
|
|
728
948
|
|
|
949
|
+
if (debugTools['asset-file-names-in-output']) {
|
|
950
|
+
code = `/* ${this.getAssetFilePath(asset)} */\n` + code;
|
|
951
|
+
lineCount += 1;
|
|
952
|
+
}
|
|
953
|
+
|
|
729
954
|
for (let [depCode, map, lines] of depContent) {
|
|
730
955
|
if (!depCode) continue;
|
|
731
956
|
code += depCode + '\n';
|
|
@@ -803,7 +1028,7 @@ ${code}
|
|
|
803
1028
|
referencedBundle &&
|
|
804
1029
|
referencedBundle.getMainEntry() === resolved &&
|
|
805
1030
|
referencedBundle.type === 'js' &&
|
|
806
|
-
!this.
|
|
1031
|
+
!this.isAssetReferencedInBundle(referencedBundle, resolved)
|
|
807
1032
|
) {
|
|
808
1033
|
this.addExternal(dep, replacements, referencedBundle);
|
|
809
1034
|
this.externalAssets.add(resolved);
|
|
@@ -848,7 +1073,7 @@ ${code}
|
|
|
848
1073
|
// If this asset is wrapped, we need to replace the exports namespace with `module.exports`,
|
|
849
1074
|
// which will be provided to us by the wrapper.
|
|
850
1075
|
if (
|
|
851
|
-
this.wrappedAssets.has(asset
|
|
1076
|
+
this.wrappedAssets.has(asset) ||
|
|
852
1077
|
(this.bundle.env.outputFormat === 'commonjs' &&
|
|
853
1078
|
asset === this.bundle.getMainEntry())
|
|
854
1079
|
) {
|
|
@@ -895,7 +1120,9 @@ ${code}
|
|
|
895
1120
|
|
|
896
1121
|
for (let [imported, {local}] of dep.symbols) {
|
|
897
1122
|
// If already imported, just add the already renamed variable to the mapping.
|
|
1123
|
+
|
|
898
1124
|
let renamed = external.get(imported);
|
|
1125
|
+
|
|
899
1126
|
if (renamed && local !== '*' && replacements) {
|
|
900
1127
|
replacements.set(local, renamed);
|
|
901
1128
|
continue;
|
|
@@ -908,6 +1135,7 @@ ${code}
|
|
|
908
1135
|
if (!renamed) {
|
|
909
1136
|
if (referencedBundle) {
|
|
910
1137
|
let entry = nullthrows(referencedBundle.getMainEntry());
|
|
1138
|
+
|
|
911
1139
|
renamed =
|
|
912
1140
|
entry.symbols.get('*')?.local ??
|
|
913
1141
|
`$${String(entry.meta.id)}$exports`;
|
|
@@ -922,6 +1150,7 @@ ${code}
|
|
|
922
1150
|
|
|
923
1151
|
if (local !== '*' && replacements) {
|
|
924
1152
|
let replacement;
|
|
1153
|
+
|
|
925
1154
|
if (imported === '*') {
|
|
926
1155
|
replacement = renamed;
|
|
927
1156
|
} else if (imported === 'default') {
|
|
@@ -946,10 +1175,12 @@ ${code}
|
|
|
946
1175
|
let property;
|
|
947
1176
|
if (referencedBundle) {
|
|
948
1177
|
let entry = nullthrows(referencedBundle.getMainEntry());
|
|
1178
|
+
|
|
949
1179
|
if (entry.symbols.hasExportSymbol('*')) {
|
|
950
1180
|
// If importing * and the referenced module has a * export (e.g. CJS), use default instead.
|
|
951
1181
|
// This mirrors the logic in buildExportedSymbols.
|
|
952
1182
|
property = imported;
|
|
1183
|
+
|
|
953
1184
|
imported =
|
|
954
1185
|
referencedBundle?.env.outputFormat === 'esmodule'
|
|
955
1186
|
? 'default'
|
|
@@ -957,6 +1188,7 @@ ${code}
|
|
|
957
1188
|
} else {
|
|
958
1189
|
if (imported === '*') {
|
|
959
1190
|
let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
|
|
1191
|
+
|
|
960
1192
|
if (local === '*') {
|
|
961
1193
|
// Re-export all symbols.
|
|
962
1194
|
for (let exported of exportedSymbols) {
|
|
@@ -967,11 +1199,10 @@ ${code}
|
|
|
967
1199
|
continue;
|
|
968
1200
|
}
|
|
969
1201
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
imported,
|
|
973
|
-
|
|
974
|
-
).symbol;
|
|
1202
|
+
|
|
1203
|
+
renamed =
|
|
1204
|
+
this.bundleGraph.getSymbolResolution(entry, imported, this.bundle)
|
|
1205
|
+
.symbol || undefined;
|
|
975
1206
|
}
|
|
976
1207
|
}
|
|
977
1208
|
|
|
@@ -993,8 +1224,10 @@ ${code}
|
|
|
993
1224
|
}
|
|
994
1225
|
|
|
995
1226
|
external.set(imported, renamed);
|
|
1227
|
+
|
|
996
1228
|
if (local !== '*' && replacements) {
|
|
997
1229
|
let replacement = renamed;
|
|
1230
|
+
|
|
998
1231
|
if (property === '*') {
|
|
999
1232
|
replacement = renamed;
|
|
1000
1233
|
} else if (property === 'default') {
|
|
@@ -1003,6 +1236,7 @@ ${code}
|
|
|
1003
1236
|
} else if (property) {
|
|
1004
1237
|
replacement = this.getPropertyAccess(renamed, property);
|
|
1005
1238
|
}
|
|
1239
|
+
|
|
1006
1240
|
replacements.set(local, replacement);
|
|
1007
1241
|
}
|
|
1008
1242
|
}
|
|
@@ -1026,7 +1260,7 @@ ${code}
|
|
|
1026
1260
|
}
|
|
1027
1261
|
return (
|
|
1028
1262
|
(!this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved)) ||
|
|
1029
|
-
(this.wrappedAssets.has(resolved
|
|
1263
|
+
(this.wrappedAssets.has(resolved) && resolved !== parentAsset)
|
|
1030
1264
|
);
|
|
1031
1265
|
}
|
|
1032
1266
|
|
|
@@ -1076,14 +1310,14 @@ ${code}
|
|
|
1076
1310
|
(!this.bundle.hasAsset(resolvedAsset) ||
|
|
1077
1311
|
!this.shouldSkipAsset(resolvedAsset))
|
|
1078
1312
|
) {
|
|
1079
|
-
let hoisted = this.hoistedRequires.get(dep
|
|
1313
|
+
let hoisted = this.hoistedRequires.get(dep);
|
|
1080
1314
|
if (!hoisted) {
|
|
1081
1315
|
hoisted = new Map();
|
|
1082
|
-
this.hoistedRequires.set(dep
|
|
1316
|
+
this.hoistedRequires.set(dep, hoisted);
|
|
1083
1317
|
}
|
|
1084
1318
|
|
|
1085
1319
|
hoisted.set(
|
|
1086
|
-
resolvedAsset
|
|
1320
|
+
resolvedAsset,
|
|
1087
1321
|
`var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`,
|
|
1088
1322
|
);
|
|
1089
1323
|
}
|
|
@@ -1117,6 +1351,7 @@ ${code}
|
|
|
1117
1351
|
obj = `$${publicId}`;
|
|
1118
1352
|
} else {
|
|
1119
1353
|
obj = resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
|
|
1354
|
+
|
|
1120
1355
|
obj = replacements?.get(obj) || obj;
|
|
1121
1356
|
}
|
|
1122
1357
|
|
|
@@ -1124,7 +1359,7 @@ ${code}
|
|
|
1124
1359
|
// Resolve to the namespace object if requested or this is a CJS default interop reqiure.
|
|
1125
1360
|
if (
|
|
1126
1361
|
parentAsset === resolvedAsset &&
|
|
1127
|
-
this.wrappedAssets.has(resolvedAsset
|
|
1362
|
+
this.wrappedAssets.has(resolvedAsset)
|
|
1128
1363
|
) {
|
|
1129
1364
|
// Directly use module.exports for wrapped assets importing themselves.
|
|
1130
1365
|
return 'module.exports';
|
|
@@ -1167,7 +1402,7 @@ ${code}
|
|
|
1167
1402
|
return ['', 0];
|
|
1168
1403
|
}
|
|
1169
1404
|
|
|
1170
|
-
let hoisted = this.hoistedRequires.get(dep
|
|
1405
|
+
let hoisted = this.hoistedRequires.get(dep);
|
|
1171
1406
|
let res = '';
|
|
1172
1407
|
let lineCount = 0;
|
|
1173
1408
|
let isWrapped = this.isWrapped(resolved, parentAsset);
|
|
@@ -1179,7 +1414,7 @@ ${code}
|
|
|
1179
1414
|
if (
|
|
1180
1415
|
isWrapped &&
|
|
1181
1416
|
!dep.meta.shouldWrap &&
|
|
1182
|
-
(!hoisted || hoisted.keys().next().value !== resolved
|
|
1417
|
+
(!hoisted || hoisted.keys().next().value !== resolved) &&
|
|
1183
1418
|
!this.bundleGraph.isDependencySkipped(dep) &&
|
|
1184
1419
|
!this.shouldSkipAsset(resolved)
|
|
1185
1420
|
) {
|
|
@@ -1191,8 +1426,22 @@ ${code}
|
|
|
1191
1426
|
|
|
1192
1427
|
if (hoisted) {
|
|
1193
1428
|
this.needsPrelude = true;
|
|
1194
|
-
|
|
1195
|
-
|
|
1429
|
+
|
|
1430
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
1431
|
+
let hoistedValues = [...hoisted.values()].filter(
|
|
1432
|
+
(val) => !this.seenHoistedRequires.has(val),
|
|
1433
|
+
);
|
|
1434
|
+
|
|
1435
|
+
for (let val of hoistedValues) {
|
|
1436
|
+
this.seenHoistedRequires.add(val);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
res += '\n' + hoistedValues.join('\n');
|
|
1440
|
+
lineCount += hoisted.size;
|
|
1441
|
+
} else {
|
|
1442
|
+
res += '\n' + [...hoisted.values()].join('\n');
|
|
1443
|
+
lineCount += hoisted.size;
|
|
1444
|
+
}
|
|
1196
1445
|
}
|
|
1197
1446
|
|
|
1198
1447
|
return [res, lineCount];
|
|
@@ -1207,7 +1456,7 @@ ${code}
|
|
|
1207
1456
|
let prependLineCount = 0;
|
|
1208
1457
|
let append = '';
|
|
1209
1458
|
|
|
1210
|
-
let shouldWrap = this.wrappedAssets.has(asset
|
|
1459
|
+
let shouldWrap = this.wrappedAssets.has(asset);
|
|
1211
1460
|
let usedSymbols = nullthrows(this.bundleGraph.getUsedSymbols(asset));
|
|
1212
1461
|
let assetId = asset.meta.id;
|
|
1213
1462
|
invariant(typeof assetId === 'string');
|
|
@@ -1220,34 +1469,51 @@ ${code}
|
|
|
1220
1469
|
usedSymbols.has('default') &&
|
|
1221
1470
|
!asset.symbols.hasExportSymbol('__esModule');
|
|
1222
1471
|
|
|
1223
|
-
let usedNamespace
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
.
|
|
1234
|
-
.
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1472
|
+
let usedNamespace;
|
|
1473
|
+
if (
|
|
1474
|
+
getFeatureFlag('inlineConstOptimisationFix') &&
|
|
1475
|
+
asset.meta.isConstantModule
|
|
1476
|
+
) {
|
|
1477
|
+
// Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
|
|
1478
|
+
usedNamespace = this.bundleGraph
|
|
1479
|
+
.getIncomingDependencies(asset)
|
|
1480
|
+
.some(
|
|
1481
|
+
(dep) =>
|
|
1482
|
+
this.bundle.hasDependency(dep) &&
|
|
1483
|
+
nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
|
|
1484
|
+
);
|
|
1485
|
+
} else {
|
|
1486
|
+
usedNamespace =
|
|
1487
|
+
// If the asset has * in its used symbols, we might need the exports namespace.
|
|
1488
|
+
// The one case where this isn't true is in ESM library entries, where the only
|
|
1489
|
+
// dependency on * is the entry dependency. In this case, we will use ESM exports
|
|
1490
|
+
// instead of the namespace object.
|
|
1491
|
+
|
|
1492
|
+
(usedSymbols.has('*') &&
|
|
1493
|
+
(this.bundle.env.outputFormat !== 'esmodule' ||
|
|
1494
|
+
!this.bundle.env.isLibrary ||
|
|
1495
|
+
asset !== this.bundle.getMainEntry() ||
|
|
1496
|
+
this.bundleGraph
|
|
1497
|
+
.getIncomingDependencies(asset)
|
|
1498
|
+
.some(
|
|
1499
|
+
(dep) =>
|
|
1500
|
+
!dep.isEntry &&
|
|
1501
|
+
this.bundle.hasDependency(dep) &&
|
|
1502
|
+
nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
|
|
1503
|
+
))) ||
|
|
1504
|
+
// If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
|
|
1505
|
+
// we fallback on the namespace object.
|
|
1506
|
+
|
|
1507
|
+
(asset.symbols.hasExportSymbol('*') &&
|
|
1508
|
+
[...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
|
|
1509
|
+
// If the exports has this asset's namespace (e.g. ESM output from CJS input),
|
|
1510
|
+
// include the namespace object for the default export.
|
|
1511
|
+
this.exportedSymbols.has(`$${assetId}$exports`) ||
|
|
1512
|
+
// CommonJS library bundle entries always need a namespace.
|
|
1513
|
+
(this.bundle.env.isLibrary &&
|
|
1514
|
+
this.bundle.env.outputFormat === 'commonjs' &&
|
|
1515
|
+
asset === this.bundle.getMainEntry());
|
|
1516
|
+
}
|
|
1251
1517
|
|
|
1252
1518
|
// If the asset doesn't have static exports, should wrap, the namespace is used,
|
|
1253
1519
|
// or we need default interop, then we need to synthesize a namespace object for
|
|
@@ -1274,6 +1540,7 @@ ${code}
|
|
|
1274
1540
|
// Insert the __esModule interop flag for this module if it has a `default` export
|
|
1275
1541
|
// and the namespace symbol is used.
|
|
1276
1542
|
// TODO: only if required by CJS?
|
|
1543
|
+
|
|
1277
1544
|
if (asset.symbols.hasExportSymbol('default') && usedSymbols.has('*')) {
|
|
1278
1545
|
prepend += `\n$parcel$defineInteropFlag($${assetId}$exports);\n`;
|
|
1279
1546
|
prependLineCount += 2;
|
|
@@ -1337,6 +1604,7 @@ ${code}
|
|
|
1337
1604
|
let resolvedSymbol = this.getSymbolResolution(
|
|
1338
1605
|
asset,
|
|
1339
1606
|
resolved,
|
|
1607
|
+
|
|
1340
1608
|
symbol,
|
|
1341
1609
|
undefined,
|
|
1342
1610
|
replacements,
|
|
@@ -1388,28 +1656,39 @@ ${code}
|
|
|
1388
1656
|
// for the symbol so that when the value changes the object property also changes. This is
|
|
1389
1657
|
// required to simulate ESM live bindings. It's easier to do it this way rather than inserting
|
|
1390
1658
|
// additional assignments after each mutation of the original binding.
|
|
1391
|
-
|
|
1392
|
-
.
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1659
|
+
for (let exp of usedExports) {
|
|
1660
|
+
let resolved = this.getSymbolResolution(
|
|
1661
|
+
asset,
|
|
1662
|
+
asset,
|
|
1663
|
+
exp,
|
|
1664
|
+
undefined,
|
|
1665
|
+
replacements,
|
|
1666
|
+
);
|
|
1667
|
+
const meta = asset.symbols.get(exp)?.meta;
|
|
1668
|
+
if (
|
|
1669
|
+
getFeatureFlag('exportsRebindingOptimisation') &&
|
|
1670
|
+
(meta?.isStaticBindingSafe ||
|
|
1671
|
+
this.manualStaticBindingExports?.some((regex) =>
|
|
1672
|
+
regex.test(asset.filePath),
|
|
1673
|
+
))
|
|
1674
|
+
) {
|
|
1675
|
+
append += `$${assetId}$exports[${JSON.stringify(
|
|
1396
1676
|
exp,
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
);
|
|
1677
|
+
)}] = ${resolved};\n`;
|
|
1678
|
+
} else {
|
|
1400
1679
|
let get = this.buildFunctionExpression([], resolved);
|
|
1401
1680
|
let isEsmExport = !!asset.symbols.get(exp)?.meta?.isEsm;
|
|
1402
1681
|
let set =
|
|
1403
1682
|
!isEsmExport && asset.meta.hasCJSExports
|
|
1404
1683
|
? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`)
|
|
1405
1684
|
: '';
|
|
1406
|
-
|
|
1685
|
+
prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(
|
|
1407
1686
|
exp,
|
|
1408
|
-
)}, ${get}${set})
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1687
|
+
)}, ${get}${set});\n`;
|
|
1688
|
+
this.usedHelpers.add('$parcel$export');
|
|
1689
|
+
prependLineCount += 1 + usedExports.length;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1413
1692
|
}
|
|
1414
1693
|
}
|
|
1415
1694
|
|
|
@@ -1448,9 +1727,11 @@ ${code}
|
|
|
1448
1727
|
}
|
|
1449
1728
|
|
|
1450
1729
|
for (let helper of this.usedHelpers) {
|
|
1451
|
-
let currentHelper = helpers[helper];
|
|
1730
|
+
let currentHelper = (helpers as Record<string, any>)[helper];
|
|
1452
1731
|
if (typeof currentHelper === 'function') {
|
|
1453
|
-
currentHelper = helpers[helper](
|
|
1732
|
+
currentHelper = (helpers as Record<string, any>)[helper](
|
|
1733
|
+
this.bundle.env,
|
|
1734
|
+
);
|
|
1454
1735
|
}
|
|
1455
1736
|
res += currentHelper;
|
|
1456
1737
|
if (enableSourceMaps) {
|
|
@@ -1470,11 +1751,14 @@ ${code}
|
|
|
1470
1751
|
.some((g) => this.bundleGraph.isEntryBundleGroup(g)) ||
|
|
1471
1752
|
this.bundle.env.isIsolated() ||
|
|
1472
1753
|
this.bundle.bundleBehavior === 'isolated' ||
|
|
1754
|
+
this.bundle.bundleBehavior === 'inlineIsolated' ||
|
|
1473
1755
|
// Conditional deps may be loaded before entrypoints on the server
|
|
1474
1756
|
this.hasConditionalDependency();
|
|
1475
1757
|
|
|
1476
1758
|
if (mightBeFirstJS) {
|
|
1477
|
-
let preludeCode =
|
|
1759
|
+
let preludeCode = (
|
|
1760
|
+
getFeatureFlag('useNewPrelude') ? preludeNew : preludeOld
|
|
1761
|
+
)(this.parcelRequireName);
|
|
1478
1762
|
res += preludeCode;
|
|
1479
1763
|
if (enableSourceMaps) {
|
|
1480
1764
|
lines += countLines(preludeCode) - 1;
|
|
@@ -1498,7 +1782,11 @@ ${code}
|
|
|
1498
1782
|
}
|
|
1499
1783
|
|
|
1500
1784
|
// Add importScripts for sibling bundles in workers.
|
|
1501
|
-
if (
|
|
1785
|
+
if (
|
|
1786
|
+
this.bundle.env.isWorker() ||
|
|
1787
|
+
this.bundle.env.isTesseract() ||
|
|
1788
|
+
this.bundle.env.isWorklet()
|
|
1789
|
+
) {
|
|
1502
1790
|
let importScripts = '';
|
|
1503
1791
|
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
|
1504
1792
|
for (let b of bundles) {
|
|
@@ -1539,7 +1827,7 @@ ${code}
|
|
|
1539
1827
|
return (
|
|
1540
1828
|
asset.sideEffects === false &&
|
|
1541
1829
|
nullthrows(this.bundleGraph.getUsedSymbols(asset)).size == 0 &&
|
|
1542
|
-
!this.
|
|
1830
|
+
!this.isAssetReferencedInBundle(this.bundle, asset)
|
|
1543
1831
|
);
|
|
1544
1832
|
}
|
|
1545
1833
|
|