@atlaspack/core 2.29.2 → 2.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ import type {
9
9
  DevDepRequest,
10
10
  AtlaspackOptions,
11
11
  DevDepRequestRef,
12
+ DependencyNode,
12
13
  } from './types';
13
14
  import type {AtlaspackConfig} from './AtlaspackConfig';
14
15
  import type PluginOptions from './public/PluginOptions';
@@ -19,6 +20,7 @@ import assert from 'assert';
19
20
  import invariant from 'assert';
20
21
  import nullthrows from 'nullthrows';
21
22
  import {nodeFromAssetGroup} from './AssetGraph';
23
+ import type AssetGraph from './AssetGraph';
22
24
  import BundleGraph from './public/BundleGraph';
23
25
  import InternalBundleGraph, {bundleGraphEdgeTypes} from './BundleGraph';
24
26
  import {NamedBundle} from './public/Bundle';
@@ -33,6 +35,7 @@ import {toProjectPath, fromProjectPathRelative} from './projectPath';
33
35
  import {tracer, PluginTracer} from '@atlaspack/profiler';
34
36
  import {DefaultMap} from '@atlaspack/utils';
35
37
  import {fromEnvironmentId} from './EnvironmentManager';
38
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
36
39
 
37
40
  type RuntimeConnection = {
38
41
  bundle: InternalBundle;
@@ -152,6 +155,7 @@ export default async function applyRuntimes<TResult extends RequestResult>({
152
155
  env,
153
156
  runtimeAssetRequiringExecutionOnLoad,
154
157
  priority,
158
+ symbolData,
155
159
  } of runtimeAssets) {
156
160
  let sourceName = path.join(
157
161
  path.dirname(filePath),
@@ -170,6 +174,7 @@ export default async function applyRuntimes<TResult extends RequestResult>({
170
174
  // Runtime assets should be considered source, as they should be
171
175
  // e.g. compiled to run in the target environment
172
176
  isSource: true,
177
+ symbolData,
173
178
  };
174
179
 
175
180
  let connectionBundle = bundle;
@@ -276,6 +281,11 @@ export default async function applyRuntimes<TResult extends RequestResult>({
276
281
  let {assetGraph: runtimesAssetGraph, changedAssets} =
277
282
  await reconcileNewRuntimes(api, connections, optionsRef);
278
283
 
284
+ if (getFeatureFlag('skipRuntimeSymbolProp')) {
285
+ // Apply pre-computed symbol data from runtime assets to skip symbol propagation
286
+ applyRuntimeSymbolData(runtimesAssetGraph, connections);
287
+ }
288
+
279
289
  // Convert the runtime AssetGraph into a BundleGraph, this includes assigning
280
290
  // the assets their public ids
281
291
  let runtimesBundleGraph = InternalBundleGraph.fromAssetGraph(
@@ -398,6 +408,93 @@ export default async function applyRuntimes<TResult extends RequestResult>({
398
408
  return changedAssets;
399
409
  }
400
410
 
411
+ /**
412
+ * Apply pre-computed symbol data from runtime assets to the asset graph
413
+ * to avoid running symbol propagation on runtime code we control.
414
+ */
415
+ function applyRuntimeSymbolData(
416
+ assetGraph: AssetGraph,
417
+ connections: Array<RuntimeConnection>,
418
+ ) {
419
+ for (let {assetGroup} of connections) {
420
+ let assetGroupNode = nodeFromAssetGroup(assetGroup);
421
+ let assetGroupAssetNodeIds = assetGraph.getNodeIdsConnectedFrom(
422
+ assetGraph.getNodeIdByContentKey(assetGroupNode.id),
423
+ );
424
+
425
+ if (assetGroupAssetNodeIds.length !== 1) {
426
+ continue;
427
+ }
428
+
429
+ let runtimeAssetNodeId = assetGroupAssetNodeIds[0];
430
+ let runtimeAssetNode = assetGraph.getNode(runtimeAssetNodeId);
431
+ if (!runtimeAssetNode || runtimeAssetNode.type !== 'asset') {
432
+ continue;
433
+ }
434
+
435
+ let symbolData = assetGroup.symbolData;
436
+ if (!symbolData) {
437
+ // We completely skip symbol propagation for runtime assets, so symbolData
438
+ // is required
439
+ throw new Error('Runtime asset is missing symbol data');
440
+ }
441
+
442
+ if (symbolData.symbols) {
443
+ // Convert from SymbolData format to internal Asset.symbols format
444
+ let internalSymbols = new Map();
445
+ for (let [symbol, data] of symbolData.symbols) {
446
+ internalSymbols.set(symbol, {
447
+ local: data.local,
448
+ loc: data.loc || null,
449
+ meta: data.meta,
450
+ });
451
+ }
452
+ runtimeAssetNode.value.symbols = internalSymbols;
453
+ }
454
+
455
+ if (symbolData.dependencies && symbolData.dependencies.length > 0) {
456
+ let outgoingDeps = assetGraph
457
+ .getNodeIdsConnectedFrom(runtimeAssetNodeId)
458
+ .map((id) => assetGraph.getNode(id))
459
+ .filter((node) => node?.type === 'dependency')
460
+ .map((node) => node as DependencyNode);
461
+
462
+ for (let depSymbolData of symbolData.dependencies) {
463
+ let matchingDep = outgoingDeps.find(
464
+ (depNode) => depNode.value.specifier === depSymbolData.specifier,
465
+ );
466
+
467
+ if (matchingDep) {
468
+ if (depSymbolData.symbols) {
469
+ let internalDepSymbols = new Map();
470
+ for (let [symbol, data] of depSymbolData.symbols) {
471
+ internalDepSymbols.set(symbol, {
472
+ local: data.local,
473
+ loc: data.loc || null,
474
+ isWeak: data.isWeak,
475
+ meta: data.meta,
476
+ });
477
+ }
478
+ matchingDep.value.symbols = internalDepSymbols;
479
+ }
480
+
481
+ if (depSymbolData.usedSymbols) {
482
+ matchingDep.usedSymbolsDown = new Set(depSymbolData.usedSymbols);
483
+ // For runtime assets, usedSymbolsUp will be the same as usedSymbolsDown
484
+ // since we know exactly what we're using
485
+ let usedSymbolsUp = new Map();
486
+ for (let symbol of depSymbolData.usedSymbols) {
487
+ // Mark as resolved to external (null) since runtime deps are typically external
488
+ usedSymbolsUp.set(symbol, null);
489
+ }
490
+ matchingDep.usedSymbolsUp = usedSymbolsUp;
491
+ }
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
+
401
498
  function reconcileNewRuntimes<TResult extends RequestResult>(
402
499
  api: RunAPI<TResult>,
403
500
  connections: Array<RuntimeConnection>,
@@ -408,6 +505,7 @@ function reconcileNewRuntimes<TResult extends RequestResult>(
408
505
  name: 'Runtimes',
409
506
  assetGroups,
410
507
  optionsRef,
508
+ skipSymbolProp: getFeatureFlag('skipRuntimeSymbolProp'),
411
509
  });
412
510
 
413
511
  // rebuild the graph
@@ -43,6 +43,7 @@ export type AssetGraphRequestInput = {
43
43
  lazyIncludes?: RegExp[];
44
44
  lazyExcludes?: RegExp[];
45
45
  requestedAssetIds?: Set<string>;
46
+ skipSymbolProp?: boolean;
46
47
  };
47
48
 
48
49
  export type AssetGraphRequestResult = {
@@ -128,6 +129,7 @@ export class AssetGraphBuilder {
128
129
  isSingleChangeRebuild: boolean;
129
130
  assetGroupsWithRemovedParents: Set<NodeId>;
130
131
  previousSymbolPropagationErrors: Map<NodeId, Array<Diagnostic>>;
132
+ skipSymbolProp: boolean;
131
133
 
132
134
  constructor(
133
135
  {input, api, options}: RunInput,
@@ -167,6 +169,8 @@ export class AssetGraphBuilder {
167
169
  this.shouldBuildLazily = shouldBuildLazily ?? false;
168
170
  this.lazyIncludes = lazyIncludes ?? [];
169
171
  this.lazyExcludes = lazyExcludes ?? [];
172
+ this.skipSymbolProp = input.skipSymbolProp ?? false;
173
+
170
174
  if (getFeatureFlag('cachePerformanceImprovements')) {
171
175
  const key = hashString(
172
176
  `${ATLASPACK_VERSION}${name}${JSON.stringify(entries) ?? ''}${
@@ -298,41 +302,51 @@ export class AssetGraphBuilder {
298
302
  this.assetGraph,
299
303
  'AssetGraph_' + this.name + '_before_prop',
300
304
  );
301
- try {
302
- let errors = propagateSymbols({
303
- options: this.options,
304
- assetGraph: this.assetGraph,
305
- changedAssetsPropagation: this.changedAssetsPropagation,
306
- assetGroupsWithRemovedParents: this.assetGroupsWithRemovedParents,
307
- previousErrors: this.previousSymbolPropagationErrors,
308
- });
309
- this.changedAssetsPropagation.clear();
310
-
311
- if (errors.size > 0) {
312
- this.api.storeResult(
313
- {
314
- assetGraph: this.assetGraph,
315
- changedAssets: this.changedAssets,
316
- changedAssetsPropagation: this.changedAssetsPropagation,
317
- assetGroupsWithRemovedParents: this.assetGroupsWithRemovedParents,
318
- previousSymbolPropagationErrors: errors,
319
- assetRequests: [],
320
- },
321
- this.cacheKey,
322
- );
323
305
 
324
- // Just throw the first error. Since errors can bubble (e.g. reexporting a reexported symbol also fails),
325
- // determining which failing export is the root cause is nontrivial (because of circular dependencies).
326
- throw new ThrowableDiagnostic({
327
- diagnostic: [...errors.values()][0],
306
+ // Skip symbol propagation for runtime assets - they have pre-computed symbol data
307
+ if (this.skipSymbolProp) {
308
+ logger.verbose({
309
+ origin: '@atlaspack/core',
310
+ message: 'Skipping symbol propagation for runtime asset graph',
311
+ });
312
+ } else {
313
+ try {
314
+ let errors = propagateSymbols({
315
+ options: this.options,
316
+ assetGraph: this.assetGraph,
317
+ changedAssetsPropagation: this.changedAssetsPropagation,
318
+ assetGroupsWithRemovedParents: this.assetGroupsWithRemovedParents,
319
+ previousErrors: this.previousSymbolPropagationErrors,
328
320
  });
321
+ this.changedAssetsPropagation.clear();
322
+
323
+ if (errors.size > 0) {
324
+ this.api.storeResult(
325
+ {
326
+ assetGraph: this.assetGraph,
327
+ changedAssets: this.changedAssets,
328
+ changedAssetsPropagation: this.changedAssetsPropagation,
329
+ assetGroupsWithRemovedParents:
330
+ this.assetGroupsWithRemovedParents,
331
+ previousSymbolPropagationErrors: errors,
332
+ assetRequests: [],
333
+ },
334
+ this.cacheKey,
335
+ );
336
+
337
+ // Just throw the first error. Since errors can bubble (e.g. reexporting a reexported symbol also fails),
338
+ // determining which failing export is the root cause is nontrivial (because of circular dependencies).
339
+ throw new ThrowableDiagnostic({
340
+ diagnostic: [...errors.values()][0],
341
+ });
342
+ }
343
+ } catch (e: any) {
344
+ await dumpGraphToGraphViz(
345
+ this.assetGraph,
346
+ 'AssetGraph_' + this.name + '_failed',
347
+ );
348
+ throw e;
329
349
  }
330
- } catch (e: any) {
331
- await dumpGraphToGraphViz(
332
- this.assetGraph,
333
- 'AssetGraph_' + this.name + '_failed',
334
- );
335
- throw e;
336
350
  }
337
351
  }
338
352
  await dumpGraphToGraphViz(this.assetGraph, 'AssetGraph_' + this.name);
@@ -523,17 +523,19 @@ class BundlerRunner {
523
523
  ),
524
524
  );
525
525
 
526
- changedRuntimes = await applyRuntimes({
527
- bundleGraph: internalBundleGraph,
528
- api: this.api,
529
- config: this.config,
530
- options: this.options,
531
- optionsRef: this.optionsRef,
532
- pluginOptions: this.pluginOptions,
533
- previousDevDeps: this.previousDevDeps,
534
- devDepRequests: this.devDepRequests,
535
- configs: this.configs,
536
- });
526
+ changedRuntimes = await instrumentAsync('applyRuntimes', () =>
527
+ applyRuntimes({
528
+ bundleGraph: internalBundleGraph,
529
+ api: this.api,
530
+ config: this.config,
531
+ options: this.options,
532
+ optionsRef: this.optionsRef,
533
+ pluginOptions: this.pluginOptions,
534
+ previousDevDeps: this.previousDevDeps,
535
+ devDepRequests: this.devDepRequests,
536
+ configs: this.configs,
537
+ }),
538
+ );
537
539
 
538
540
  // Add dev deps for namers, AFTER running them to account for lazy require().
539
541
  for (let namer of namers) {
package/src/types.ts CHANGED
@@ -23,6 +23,7 @@ import type {
23
23
  HMROptions,
24
24
  DetailedReportOptions,
25
25
  Symbol,
26
+ SymbolData,
26
27
  } from '@atlaspack/types';
27
28
  import type {SharedReference} from '@atlaspack/workers';
28
29
  import type {FileSystem} from '@atlaspack/fs';
@@ -438,6 +439,7 @@ export type AssetRequestInput = {
438
439
  isURL?: boolean;
439
440
  query?: string | null | undefined;
440
441
  isSingleChangeRebuild?: boolean;
442
+ symbolData?: SymbolData;
441
443
  };
442
444
 
443
445
  export type AssetRequestResult = Array<Asset>;