@atlaspack/core 2.31.2 → 2.32.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.
@@ -46,6 +46,7 @@ import {ISOLATED_ENVS} from './public/Environment';
46
46
  import {fromProjectPath, fromProjectPathRelative} from './projectPath';
47
47
  import {HASH_REF_PREFIX} from './constants';
48
48
  import {getFeatureFlag} from '@atlaspack/feature-flags';
49
+ import logger from '@atlaspack/logger';
49
50
  import {fromEnvironmentId} from './EnvironmentManager';
50
51
  import type {EnvironmentRef} from './EnvironmentManager';
51
52
 
@@ -571,6 +572,76 @@ export default class BundleGraph {
571
572
  });
572
573
  }
573
574
 
575
+ /**
576
+ * Serialize the bundle graph for efficient transfer to native Rust code.
577
+ * Returns a JSON string of nodes and an array of edges.
578
+ */
579
+ serializeForNative(): {
580
+ nodesJson: string;
581
+ edges: [number, number, BundleGraphEdgeType][];
582
+ } {
583
+ const start = performance.now();
584
+
585
+ const nodes = this._graph.nodes as BundleGraphNode[];
586
+ const edges: [number, number, BundleGraphEdgeType][] = [];
587
+
588
+ const edgeIterator = this._graph.getAllEdges();
589
+ let next = edgeIterator.next();
590
+ while (!next.done) {
591
+ const edge = next.value;
592
+ edges.push([edge.from, edge.to, edge.type]);
593
+ next = edgeIterator.next();
594
+ }
595
+
596
+ // Optimize nodes by omitting null/undefined values to reduce JSON size
597
+ const optimizedNodes = nodes.map((node) => this._omitNulls(node));
598
+ const nodesJson = JSON.stringify(optimizedNodes);
599
+
600
+ const duration = performance.now() - start;
601
+ const sizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
602
+ logger.verbose({
603
+ origin: '@atlaspack/core',
604
+ message: `serializeForNative: ${duration.toFixed(1)}ms, ${sizeMB}MB JSON, ${nodes.length} nodes, ${edges.length} edges`,
605
+ });
606
+
607
+ return {nodesJson, edges};
608
+ }
609
+
610
+ /**
611
+ * Remove null and undefined values from an object to reduce JSON size.
612
+ * Preserves false, 0, empty strings, and arrays.
613
+ */
614
+ private _omitNulls(obj: unknown): unknown {
615
+ if (obj === null || obj === undefined) return obj;
616
+ if (typeof obj !== 'object') return obj;
617
+ if (Array.isArray(obj)) {
618
+ return obj.map((item) => this._omitNulls(item));
619
+ }
620
+
621
+ const result: Record<string, unknown> = {};
622
+ for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
623
+ if (value === null || value === undefined) {
624
+ continue;
625
+ }
626
+ if (
627
+ typeof value === 'object' &&
628
+ !Array.isArray(value) &&
629
+ Object.keys(value as object).length === 0
630
+ ) {
631
+ continue;
632
+ }
633
+ if (typeof value === 'object') {
634
+ const processed = this._omitNulls(value);
635
+ if (processed !== undefined) {
636
+ result[key] = processed;
637
+ }
638
+ } else {
639
+ result[key] = value;
640
+ }
641
+ }
642
+ return result;
643
+ }
644
+
574
645
  createBundle(
575
646
  opts:
576
647
  | {
@@ -3,6 +3,8 @@ import {
3
3
  atlaspackNapiBuildAssetGraph,
4
4
  atlaspackNapiRespondToFsEvents,
5
5
  atlaspackNapiCompleteSession,
6
+ atlaspackNapiLoadBundleGraph,
7
+ atlaspackNapiPackage,
6
8
  AtlaspackNapi,
7
9
  Lmdb,
8
10
  AtlaspackNapiOptions,
@@ -12,6 +14,8 @@ import {NapiWorkerPool} from './NapiWorkerPool';
12
14
  import ThrowableDiagnostic from '@atlaspack/diagnostic';
13
15
  import type {Event} from '@parcel/watcher';
14
16
  import type {NapiWorkerPool as INapiWorkerPool} from '@atlaspack/types';
17
+ import invariant from 'assert';
18
+ import type BundleGraph from '../BundleGraph';
15
19
 
16
20
  export type AtlaspackV3Options = {
17
21
  fs?: AtlaspackNapiOptions['fs'];
@@ -97,6 +101,20 @@ export class AtlaspackV3 {
97
101
  return atlaspackNapiBuildAssetGraph(this._atlaspack_napi) as Promise<any>;
98
102
  }
99
103
 
104
+ loadBundleGraph(bundleGraph: BundleGraph): Promise<void> {
105
+ const {nodesJson, edges} = bundleGraph.serializeForNative();
106
+
107
+ return atlaspackNapiLoadBundleGraph(
108
+ this._atlaspack_napi,
109
+ nodesJson,
110
+ edges,
111
+ ) as Promise<void>;
112
+ }
113
+
114
+ package(): Promise<any> {
115
+ return atlaspackNapiPackage(this._atlaspack_napi) as Promise<any>;
116
+ }
117
+
100
118
  async respondToFsEvents(events: Array<Event>): Promise<boolean> {
101
119
  // @ts-expect-error TS2488
102
120
  let [needsRebuild, error] = await atlaspackNapiRespondToFsEvents(
@@ -20,6 +20,9 @@ import {assetFromValue} from '../public/Asset';
20
20
 
21
21
  import {tracer} from '@atlaspack/profiler';
22
22
  import {requestTypes} from '../RequestTracker';
23
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
24
+ import {fromEnvironmentId} from '../EnvironmentManager';
25
+ import invariant from 'assert';
23
26
 
24
27
  type AtlaspackBuildRequestInput = {
25
28
  optionsRef: SharedReference;
@@ -83,6 +86,26 @@ async function run({
83
86
  (options.shouldBuildLazily && requestedAssetIds.size > 0),
84
87
  });
85
88
 
89
+ if (
90
+ getFeatureFlag('nativePackager') &&
91
+ getFeatureFlag('nativePackagerSSRDev') &&
92
+ rustAtlaspack
93
+ ) {
94
+ let hasSupportedTarget = false;
95
+ bundleGraph.traverseBundles((bundle, ctx, actions) => {
96
+ if (
97
+ fromEnvironmentId(bundle.env).context === 'tesseract' &&
98
+ bundle.type === 'js'
99
+ ) {
100
+ hasSupportedTarget = true;
101
+ actions.stop();
102
+ }
103
+ });
104
+ if (hasSupportedTarget) {
105
+ await rustAtlaspack.loadBundleGraph(bundleGraph);
106
+ }
107
+ }
108
+
86
109
  // @ts-expect-error TS2345
87
110
  dumpGraphToGraphViz(bundleGraph._graph, 'BundleGraph', bundleGraphEdgeTypes);
88
111
 
@@ -141,9 +141,10 @@ export default function createBundleGraphRequest(
141
141
  let {optionsRef, requestedAssetIds, signal} = input.input;
142
142
  let measurement = tracer.createMeasurement('building');
143
143
 
144
- let createAssetGraphRequest = input.rustAtlaspack
145
- ? createAssetGraphRequestRust(input.rustAtlaspack)
146
- : createAssetGraphRequestJS;
144
+ let createAssetGraphRequest =
145
+ getFeatureFlag('atlaspackV3') && input.rustAtlaspack
146
+ ? createAssetGraphRequestRust(input.rustAtlaspack)
147
+ : createAssetGraphRequestJS;
147
148
 
148
149
  let request = createAssetGraphRequest({
149
150
  name: 'Main',
@@ -13,6 +13,8 @@ import nullthrows from 'nullthrows';
13
13
  import {runConfigRequest} from './ConfigRequest';
14
14
  import {getDevDepRequests, runDevDepRequest} from './DevDepRequest';
15
15
  import createAtlaspackConfigRequest from './AtlaspackConfigRequest';
16
+ import {fromEnvironmentId} from '../EnvironmentManager';
17
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
16
18
 
17
19
  type PackageRequestInput = {
18
20
  bundleGraph: BundleGraph;
@@ -46,8 +48,9 @@ export function createPackageRequest(
46
48
  };
47
49
  }
48
50
 
49
- async function run({input, api, farm}: RunInput<BundleInfo>) {
51
+ async function run({input, api, farm, rustAtlaspack}: RunInput<BundleInfo>) {
50
52
  let {bundleGraphReference, optionsRef, bundle, useMainThread} = input;
53
+
51
54
  let runPackage = farm.createHandle('runPackage', useMainThread);
52
55
 
53
56
  let start = Date.now();
@@ -58,6 +61,17 @@ async function run({input, api, farm}: RunInput<BundleInfo>) {
58
61
  ),
59
62
  );
60
63
 
64
+ if (
65
+ getFeatureFlag('nativePackager') &&
66
+ getFeatureFlag('nativePackagerSSRDev') &&
67
+ rustAtlaspack &&
68
+ fromEnvironmentId(bundle.env).context === 'tesseract' &&
69
+ bundle.type === 'js'
70
+ ) {
71
+ // Once this actually does something, the code below will be in an `else` block (i.e. we'll only run one or the other)
72
+ await rustAtlaspack.package();
73
+ }
74
+
61
75
  let {devDepRequests, configRequests, bundleInfo, invalidations} =
62
76
  (await runPackage({
63
77
  bundle,
@@ -181,7 +181,8 @@ export default async function resolveOptions(
181
181
  return initialOptions.cache;
182
182
  }
183
183
 
184
- const needsRustLmdbCache = getFeatureFlag('atlaspackV3');
184
+ const needsRustLmdbCache =
185
+ getFeatureFlag('atlaspackV3') || getFeatureFlag('nativePackager');
185
186
 
186
187
  if (!getFeatureFlag('cachePerformanceImprovements')) {
187
188
  if (!needsRustLmdbCache && !(outputFS instanceof NodeFS)) {