@atlaspack/packager-js 2.14.5-canary.36 → 2.14.5-canary.361
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 +546 -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 +1396 -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 +301 -112
- 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} +476 -185
- 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,58 @@ 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
|
+
|
|
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
|
+
// STEP 2: Cache miss - try fast checks (~0.01ms)
|
|
428
|
+
let fastCheckResult = this.bundleGraph.isAssetReferencedFastCheck(
|
|
429
|
+
bundle,
|
|
430
|
+
asset,
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
if (fastCheckResult === true) {
|
|
434
|
+
// Fast check succeeded - asset is referenced
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// STEP 3: Need expensive computation (~20-2000ms)
|
|
439
|
+
|
|
440
|
+
// Compute and cache expensive results for this bundle
|
|
441
|
+
referencedAssets = this.bundleGraph.getReferencedAssets(bundle);
|
|
442
|
+
this.referencedAssetsCache.set(bundleId, referencedAssets);
|
|
443
|
+
|
|
444
|
+
return referencedAssets.has(asset);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async loadAssets() {
|
|
448
|
+
type QueueItem = [Asset, {code: string; map: Buffer | undefined | null}];
|
|
449
|
+
let queue = new PromiseQueue<QueueItem>({
|
|
450
|
+
maxConcurrent: 32,
|
|
451
|
+
});
|
|
452
|
+
|
|
360
453
|
this.bundle.traverseAssets((asset) => {
|
|
361
454
|
queue.add(async () => {
|
|
362
455
|
let [code, map] = await Promise.all([
|
|
363
456
|
asset.getCode(),
|
|
364
457
|
this.bundle.env.sourceMap ? asset.getMapBuffer() : null,
|
|
365
458
|
]);
|
|
366
|
-
|
|
459
|
+
|
|
460
|
+
return [asset, {code, map}];
|
|
367
461
|
});
|
|
368
462
|
|
|
369
463
|
if (
|
|
370
464
|
asset.meta.shouldWrap ||
|
|
371
465
|
this.bundle.env.sourceType === 'script' ||
|
|
372
|
-
this.
|
|
466
|
+
this.isAssetReferencedInBundle(this.bundle, asset) ||
|
|
373
467
|
this.bundleGraph
|
|
374
468
|
.getIncomingDependencies(asset)
|
|
375
469
|
.some((dep) => dep.meta.shouldWrap && dep.specifierType !== 'url')
|
|
@@ -381,52 +475,113 @@ export class ScopeHoistingPackager {
|
|
|
381
475
|
.getIncomingDependencies(asset)
|
|
382
476
|
.some((dep) => dep.priority === 'lazy')
|
|
383
477
|
) {
|
|
384
|
-
this.wrappedAssets.add(asset
|
|
385
|
-
|
|
478
|
+
this.wrappedAssets.add(asset);
|
|
479
|
+
} else if (
|
|
480
|
+
(getFeatureFlag('inlineConstOptimisationFix') ||
|
|
481
|
+
this.useBothScopeHoistingImprovements) &&
|
|
482
|
+
asset.meta.isConstantModule
|
|
483
|
+
) {
|
|
484
|
+
this.constantAssets.add(asset);
|
|
386
485
|
}
|
|
387
486
|
}
|
|
388
487
|
});
|
|
389
488
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
489
|
+
if (this.useBothScopeHoistingImprovements) {
|
|
490
|
+
// Tracks which assets have been assigned to a wrap group
|
|
491
|
+
let assignedAssets = new Set<Asset>();
|
|
492
|
+
|
|
493
|
+
// In V2 scope hoisting, we iterate from the main entry, rather than
|
|
494
|
+
// wrapping the entry assets
|
|
495
|
+
if (!getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
496
|
+
// Make all entry assets wrapped, to avoid any top level hoisting
|
|
497
|
+
for (let entryAsset of this.bundle.getEntryAssets()) {
|
|
498
|
+
if (!this.wrappedAssets.has(entryAsset)) {
|
|
499
|
+
this.wrappedAssets.add(entryAsset);
|
|
500
|
+
}
|
|
394
501
|
}
|
|
502
|
+
}
|
|
395
503
|
|
|
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);
|
|
504
|
+
// We need to make a new copy here so that we can add to the list and
|
|
505
|
+
// iterate the newly added items, without mutating the wrappedAssets set
|
|
506
|
+
let moduleGroupParents = [...this.wrappedAssets.values()];
|
|
507
|
+
|
|
508
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
509
|
+
// The main entry needs to be check to find assets that would have gone in
|
|
510
|
+
// the top level scope
|
|
511
|
+
let mainEntry = this.bundle.getMainEntry();
|
|
512
|
+
if (mainEntry && !this.wrappedAssets.has(mainEntry)) {
|
|
513
|
+
moduleGroupParents.unshift(mainEntry);
|
|
424
514
|
}
|
|
425
|
-
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
for (let moduleGroupParentAsset of moduleGroupParents) {
|
|
518
|
+
this.bundle.traverseAssets((asset, _, actions) => {
|
|
519
|
+
if (asset === moduleGroupParentAsset) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (this.wrappedAssets.has(asset)) {
|
|
524
|
+
actions.skipChildren();
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (
|
|
529
|
+
!asset.meta.isConstantModule &&
|
|
530
|
+
(assignedAssets.has(asset) || this.isReExported(asset))
|
|
531
|
+
) {
|
|
532
|
+
this.wrappedAssets.add(asset);
|
|
533
|
+
|
|
534
|
+
// This also needs to be added to the traversal so that we iterate
|
|
535
|
+
// it during this check.
|
|
536
|
+
moduleGroupParents.push(asset);
|
|
537
|
+
|
|
538
|
+
actions.skipChildren();
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
assignedAssets.add(asset);
|
|
543
|
+
}, moduleGroupParentAsset);
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
for (let wrappedAssetRoot of this.wrappedAssets) {
|
|
547
|
+
this.bundle.traverseAssets((asset, _, actions) => {
|
|
548
|
+
if (asset === wrappedAssetRoot) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (this.wrappedAssets.has(asset)) {
|
|
553
|
+
actions.skipChildren();
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (!asset.meta.isConstantModule) {
|
|
558
|
+
this.wrappedAssets.add(asset);
|
|
559
|
+
}
|
|
560
|
+
}, wrappedAssetRoot);
|
|
561
|
+
}
|
|
426
562
|
}
|
|
427
563
|
|
|
428
564
|
this.assetOutputs = new Map(await queue.run());
|
|
429
|
-
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
isReExported(asset: Asset): boolean {
|
|
568
|
+
let parentSymbols = this.bundleGraph
|
|
569
|
+
.getIncomingDependencies(asset)
|
|
570
|
+
.map((dep) => this.bundleGraph.getAssetWithDependency(dep))
|
|
571
|
+
.flatMap((parent) => {
|
|
572
|
+
if (parent == null) {
|
|
573
|
+
return [];
|
|
574
|
+
}
|
|
575
|
+
return this.bundleGraph.getExportedSymbols(parent, this.bundle);
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
let assetSymbols = this.bundleGraph.getExportedSymbols(asset, this.bundle);
|
|
579
|
+
|
|
580
|
+
return assetSymbols.some((assetSymbol) =>
|
|
581
|
+
parentSymbols.some(
|
|
582
|
+
(parentSymbol) => parentSymbol.symbol === assetSymbol.symbol,
|
|
583
|
+
),
|
|
584
|
+
);
|
|
430
585
|
}
|
|
431
586
|
|
|
432
587
|
buildExportedSymbols() {
|
|
@@ -439,7 +594,7 @@ export class ScopeHoistingPackager {
|
|
|
439
594
|
|
|
440
595
|
// TODO: handle ESM exports of wrapped entry assets...
|
|
441
596
|
let entry = this.bundle.getMainEntry();
|
|
442
|
-
if (entry && !this.wrappedAssets.has(entry
|
|
597
|
+
if (entry && !this.wrappedAssets.has(entry)) {
|
|
443
598
|
let hasNamespace = entry.symbols.hasExportSymbol('*');
|
|
444
599
|
|
|
445
600
|
for (let {
|
|
@@ -464,6 +619,7 @@ export class ScopeHoistingPackager {
|
|
|
464
619
|
symbols = [];
|
|
465
620
|
this.exportedSymbols.set(symbol, {
|
|
466
621
|
asset,
|
|
622
|
+
|
|
467
623
|
exportSymbol,
|
|
468
624
|
local: symbol,
|
|
469
625
|
exportAs: symbols,
|
|
@@ -519,20 +675,24 @@ export class ScopeHoistingPackager {
|
|
|
519
675
|
return `${obj}[${JSON.stringify(property)}]`;
|
|
520
676
|
}
|
|
521
677
|
|
|
522
|
-
visitAsset(asset: Asset): [string,
|
|
523
|
-
invariant(!this.seenAssets.has(asset
|
|
524
|
-
this.seenAssets.add(asset
|
|
678
|
+
visitAsset(asset: Asset): [string, SourceMap | null | undefined, number] {
|
|
679
|
+
invariant(!this.seenAssets.has(asset), 'Already visited asset');
|
|
680
|
+
this.seenAssets.add(asset);
|
|
525
681
|
|
|
526
|
-
let {code, map} = nullthrows(this.assetOutputs.get(asset
|
|
682
|
+
let {code, map} = nullthrows(this.assetOutputs.get(asset));
|
|
527
683
|
return this.buildAsset(asset, code, map);
|
|
528
684
|
}
|
|
529
685
|
|
|
686
|
+
getAssetFilePath(asset: Asset): string {
|
|
687
|
+
return path.relative(this.options.projectRoot, asset.filePath);
|
|
688
|
+
}
|
|
689
|
+
|
|
530
690
|
buildAsset(
|
|
531
691
|
asset: Asset,
|
|
532
692
|
code: string,
|
|
533
|
-
map
|
|
534
|
-
): [string,
|
|
535
|
-
let shouldWrap = this.wrappedAssets.has(asset
|
|
693
|
+
map?: Buffer | null,
|
|
694
|
+
): [string, SourceMap | null | undefined, number] {
|
|
695
|
+
let shouldWrap = this.wrappedAssets.has(asset);
|
|
536
696
|
let deps = this.bundleGraph.getDependencies(asset);
|
|
537
697
|
|
|
538
698
|
let sourceMap =
|
|
@@ -559,16 +719,29 @@ export class ScopeHoistingPackager {
|
|
|
559
719
|
continue;
|
|
560
720
|
}
|
|
561
721
|
|
|
562
|
-
if (
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
722
|
+
if (this.bundle.hasAsset(resolved) && !this.seenAssets.has(resolved)) {
|
|
723
|
+
if (
|
|
724
|
+
this.useBothScopeHoistingImprovements &&
|
|
725
|
+
this.wrappedAssets.has(resolved)
|
|
726
|
+
) {
|
|
727
|
+
if (this.wrappedAssets.has(asset)) {
|
|
728
|
+
// If both the asset and the dep are wrapped there's no need to
|
|
729
|
+
// drop a side-effect require. This is an extremely rare case.
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// When the dep is wrapped then we just need to drop a side effect
|
|
734
|
+
// require instead of inlining
|
|
735
|
+
depCode += `parcelRequire("${this.bundleGraph.getAssetPublicId(resolved)}");\n`;
|
|
736
|
+
lineCount += 1;
|
|
737
|
+
} else {
|
|
738
|
+
let [code, map, lines] = this.visitAsset(resolved);
|
|
739
|
+
depCode += code + '\n';
|
|
740
|
+
if (sourceMap && map) {
|
|
741
|
+
sourceMap.addSourceMap(map, lineCount);
|
|
742
|
+
}
|
|
743
|
+
lineCount += lines + 1;
|
|
570
744
|
}
|
|
571
|
-
lineCount += lines + 1;
|
|
572
745
|
}
|
|
573
746
|
}
|
|
574
747
|
|
|
@@ -602,7 +775,7 @@ export class ScopeHoistingPackager {
|
|
|
602
775
|
code += append;
|
|
603
776
|
|
|
604
777
|
let lineCount = 0;
|
|
605
|
-
let depContent = [];
|
|
778
|
+
let depContent: Array<[string, SourceMap | null | undefined, number]> = [];
|
|
606
779
|
if (depMap.size === 0 && replacements.size === 0) {
|
|
607
780
|
// If there are no dependencies or replacements, use a simple function to count the number of lines.
|
|
608
781
|
lineCount = countLines(code) - 1;
|
|
@@ -647,27 +820,68 @@ export class ScopeHoistingPackager {
|
|
|
647
820
|
// after the dependency is declared. This handles the case where the resulting asset
|
|
648
821
|
// is wrapped, but the dependency in this asset is not marked as wrapped. This means
|
|
649
822
|
// that it was imported/required at the top-level, so its side effects should run immediately.
|
|
650
|
-
let
|
|
651
|
-
|
|
652
|
-
dep,
|
|
653
|
-
resolved,
|
|
654
|
-
);
|
|
823
|
+
let res = '';
|
|
824
|
+
let lines = 0;
|
|
655
825
|
let map;
|
|
826
|
+
|
|
827
|
+
if (!getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
828
|
+
[res, lines] = this.getHoistedParcelRequires(
|
|
829
|
+
asset,
|
|
830
|
+
dep,
|
|
831
|
+
resolved,
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
|
|
656
835
|
if (
|
|
657
836
|
this.bundle.hasAsset(resolved) &&
|
|
658
|
-
!this.seenAssets.has(resolved
|
|
837
|
+
!this.seenAssets.has(resolved)
|
|
659
838
|
) {
|
|
660
839
|
// If this asset is wrapped, we need to hoist the code for the dependency
|
|
661
840
|
// outside our parcelRequire.register wrapper. This is safe because all
|
|
662
841
|
// assets referenced by this asset will also be wrapped. Otherwise, inline the
|
|
663
842
|
// asset content where the import statement was.
|
|
664
|
-
if (
|
|
665
|
-
|
|
843
|
+
if (this.useBothScopeHoistingImprovements) {
|
|
844
|
+
if (
|
|
845
|
+
!resolved.meta.isConstantModule &&
|
|
846
|
+
!this.wrappedAssets.has(resolved)
|
|
847
|
+
) {
|
|
848
|
+
let [depCode, depMap, depLines] =
|
|
849
|
+
this.visitAsset(resolved);
|
|
850
|
+
if (debugTools['asset-file-names-in-output']) {
|
|
851
|
+
let resolvedPath = this.getAssetFilePath(resolved);
|
|
852
|
+
res = outdent`
|
|
853
|
+
/* Scope hoisted asset: ${resolvedPath} */
|
|
854
|
+
${depCode}
|
|
855
|
+
/* End: ${resolvedPath} */
|
|
856
|
+
${res}
|
|
857
|
+
`;
|
|
858
|
+
lines += 3 + depLines;
|
|
859
|
+
} else {
|
|
860
|
+
res = depCode + '\n' + res;
|
|
861
|
+
lines += 1 + depLines;
|
|
862
|
+
}
|
|
863
|
+
map = depMap;
|
|
864
|
+
}
|
|
666
865
|
} else {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
866
|
+
if (shouldWrap) {
|
|
867
|
+
depContent.push(this.visitAsset(resolved));
|
|
868
|
+
} else {
|
|
869
|
+
let [depCode, depMap, depLines] =
|
|
870
|
+
this.visitAsset(resolved);
|
|
871
|
+
res = depCode + '\n' + res;
|
|
872
|
+
lines += 1 + depLines;
|
|
873
|
+
map = depMap;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
879
|
+
let [requiresCode, requiresLines] =
|
|
880
|
+
this.getHoistedParcelRequires(asset, dep, resolved);
|
|
881
|
+
|
|
882
|
+
if (requiresCode) {
|
|
883
|
+
res = requiresCode + '\n' + res;
|
|
884
|
+
lines += requiresLines + 1;
|
|
671
885
|
}
|
|
672
886
|
}
|
|
673
887
|
|
|
@@ -726,6 +940,11 @@ ${code}
|
|
|
726
940
|
|
|
727
941
|
lineCount += 2;
|
|
728
942
|
|
|
943
|
+
if (debugTools['asset-file-names-in-output']) {
|
|
944
|
+
code = `/* ${this.getAssetFilePath(asset)} */\n` + code;
|
|
945
|
+
lineCount += 1;
|
|
946
|
+
}
|
|
947
|
+
|
|
729
948
|
for (let [depCode, map, lines] of depContent) {
|
|
730
949
|
if (!depCode) continue;
|
|
731
950
|
code += depCode + '\n';
|
|
@@ -803,7 +1022,7 @@ ${code}
|
|
|
803
1022
|
referencedBundle &&
|
|
804
1023
|
referencedBundle.getMainEntry() === resolved &&
|
|
805
1024
|
referencedBundle.type === 'js' &&
|
|
806
|
-
!this.
|
|
1025
|
+
!this.isAssetReferencedInBundle(referencedBundle, resolved)
|
|
807
1026
|
) {
|
|
808
1027
|
this.addExternal(dep, replacements, referencedBundle);
|
|
809
1028
|
this.externalAssets.add(resolved);
|
|
@@ -848,7 +1067,7 @@ ${code}
|
|
|
848
1067
|
// If this asset is wrapped, we need to replace the exports namespace with `module.exports`,
|
|
849
1068
|
// which will be provided to us by the wrapper.
|
|
850
1069
|
if (
|
|
851
|
-
this.wrappedAssets.has(asset
|
|
1070
|
+
this.wrappedAssets.has(asset) ||
|
|
852
1071
|
(this.bundle.env.outputFormat === 'commonjs' &&
|
|
853
1072
|
asset === this.bundle.getMainEntry())
|
|
854
1073
|
) {
|
|
@@ -895,7 +1114,9 @@ ${code}
|
|
|
895
1114
|
|
|
896
1115
|
for (let [imported, {local}] of dep.symbols) {
|
|
897
1116
|
// If already imported, just add the already renamed variable to the mapping.
|
|
1117
|
+
|
|
898
1118
|
let renamed = external.get(imported);
|
|
1119
|
+
|
|
899
1120
|
if (renamed && local !== '*' && replacements) {
|
|
900
1121
|
replacements.set(local, renamed);
|
|
901
1122
|
continue;
|
|
@@ -908,6 +1129,7 @@ ${code}
|
|
|
908
1129
|
if (!renamed) {
|
|
909
1130
|
if (referencedBundle) {
|
|
910
1131
|
let entry = nullthrows(referencedBundle.getMainEntry());
|
|
1132
|
+
|
|
911
1133
|
renamed =
|
|
912
1134
|
entry.symbols.get('*')?.local ??
|
|
913
1135
|
`$${String(entry.meta.id)}$exports`;
|
|
@@ -922,6 +1144,7 @@ ${code}
|
|
|
922
1144
|
|
|
923
1145
|
if (local !== '*' && replacements) {
|
|
924
1146
|
let replacement;
|
|
1147
|
+
|
|
925
1148
|
if (imported === '*') {
|
|
926
1149
|
replacement = renamed;
|
|
927
1150
|
} else if (imported === 'default') {
|
|
@@ -946,10 +1169,12 @@ ${code}
|
|
|
946
1169
|
let property;
|
|
947
1170
|
if (referencedBundle) {
|
|
948
1171
|
let entry = nullthrows(referencedBundle.getMainEntry());
|
|
1172
|
+
|
|
949
1173
|
if (entry.symbols.hasExportSymbol('*')) {
|
|
950
1174
|
// If importing * and the referenced module has a * export (e.g. CJS), use default instead.
|
|
951
1175
|
// This mirrors the logic in buildExportedSymbols.
|
|
952
1176
|
property = imported;
|
|
1177
|
+
|
|
953
1178
|
imported =
|
|
954
1179
|
referencedBundle?.env.outputFormat === 'esmodule'
|
|
955
1180
|
? 'default'
|
|
@@ -957,6 +1182,7 @@ ${code}
|
|
|
957
1182
|
} else {
|
|
958
1183
|
if (imported === '*') {
|
|
959
1184
|
let exportedSymbols = this.bundleGraph.getExportedSymbols(entry);
|
|
1185
|
+
|
|
960
1186
|
if (local === '*') {
|
|
961
1187
|
// Re-export all symbols.
|
|
962
1188
|
for (let exported of exportedSymbols) {
|
|
@@ -967,11 +1193,10 @@ ${code}
|
|
|
967
1193
|
continue;
|
|
968
1194
|
}
|
|
969
1195
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
imported,
|
|
973
|
-
|
|
974
|
-
).symbol;
|
|
1196
|
+
|
|
1197
|
+
renamed =
|
|
1198
|
+
this.bundleGraph.getSymbolResolution(entry, imported, this.bundle)
|
|
1199
|
+
.symbol || undefined;
|
|
975
1200
|
}
|
|
976
1201
|
}
|
|
977
1202
|
|
|
@@ -993,8 +1218,10 @@ ${code}
|
|
|
993
1218
|
}
|
|
994
1219
|
|
|
995
1220
|
external.set(imported, renamed);
|
|
1221
|
+
|
|
996
1222
|
if (local !== '*' && replacements) {
|
|
997
1223
|
let replacement = renamed;
|
|
1224
|
+
|
|
998
1225
|
if (property === '*') {
|
|
999
1226
|
replacement = renamed;
|
|
1000
1227
|
} else if (property === 'default') {
|
|
@@ -1003,6 +1230,7 @@ ${code}
|
|
|
1003
1230
|
} else if (property) {
|
|
1004
1231
|
replacement = this.getPropertyAccess(renamed, property);
|
|
1005
1232
|
}
|
|
1233
|
+
|
|
1006
1234
|
replacements.set(local, replacement);
|
|
1007
1235
|
}
|
|
1008
1236
|
}
|
|
@@ -1026,7 +1254,7 @@ ${code}
|
|
|
1026
1254
|
}
|
|
1027
1255
|
return (
|
|
1028
1256
|
(!this.bundle.hasAsset(resolved) && !this.externalAssets.has(resolved)) ||
|
|
1029
|
-
(this.wrappedAssets.has(resolved
|
|
1257
|
+
(this.wrappedAssets.has(resolved) && resolved !== parentAsset)
|
|
1030
1258
|
);
|
|
1031
1259
|
}
|
|
1032
1260
|
|
|
@@ -1076,14 +1304,14 @@ ${code}
|
|
|
1076
1304
|
(!this.bundle.hasAsset(resolvedAsset) ||
|
|
1077
1305
|
!this.shouldSkipAsset(resolvedAsset))
|
|
1078
1306
|
) {
|
|
1079
|
-
let hoisted = this.hoistedRequires.get(dep
|
|
1307
|
+
let hoisted = this.hoistedRequires.get(dep);
|
|
1080
1308
|
if (!hoisted) {
|
|
1081
1309
|
hoisted = new Map();
|
|
1082
|
-
this.hoistedRequires.set(dep
|
|
1310
|
+
this.hoistedRequires.set(dep, hoisted);
|
|
1083
1311
|
}
|
|
1084
1312
|
|
|
1085
1313
|
hoisted.set(
|
|
1086
|
-
resolvedAsset
|
|
1314
|
+
resolvedAsset,
|
|
1087
1315
|
`var $${publicId} = parcelRequire(${JSON.stringify(publicId)});`,
|
|
1088
1316
|
);
|
|
1089
1317
|
}
|
|
@@ -1117,6 +1345,7 @@ ${code}
|
|
|
1117
1345
|
obj = `$${publicId}`;
|
|
1118
1346
|
} else {
|
|
1119
1347
|
obj = resolvedAsset.symbols.get('*')?.local || `$${assetId}$exports`;
|
|
1348
|
+
|
|
1120
1349
|
obj = replacements?.get(obj) || obj;
|
|
1121
1350
|
}
|
|
1122
1351
|
|
|
@@ -1124,7 +1353,7 @@ ${code}
|
|
|
1124
1353
|
// Resolve to the namespace object if requested or this is a CJS default interop reqiure.
|
|
1125
1354
|
if (
|
|
1126
1355
|
parentAsset === resolvedAsset &&
|
|
1127
|
-
this.wrappedAssets.has(resolvedAsset
|
|
1356
|
+
this.wrappedAssets.has(resolvedAsset)
|
|
1128
1357
|
) {
|
|
1129
1358
|
// Directly use module.exports for wrapped assets importing themselves.
|
|
1130
1359
|
return 'module.exports';
|
|
@@ -1152,7 +1381,16 @@ ${code}
|
|
|
1152
1381
|
return this.getPropertyAccess(obj, exportSymbol);
|
|
1153
1382
|
}
|
|
1154
1383
|
} else if (!symbol) {
|
|
1155
|
-
|
|
1384
|
+
let parentPath =
|
|
1385
|
+
path.relative(this.options.projectRoot, parentAsset.filePath) ||
|
|
1386
|
+
'<unknown>';
|
|
1387
|
+
let resolvedPath =
|
|
1388
|
+
path.relative(this.options.projectRoot, resolvedAsset.filePath) ||
|
|
1389
|
+
'<unknown>';
|
|
1390
|
+
invariant(
|
|
1391
|
+
false,
|
|
1392
|
+
`Asset was skipped or not found when packaging ${this.bundle.name}.\nSearching for exported symbol "${imported}" (resolved as "${exportSymbol}") in asset with id "${resolvedAsset.meta.id}" (public id: "${publicId}", path: "${resolvedPath}") from parent asset "${parentAsset.meta.id}" (path: "${parentPath}").`,
|
|
1393
|
+
);
|
|
1156
1394
|
} else {
|
|
1157
1395
|
return replacements?.get(symbol) || symbol;
|
|
1158
1396
|
}
|
|
@@ -1167,7 +1405,7 @@ ${code}
|
|
|
1167
1405
|
return ['', 0];
|
|
1168
1406
|
}
|
|
1169
1407
|
|
|
1170
|
-
let hoisted = this.hoistedRequires.get(dep
|
|
1408
|
+
let hoisted = this.hoistedRequires.get(dep);
|
|
1171
1409
|
let res = '';
|
|
1172
1410
|
let lineCount = 0;
|
|
1173
1411
|
let isWrapped = this.isWrapped(resolved, parentAsset);
|
|
@@ -1179,7 +1417,7 @@ ${code}
|
|
|
1179
1417
|
if (
|
|
1180
1418
|
isWrapped &&
|
|
1181
1419
|
!dep.meta.shouldWrap &&
|
|
1182
|
-
(!hoisted || hoisted.keys().next().value !== resolved
|
|
1420
|
+
(!hoisted || hoisted.keys().next().value !== resolved) &&
|
|
1183
1421
|
!this.bundleGraph.isDependencySkipped(dep) &&
|
|
1184
1422
|
!this.shouldSkipAsset(resolved)
|
|
1185
1423
|
) {
|
|
@@ -1191,8 +1429,22 @@ ${code}
|
|
|
1191
1429
|
|
|
1192
1430
|
if (hoisted) {
|
|
1193
1431
|
this.needsPrelude = true;
|
|
1194
|
-
|
|
1195
|
-
|
|
1432
|
+
|
|
1433
|
+
if (getFeatureFlag('applyScopeHoistingImprovementV2')) {
|
|
1434
|
+
let hoistedValues = [...hoisted.values()].filter(
|
|
1435
|
+
(val) => !this.seenHoistedRequires.has(val),
|
|
1436
|
+
);
|
|
1437
|
+
|
|
1438
|
+
for (let val of hoistedValues) {
|
|
1439
|
+
this.seenHoistedRequires.add(val);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
res += '\n' + hoistedValues.join('\n');
|
|
1443
|
+
lineCount += hoisted.size;
|
|
1444
|
+
} else {
|
|
1445
|
+
res += '\n' + [...hoisted.values()].join('\n');
|
|
1446
|
+
lineCount += hoisted.size;
|
|
1447
|
+
}
|
|
1196
1448
|
}
|
|
1197
1449
|
|
|
1198
1450
|
return [res, lineCount];
|
|
@@ -1207,7 +1459,7 @@ ${code}
|
|
|
1207
1459
|
let prependLineCount = 0;
|
|
1208
1460
|
let append = '';
|
|
1209
1461
|
|
|
1210
|
-
let shouldWrap = this.wrappedAssets.has(asset
|
|
1462
|
+
let shouldWrap = this.wrappedAssets.has(asset);
|
|
1211
1463
|
let usedSymbols = nullthrows(this.bundleGraph.getUsedSymbols(asset));
|
|
1212
1464
|
let assetId = asset.meta.id;
|
|
1213
1465
|
invariant(typeof assetId === 'string');
|
|
@@ -1220,34 +1472,51 @@ ${code}
|
|
|
1220
1472
|
usedSymbols.has('default') &&
|
|
1221
1473
|
!asset.symbols.hasExportSymbol('__esModule');
|
|
1222
1474
|
|
|
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
|
-
|
|
1475
|
+
let usedNamespace;
|
|
1476
|
+
if (
|
|
1477
|
+
getFeatureFlag('inlineConstOptimisationFix') &&
|
|
1478
|
+
asset.meta.isConstantModule
|
|
1479
|
+
) {
|
|
1480
|
+
// Only set usedNamespace if there is an incoming dependency in the current bundle that uses '*'
|
|
1481
|
+
usedNamespace = this.bundleGraph
|
|
1482
|
+
.getIncomingDependencies(asset)
|
|
1483
|
+
.some(
|
|
1484
|
+
(dep) =>
|
|
1485
|
+
this.bundle.hasDependency(dep) &&
|
|
1486
|
+
nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
|
|
1487
|
+
);
|
|
1488
|
+
} else {
|
|
1489
|
+
usedNamespace =
|
|
1490
|
+
// If the asset has * in its used symbols, we might need the exports namespace.
|
|
1491
|
+
// The one case where this isn't true is in ESM library entries, where the only
|
|
1492
|
+
// dependency on * is the entry dependency. In this case, we will use ESM exports
|
|
1493
|
+
// instead of the namespace object.
|
|
1494
|
+
|
|
1495
|
+
(usedSymbols.has('*') &&
|
|
1496
|
+
(this.bundle.env.outputFormat !== 'esmodule' ||
|
|
1497
|
+
!this.bundle.env.isLibrary ||
|
|
1498
|
+
asset !== this.bundle.getMainEntry() ||
|
|
1499
|
+
this.bundleGraph
|
|
1500
|
+
.getIncomingDependencies(asset)
|
|
1501
|
+
.some(
|
|
1502
|
+
(dep) =>
|
|
1503
|
+
!dep.isEntry &&
|
|
1504
|
+
this.bundle.hasDependency(dep) &&
|
|
1505
|
+
nullthrows(this.bundleGraph.getUsedSymbols(dep)).has('*'),
|
|
1506
|
+
))) ||
|
|
1507
|
+
// If a symbol is imported (used) from a CJS asset but isn't listed in the symbols,
|
|
1508
|
+
// we fallback on the namespace object.
|
|
1509
|
+
|
|
1510
|
+
(asset.symbols.hasExportSymbol('*') &&
|
|
1511
|
+
[...usedSymbols].some((s) => !asset.symbols.hasExportSymbol(s))) ||
|
|
1512
|
+
// If the exports has this asset's namespace (e.g. ESM output from CJS input),
|
|
1513
|
+
// include the namespace object for the default export.
|
|
1514
|
+
this.exportedSymbols.has(`$${assetId}$exports`) ||
|
|
1515
|
+
// CommonJS library bundle entries always need a namespace.
|
|
1516
|
+
(this.bundle.env.isLibrary &&
|
|
1517
|
+
this.bundle.env.outputFormat === 'commonjs' &&
|
|
1518
|
+
asset === this.bundle.getMainEntry());
|
|
1519
|
+
}
|
|
1251
1520
|
|
|
1252
1521
|
// If the asset doesn't have static exports, should wrap, the namespace is used,
|
|
1253
1522
|
// or we need default interop, then we need to synthesize a namespace object for
|
|
@@ -1274,6 +1543,7 @@ ${code}
|
|
|
1274
1543
|
// Insert the __esModule interop flag for this module if it has a `default` export
|
|
1275
1544
|
// and the namespace symbol is used.
|
|
1276
1545
|
// TODO: only if required by CJS?
|
|
1546
|
+
|
|
1277
1547
|
if (asset.symbols.hasExportSymbol('default') && usedSymbols.has('*')) {
|
|
1278
1548
|
prepend += `\n$parcel$defineInteropFlag($${assetId}$exports);\n`;
|
|
1279
1549
|
prependLineCount += 2;
|
|
@@ -1337,6 +1607,7 @@ ${code}
|
|
|
1337
1607
|
let resolvedSymbol = this.getSymbolResolution(
|
|
1338
1608
|
asset,
|
|
1339
1609
|
resolved,
|
|
1610
|
+
|
|
1340
1611
|
symbol,
|
|
1341
1612
|
undefined,
|
|
1342
1613
|
replacements,
|
|
@@ -1388,28 +1659,39 @@ ${code}
|
|
|
1388
1659
|
// for the symbol so that when the value changes the object property also changes. This is
|
|
1389
1660
|
// required to simulate ESM live bindings. It's easier to do it this way rather than inserting
|
|
1390
1661
|
// additional assignments after each mutation of the original binding.
|
|
1391
|
-
|
|
1392
|
-
.
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1662
|
+
for (let exp of usedExports) {
|
|
1663
|
+
let resolved = this.getSymbolResolution(
|
|
1664
|
+
asset,
|
|
1665
|
+
asset,
|
|
1666
|
+
exp,
|
|
1667
|
+
undefined,
|
|
1668
|
+
replacements,
|
|
1669
|
+
);
|
|
1670
|
+
const meta = asset.symbols.get(exp)?.meta;
|
|
1671
|
+
if (
|
|
1672
|
+
getFeatureFlag('exportsRebindingOptimisation') &&
|
|
1673
|
+
(meta?.isStaticBindingSafe ||
|
|
1674
|
+
this.manualStaticBindingExports?.some((regex) =>
|
|
1675
|
+
regex.test(asset.filePath),
|
|
1676
|
+
))
|
|
1677
|
+
) {
|
|
1678
|
+
append += `$${assetId}$exports[${JSON.stringify(
|
|
1396
1679
|
exp,
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
);
|
|
1680
|
+
)}] = ${resolved};\n`;
|
|
1681
|
+
} else {
|
|
1400
1682
|
let get = this.buildFunctionExpression([], resolved);
|
|
1401
1683
|
let isEsmExport = !!asset.symbols.get(exp)?.meta?.isEsm;
|
|
1402
1684
|
let set =
|
|
1403
1685
|
!isEsmExport && asset.meta.hasCJSExports
|
|
1404
1686
|
? ', ' + this.buildFunctionExpression(['v'], `${resolved} = v`)
|
|
1405
1687
|
: '';
|
|
1406
|
-
|
|
1688
|
+
prepend += `$parcel$export($${assetId}$exports, ${JSON.stringify(
|
|
1407
1689
|
exp,
|
|
1408
|
-
)}, ${get}${set})
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1690
|
+
)}, ${get}${set});\n`;
|
|
1691
|
+
this.usedHelpers.add('$parcel$export');
|
|
1692
|
+
prependLineCount += 1 + usedExports.length;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1413
1695
|
}
|
|
1414
1696
|
}
|
|
1415
1697
|
|
|
@@ -1448,9 +1730,11 @@ ${code}
|
|
|
1448
1730
|
}
|
|
1449
1731
|
|
|
1450
1732
|
for (let helper of this.usedHelpers) {
|
|
1451
|
-
let currentHelper = helpers[helper];
|
|
1733
|
+
let currentHelper = (helpers as Record<string, any>)[helper];
|
|
1452
1734
|
if (typeof currentHelper === 'function') {
|
|
1453
|
-
currentHelper = helpers[helper](
|
|
1735
|
+
currentHelper = (helpers as Record<string, any>)[helper](
|
|
1736
|
+
this.bundle.env,
|
|
1737
|
+
);
|
|
1454
1738
|
}
|
|
1455
1739
|
res += currentHelper;
|
|
1456
1740
|
if (enableSourceMaps) {
|
|
@@ -1470,11 +1754,14 @@ ${code}
|
|
|
1470
1754
|
.some((g) => this.bundleGraph.isEntryBundleGroup(g)) ||
|
|
1471
1755
|
this.bundle.env.isIsolated() ||
|
|
1472
1756
|
this.bundle.bundleBehavior === 'isolated' ||
|
|
1757
|
+
this.bundle.bundleBehavior === 'inlineIsolated' ||
|
|
1473
1758
|
// Conditional deps may be loaded before entrypoints on the server
|
|
1474
1759
|
this.hasConditionalDependency();
|
|
1475
1760
|
|
|
1476
1761
|
if (mightBeFirstJS) {
|
|
1477
|
-
let preludeCode =
|
|
1762
|
+
let preludeCode = (
|
|
1763
|
+
getFeatureFlag('useNewPrelude') ? preludeNew : preludeOld
|
|
1764
|
+
)(this.parcelRequireName);
|
|
1478
1765
|
res += preludeCode;
|
|
1479
1766
|
if (enableSourceMaps) {
|
|
1480
1767
|
lines += countLines(preludeCode) - 1;
|
|
@@ -1498,7 +1785,11 @@ ${code}
|
|
|
1498
1785
|
}
|
|
1499
1786
|
|
|
1500
1787
|
// Add importScripts for sibling bundles in workers.
|
|
1501
|
-
if (
|
|
1788
|
+
if (
|
|
1789
|
+
this.bundle.env.isWorker() ||
|
|
1790
|
+
this.bundle.env.isTesseract() ||
|
|
1791
|
+
this.bundle.env.isWorklet()
|
|
1792
|
+
) {
|
|
1502
1793
|
let importScripts = '';
|
|
1503
1794
|
let bundles = this.bundleGraph.getReferencedBundles(this.bundle);
|
|
1504
1795
|
for (let b of bundles) {
|
|
@@ -1539,7 +1830,7 @@ ${code}
|
|
|
1539
1830
|
return (
|
|
1540
1831
|
asset.sideEffects === false &&
|
|
1541
1832
|
nullthrows(this.bundleGraph.getUsedSymbols(asset)).size == 0 &&
|
|
1542
|
-
!this.
|
|
1833
|
+
!this.isAssetReferencedInBundle(this.bundle, asset)
|
|
1543
1834
|
);
|
|
1544
1835
|
}
|
|
1545
1836
|
|