@atlaspack/core 2.31.3 → 2.32.1

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 CHANGED
@@ -1,5 +1,57 @@
1
1
  # @atlaspack/core
2
2
 
3
+ ## 2.32.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#988](https://github.com/atlassian-labs/atlaspack/pull/988) [`a631dcd`](https://github.com/atlassian-labs/atlaspack/commit/a631dcd961112db072b0f8de0831efd178f355a7) Thanks [@marcins](https://github.com/marcins)! - Implement a basic package() method for the native packager
8
+
9
+ - [#990](https://github.com/atlassian-labs/atlaspack/pull/990) [`5755a11`](https://github.com/atlassian-labs/atlaspack/commit/5755a114903bbf660e2ada3ae2e7ff6ceac7565b) Thanks [@vykimnguyen](https://github.com/vykimnguyen)! - changes conditional bundleGraphEdgeType value
10
+
11
+ - [#987](https://github.com/atlassian-labs/atlaspack/pull/987) [`fcaf517`](https://github.com/atlassian-labs/atlaspack/commit/fcaf517010d15c9300393bcad3f9b465689d9d16) Thanks [@vykimnguyen](https://github.com/vykimnguyen)! - add get_bundle_assets
12
+
13
+ - Updated dependencies [[`a631dcd`](https://github.com/atlassian-labs/atlaspack/commit/a631dcd961112db072b0f8de0831efd178f355a7), [`e9dce31`](https://github.com/atlassian-labs/atlaspack/commit/e9dce3168a8e6727a994bf2a6ac6041eb29f6027), [`59e1345`](https://github.com/atlassian-labs/atlaspack/commit/59e1345f84f43e0632d434ab42c06bf748241985), [`783118c`](https://github.com/atlassian-labs/atlaspack/commit/783118c772f45a0cf6a3b6b447fb9a0e225b25a6), [`fcaf517`](https://github.com/atlassian-labs/atlaspack/commit/fcaf517010d15c9300393bcad3f9b465689d9d16)]:
14
+ - @atlaspack/rust@3.21.0
15
+ - @atlaspack/cache@3.2.46
16
+ - @atlaspack/fs@2.15.46
17
+ - @atlaspack/logger@2.14.43
18
+ - @atlaspack/source-map@3.2.6
19
+ - @atlaspack/utils@3.3.3
20
+ - @atlaspack/package-manager@2.14.51
21
+ - @atlaspack/profiler@2.15.12
22
+ - @atlaspack/workers@2.14.51
23
+ - @atlaspack/types@2.15.41
24
+ - @atlaspack/graph@3.6.13
25
+ - @atlaspack/plugin@2.14.51
26
+
27
+ ## 2.32.0
28
+
29
+ ### Minor Changes
30
+
31
+ - [#976](https://github.com/atlassian-labs/atlaspack/pull/976) [`e8ea59b`](https://github.com/atlassian-labs/atlaspack/commit/e8ea59beabb4b4fef647dc9ebea3519b6d56d7b5) Thanks [@marcins](https://github.com/marcins)! - Initial implementation of loadBundleGraph to deserialise JS -> Rust BundleGraph.
32
+
33
+ - [#970](https://github.com/atlassian-labs/atlaspack/pull/970) [`8826fd0`](https://github.com/atlassian-labs/atlaspack/commit/8826fd02c29c9c67cf0c80da41f424257fbdef93) Thanks [@marcins](https://github.com/marcins)! - Add initial plumbing for native packaging to core and Atlaspack V3 code
34
+
35
+ ### Patch Changes
36
+
37
+ - [#984](https://github.com/atlassian-labs/atlaspack/pull/984) [`dbcaabb`](https://github.com/atlassian-labs/atlaspack/commit/dbcaabbf15d4fbc8ecd9c0be58cf7b2317eebfc4) Thanks [@marcins](https://github.com/marcins)! - Serialise to JSON on the JS side before sending bundle graph nodes to Rust for performance.
38
+
39
+ - Updated dependencies [[`e8ea59b`](https://github.com/atlassian-labs/atlaspack/commit/e8ea59beabb4b4fef647dc9ebea3519b6d56d7b5), [`3753cb1`](https://github.com/atlassian-labs/atlaspack/commit/3753cb1bf9155eaf3a1a8f952886864682738647), [`8826fd0`](https://github.com/atlassian-labs/atlaspack/commit/8826fd02c29c9c67cf0c80da41f424257fbdef93), [`225683f`](https://github.com/atlassian-labs/atlaspack/commit/225683f7c59355da53b7004d2b8596701ce3af41), [`43adda0`](https://github.com/atlassian-labs/atlaspack/commit/43adda06bf3b6a404b54f8ba2a3b810d92e61d75), [`dbcaabb`](https://github.com/atlassian-labs/atlaspack/commit/dbcaabbf15d4fbc8ecd9c0be58cf7b2317eebfc4)]:
40
+ - @atlaspack/rust@3.20.0
41
+ - @atlaspack/feature-flags@2.28.0
42
+ - @atlaspack/cache@3.2.45
43
+ - @atlaspack/fs@2.15.45
44
+ - @atlaspack/logger@2.14.42
45
+ - @atlaspack/source-map@3.2.5
46
+ - @atlaspack/utils@3.3.2
47
+ - @atlaspack/build-cache@2.13.9
48
+ - @atlaspack/graph@3.6.12
49
+ - @atlaspack/package-manager@2.14.50
50
+ - @atlaspack/profiler@2.15.11
51
+ - @atlaspack/workers@2.14.50
52
+ - @atlaspack/plugin@2.14.50
53
+ - @atlaspack/types@2.15.40
54
+
3
55
  ## 2.31.3
4
56
 
5
57
  ### Patch Changes
package/dist/Atlaspack.js CHANGED
@@ -157,7 +157,8 @@ class Atlaspack {
157
157
  });
158
158
  __classPrivateFieldSet(this, _Atlaspack_resolvedOptions, resolvedOptions, "f");
159
159
  let rustAtlaspack;
160
- if (resolvedOptions.featureFlags.atlaspackV3) {
160
+ if (resolvedOptions.featureFlags.atlaspackV3 ||
161
+ resolvedOptions.featureFlags.nativePackager) {
161
162
  // eslint-disable-next-line no-unused-vars
162
163
  let { entries, inputFS, outputFS, ...options } = __classPrivateFieldGet(this, _Atlaspack_initialOptions, "f");
163
164
  if (!(resolvedOptions.cache instanceof cache_1.LMDBLiteCache)) {
@@ -487,7 +488,7 @@ class Atlaspack {
487
488
  message: `File watch event emitted with ${events.length} events. Sample event: [${events[0]?.type}] ${events[0]?.path}`,
488
489
  });
489
490
  let nativeInvalid = false;
490
- if (this.rustAtlaspack) {
491
+ if ((0, feature_flags_1.getFeatureFlag)('atlaspackV3') && this.rustAtlaspack) {
491
492
  nativeInvalid = await this.rustAtlaspack.respondToFsEvents(events);
492
493
  }
493
494
  let { didInvalidate: isInvalid } = await __classPrivateFieldGet(this, _Atlaspack_requestTracker, "f").respondToFSEvents(events, Number.POSITIVE_INFINITY);
@@ -555,7 +556,7 @@ class Atlaspack {
555
556
  requestedAssetIds: __classPrivateFieldGet(this, _Atlaspack_requestedAssetIds, "f"),
556
557
  };
557
558
  const start = Date.now();
558
- const result = await __classPrivateFieldGet(this, _Atlaspack_requestTracker, "f").runRequest(this.rustAtlaspack != null
559
+ const result = await __classPrivateFieldGet(this, _Atlaspack_requestTracker, "f").runRequest((0, feature_flags_1.getFeatureFlag)('atlaspackV3') && this.rustAtlaspack != null
559
560
  ? // @ts-expect-error TS2345
560
561
  (0, AssetGraphRequestRust_1.createAssetGraphRequestRust)(this.rustAtlaspack)(input)
561
562
  : // @ts-expect-error TS2345
@@ -16,6 +16,7 @@ const Environment_1 = require("./public/Environment");
16
16
  const projectPath_1 = require("./projectPath");
17
17
  const constants_1 = require("./constants");
18
18
  const feature_flags_1 = require("@atlaspack/feature-flags");
19
+ const logger_1 = __importDefault(require("@atlaspack/logger"));
19
20
  const EnvironmentManager_1 = require("./EnvironmentManager");
20
21
  exports.bundleGraphEdgeTypes = {
21
22
  // A lack of an edge type indicates to follow the edge while traversing
@@ -42,7 +43,7 @@ exports.bundleGraphEdgeTypes = {
42
43
  internal_async: 5,
43
44
  // This type is used to mark an edge between a bundle and a conditional bundle.
44
45
  // This allows efficient discovery of conditional bundles in packaging
45
- conditional: 5,
46
+ conditional: 6,
46
47
  };
47
48
  function makeReadOnlySet(set) {
48
49
  return new Proxy(set, {
@@ -380,6 +381,108 @@ class BundleGraph {
380
381
  conditions: serialized.conditions,
381
382
  });
382
383
  }
384
+ /**
385
+ * Serialize the bundle graph for efficient transfer to native Rust code.
386
+ * Returns a JSON string of nodes, an array of edges, and a map of asset IDs to public IDs.
387
+ */
388
+ serializeForNative() {
389
+ const start = performance.now();
390
+ const nodes = this._graph.nodes;
391
+ const edges = [];
392
+ const edgeIterator = this._graph.getAllEdges();
393
+ let next = edgeIterator.next();
394
+ while (!next.done) {
395
+ const edge = next.value;
396
+ edges.push([edge.from, edge.to, edge.type]);
397
+ next = edgeIterator.next();
398
+ }
399
+ // Extract and deduplicate environments
400
+ const environmentMap = new Map();
401
+ const extractEnvironment = (envRef) => {
402
+ const env = (0, EnvironmentManager_1.fromEnvironmentId)(envRef);
403
+ const envId = env.id;
404
+ if (!environmentMap.has(envId)) {
405
+ environmentMap.set(envId, env);
406
+ }
407
+ return envId;
408
+ };
409
+ // Replace env objects with env IDs in nodes
410
+ const processedNodes = nodes.map((node) => {
411
+ const processedNode = { ...node };
412
+ if (node.type === 'asset' && node.value?.env) {
413
+ processedNode.value = {
414
+ ...node.value,
415
+ env: extractEnvironment(node.value.env),
416
+ };
417
+ }
418
+ else if (node.type === 'dependency' && node.value?.env) {
419
+ processedNode.value = {
420
+ ...node.value,
421
+ env: extractEnvironment(node.value.env),
422
+ };
423
+ }
424
+ else if (node.type === 'bundle' && node.value?.env) {
425
+ processedNode.value = {
426
+ ...node.value,
427
+ env: extractEnvironment(node.value.env),
428
+ };
429
+ }
430
+ return processedNode;
431
+ });
432
+ // Optimize nodes by omitting null/undefined values to reduce JSON size
433
+ const optimizedNodes = processedNodes.map((node) => this._omitNulls(node));
434
+ const nodesJson = JSON.stringify(optimizedNodes);
435
+ // Serialize environments as array
436
+ const environments = Array.from(environmentMap.values());
437
+ const environmentsJson = JSON.stringify(environments);
438
+ // Convert Map to plain object for serialization
439
+ const publicIdByAssetId = {};
440
+ for (const [assetId, publicId] of this._publicIdByAssetId) {
441
+ publicIdByAssetId[assetId] = publicId;
442
+ }
443
+ const duration = performance.now() - start;
444
+ const nodesSizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
445
+ const envsSizeMB = (environmentsJson.length / (1024 * 1024)).toFixed(2);
446
+ logger_1.default.verbose({
447
+ origin: '@atlaspack/core',
448
+ message: `serializeForNative: ${duration.toFixed(1)}ms, ${nodesSizeMB}MB nodes, ${envsSizeMB}MB envs (${environmentMap.size} unique), ${nodes.length} nodes, ${edges.length} edges`,
449
+ });
450
+ return { nodesJson, edges, publicIdByAssetId, environmentsJson };
451
+ }
452
+ /**
453
+ * Remove null and undefined values from an object to reduce JSON size.
454
+ * Preserves false, 0, empty strings, and arrays.
455
+ */
456
+ _omitNulls(obj) {
457
+ if (obj === null || obj === undefined)
458
+ return obj;
459
+ if (typeof obj !== 'object')
460
+ return obj;
461
+ if (Array.isArray(obj)) {
462
+ return obj.map((item) => this._omitNulls(item));
463
+ }
464
+ const result = {};
465
+ for (const [key, value] of Object.entries(obj)) {
466
+ if (value === null || value === undefined) {
467
+ continue;
468
+ }
469
+ if (typeof value === 'object' &&
470
+ !Array.isArray(value) &&
471
+ Object.keys(value).length === 0) {
472
+ continue;
473
+ }
474
+ if (typeof value === 'object') {
475
+ const processed = this._omitNulls(value);
476
+ if (processed !== undefined) {
477
+ result[key] = processed;
478
+ }
479
+ }
480
+ else {
481
+ result[key] = value;
482
+ }
483
+ }
484
+ return result;
485
+ }
383
486
  createBundle(opts) {
384
487
  // @ts-expect-error TS2339
385
488
  let { entryAsset, target } = opts;
@@ -1103,8 +1206,36 @@ class BundleGraph {
1103
1206
  });
1104
1207
  }
1105
1208
  /**
1106
- * TODO: Document why this works like this & why visitor order matters
1107
- * on these use-cases.
1209
+ * Performs a depth-first traversal of all assets and dependencies contained
1210
+ * within a bundle. Only visits nodes that are directly contained in the bundle
1211
+ * (connected via a `contains` edge).
1212
+ *
1213
+ * Entry Asset Ordering:
1214
+ * The traversal guarantees that entry assets are visited in the exact order they
1215
+ * appear in `bundle.entryAssetIds`. This ordering is critical for several reasons:
1216
+ *
1217
+ * 1. **Code Execution Order in Packagers**: Packagers (ScopeHoistingPackager,
1218
+ * DevPackager) use this traversal to concatenate assets into the final bundle.
1219
+ * The traversal order determines the execution order of code in the output.
1220
+ * Entry assets must be processed in their defined order to ensure correct
1221
+ * initialization sequences.
1222
+ *
1223
+ * 2. **Runtime Injection**: Runtime assets (HMR, bundle manifests) are prepended
1224
+ * to `entryAssetIds` via `unshift()` in `applyRuntimes.ts`. By honoring the
1225
+ * array order, runtimes are guaranteed to be visited (and thus output) before
1226
+ * application entry points, ensuring the runtime infrastructure is available
1227
+ * when application code executes.
1228
+ *
1229
+ * 3. **Deterministic Builds**: Consistent traversal order ensures reproducible
1230
+ * bundle output, which is essential for caching and build verification.
1231
+ *
1232
+ * The sorting only applies at the first traversal level (direct children of the
1233
+ * start node). Subsequent levels follow standard DFS order based on the graph's
1234
+ * edge structure.
1235
+ *
1236
+ * @param bundle - The bundle to traverse
1237
+ * @param visit - Visitor callback receiving asset or dependency nodes
1238
+ * @param startAsset - Optional asset to start traversal from (defaults to bundle root)
1108
1239
  */
1109
1240
  traverseBundle(bundle, visit, startAsset) {
1110
1241
  let entries = !startAsset;
@@ -51,6 +51,13 @@ class AtlaspackV3 {
51
51
  buildAssetGraph() {
52
52
  return (0, rust_1.atlaspackNapiBuildAssetGraph)(this._atlaspack_napi);
53
53
  }
54
+ loadBundleGraph(bundleGraph) {
55
+ const { nodesJson, edges, publicIdByAssetId, environmentsJson } = bundleGraph.serializeForNative();
56
+ return (0, rust_1.atlaspackNapiLoadBundleGraph)(this._atlaspack_napi, nodesJson, edges, publicIdByAssetId, environmentsJson);
57
+ }
58
+ package(bundleId) {
59
+ return (0, rust_1.atlaspackNapiPackage)(this._atlaspack_napi, bundleId);
60
+ }
54
61
  async respondToFsEvents(events) {
55
62
  // @ts-expect-error TS2488
56
63
  let [needsRebuild, error] = await (0, rust_1.atlaspackNapiRespondToFsEvents)(this._atlaspack_napi, events);
@@ -15,6 +15,8 @@ const Bundle_1 = require("../public/Bundle");
15
15
  const Asset_1 = require("../public/Asset");
16
16
  const profiler_1 = require("@atlaspack/profiler");
17
17
  const RequestTracker_1 = require("../RequestTracker");
18
+ const feature_flags_1 = require("@atlaspack/feature-flags");
19
+ const EnvironmentManager_1 = require("../EnvironmentManager");
18
20
  function createAtlaspackBuildRequest(input) {
19
21
  return {
20
22
  type: RequestTracker_1.requestTypes.atlaspack_build_request,
@@ -34,6 +36,21 @@ async function run({ input, api, options, rustAtlaspack, }) {
34
36
  force: Boolean(rustAtlaspack) ||
35
37
  (options.shouldBuildLazily && requestedAssetIds.size > 0),
36
38
  });
39
+ if ((0, feature_flags_1.getFeatureFlag)('nativePackager') &&
40
+ (0, feature_flags_1.getFeatureFlag)('nativePackagerSSRDev') &&
41
+ rustAtlaspack) {
42
+ let hasSupportedTarget = false;
43
+ bundleGraph.traverseBundles((bundle, ctx, actions) => {
44
+ if ((0, EnvironmentManager_1.fromEnvironmentId)(bundle.env).context === 'tesseract' &&
45
+ bundle.type === 'js') {
46
+ hasSupportedTarget = true;
47
+ actions.stop();
48
+ }
49
+ });
50
+ if (hasSupportedTarget) {
51
+ await rustAtlaspack.loadBundleGraph(bundleGraph);
52
+ }
53
+ }
37
54
  // @ts-expect-error TS2345
38
55
  (0, dumpGraphToGraphViz_1.default)(bundleGraph._graph, 'BundleGraph', BundleGraph_1.bundleGraphEdgeTypes);
39
56
  await (0, ReporterRunner_1.report)({
@@ -104,7 +104,7 @@ function createBundleGraphRequest(input) {
104
104
  let { options, api, invalidateReason } = input;
105
105
  let { optionsRef, requestedAssetIds, signal } = input.input;
106
106
  let measurement = profiler_1.tracer.createMeasurement('building');
107
- let createAssetGraphRequest = input.rustAtlaspack
107
+ let createAssetGraphRequest = (0, feature_flags_1.getFeatureFlag)('atlaspackV3') && input.rustAtlaspack
108
108
  ? (0, AssetGraphRequestRust_1.createAssetGraphRequestRust)(input.rustAtlaspack)
109
109
  : AssetGraphRequest_1.default;
110
110
  let request = createAssetGraphRequest({
@@ -9,6 +9,10 @@ const nullthrows_1 = __importDefault(require("nullthrows"));
9
9
  const ConfigRequest_1 = require("./ConfigRequest");
10
10
  const DevDepRequest_1 = require("./DevDepRequest");
11
11
  const AtlaspackConfigRequest_1 = __importDefault(require("./AtlaspackConfigRequest"));
12
+ const EnvironmentManager_1 = require("../EnvironmentManager");
13
+ const feature_flags_1 = require("@atlaspack/feature-flags");
14
+ const logger_1 = __importDefault(require("@atlaspack/logger"));
15
+ const diagnostic_1 = __importDefault(require("@atlaspack/diagnostic"));
12
16
  function createPackageRequest(input) {
13
17
  return {
14
18
  type: RequestTracker_1.requestTypes.package_request,
@@ -17,21 +21,44 @@ function createPackageRequest(input) {
17
21
  input,
18
22
  };
19
23
  }
20
- async function run({ input, api, farm }) {
24
+ async function run({ input, api, farm, rustAtlaspack }) {
21
25
  let { bundleGraphReference, optionsRef, bundle, useMainThread } = input;
22
26
  let runPackage = farm.createHandle('runPackage', useMainThread);
23
27
  let start = Date.now();
24
28
  let { devDeps, invalidDevDeps } = await (0, DevDepRequest_1.getDevDepRequests)(api);
25
29
  let { cachePath } = (0, nullthrows_1.default)(await api.runRequest((0, AtlaspackConfigRequest_1.default)()));
26
- let { devDepRequests, configRequests, bundleInfo, invalidations } = (await runPackage({
27
- bundle,
28
- bundleGraphReference,
29
- optionsRef,
30
- configCachePath: cachePath,
31
- previousDevDeps: devDeps,
32
- invalidDevDeps,
33
- previousInvalidations: api.getInvalidations(),
34
- }));
30
+ let packagingResult;
31
+ if ((0, feature_flags_1.getFeatureFlag)('nativePackager') &&
32
+ (0, feature_flags_1.getFeatureFlag)('nativePackagerSSRDev') &&
33
+ rustAtlaspack &&
34
+ (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env).context === 'tesseract' &&
35
+ bundle.type === 'js') {
36
+ // Once this actually does something, the code below will be in an `else` block (i.e. we'll only run one or the other)
37
+ let result = await rustAtlaspack.package(bundle.id);
38
+ let error = null;
39
+ [packagingResult, error] = result;
40
+ if (error) {
41
+ throw new diagnostic_1.default({
42
+ diagnostic: error,
43
+ });
44
+ }
45
+ logger_1.default.verbose({
46
+ message: JSON.stringify(packagingResult, null, 2),
47
+ origin: '@atlaspack/core',
48
+ });
49
+ }
50
+ else {
51
+ packagingResult = (await runPackage({
52
+ bundle,
53
+ bundleGraphReference,
54
+ optionsRef,
55
+ configCachePath: cachePath,
56
+ previousDevDeps: devDeps,
57
+ invalidDevDeps,
58
+ previousInvalidations: api.getInvalidations(),
59
+ }));
60
+ }
61
+ let { devDepRequests, configRequests, bundleInfo, invalidations } = packagingResult;
35
62
  for (let devDepRequest of devDepRequests) {
36
63
  await (0, DevDepRequest_1.runDevDepRequest)(api, devDepRequest);
37
64
  }
@@ -132,7 +132,7 @@ async function resolveOptions(initialOptions) {
132
132
  if (initialOptions.cache) {
133
133
  return initialOptions.cache;
134
134
  }
135
- const needsRustLmdbCache = (0, feature_flags_1.getFeatureFlag)('atlaspackV3');
135
+ const needsRustLmdbCache = (0, feature_flags_1.getFeatureFlag)('atlaspackV3') || (0, feature_flags_1.getFeatureFlag)('nativePackager');
136
136
  if (!(0, feature_flags_1.getFeatureFlag)('cachePerformanceImprovements')) {
137
137
  if (!needsRustLmdbCache && !(outputFS instanceof fs_1.NodeFS)) {
138
138
  return new cache_1.FSCache(outputFS, cacheDir);
package/lib/Atlaspack.js CHANGED
@@ -197,7 +197,7 @@ class Atlaspack {
197
197
  });
198
198
  this.#resolvedOptions = resolvedOptions;
199
199
  let rustAtlaspack;
200
- if (resolvedOptions.featureFlags.atlaspackV3) {
200
+ if (resolvedOptions.featureFlags.atlaspackV3 || resolvedOptions.featureFlags.nativePackager) {
201
201
  // eslint-disable-next-line no-unused-vars
202
202
  let {
203
203
  entries,
@@ -553,7 +553,7 @@ class Atlaspack {
553
553
  message: `File watch event emitted with ${events.length} events. Sample event: [${(_events$ = events[0]) === null || _events$ === void 0 ? void 0 : _events$.type}] ${(_events$2 = events[0]) === null || _events$2 === void 0 ? void 0 : _events$2.path}`
554
554
  });
555
555
  let nativeInvalid = false;
556
- if (this.rustAtlaspack) {
556
+ if ((0, _featureFlags().getFeatureFlag)('atlaspackV3') && this.rustAtlaspack) {
557
557
  nativeInvalid = await this.rustAtlaspack.respondToFsEvents(events);
558
558
  }
559
559
  let {
@@ -634,7 +634,7 @@ class Atlaspack {
634
634
  requestedAssetIds: this.#requestedAssetIds
635
635
  };
636
636
  const start = Date.now();
637
- const result = await this.#requestTracker.runRequest(this.rustAtlaspack != null ?
637
+ const result = await this.#requestTracker.runRequest((0, _featureFlags().getFeatureFlag)('atlaspackV3') && this.rustAtlaspack != null ?
638
638
  // @ts-expect-error TS2345
639
639
  (0, _AssetGraphRequestRust.createAssetGraphRequestRust)(this.rustAtlaspack)(input) :
640
640
  // @ts-expect-error TS2345
@@ -51,6 +51,13 @@ function _featureFlags() {
51
51
  };
52
52
  return data;
53
53
  }
54
+ function _logger() {
55
+ const data = _interopRequireDefault(require("@atlaspack/logger"));
56
+ _logger = function () {
57
+ return data;
58
+ };
59
+ return data;
60
+ }
54
61
  var _EnvironmentManager = require("./EnvironmentManager");
55
62
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
56
63
  const bundleGraphEdgeTypes = exports.bundleGraphEdgeTypes = {
@@ -78,7 +85,7 @@ const bundleGraphEdgeTypes = exports.bundleGraphEdgeTypes = {
78
85
  internal_async: 5,
79
86
  // This type is used to mark an edge between a bundle and a conditional bundle.
80
87
  // This allows efficient discovery of conditional bundles in packaging
81
- conditional: 5
88
+ conditional: 6
82
89
  };
83
90
  function makeReadOnlySet(set) {
84
91
  return new Proxy(set, {
@@ -428,6 +435,116 @@ class BundleGraph {
428
435
  conditions: serialized.conditions
429
436
  });
430
437
  }
438
+
439
+ /**
440
+ * Serialize the bundle graph for efficient transfer to native Rust code.
441
+ * Returns a JSON string of nodes, an array of edges, and a map of asset IDs to public IDs.
442
+ */
443
+ serializeForNative() {
444
+ const start = performance.now();
445
+ const nodes = this._graph.nodes;
446
+ const edges = [];
447
+ const edgeIterator = this._graph.getAllEdges();
448
+ let next = edgeIterator.next();
449
+ while (!next.done) {
450
+ const edge = next.value;
451
+ edges.push([edge.from, edge.to, edge.type]);
452
+ next = edgeIterator.next();
453
+ }
454
+
455
+ // Extract and deduplicate environments
456
+ const environmentMap = new Map();
457
+ const extractEnvironment = envRef => {
458
+ const env = (0, _EnvironmentManager.fromEnvironmentId)(envRef);
459
+ const envId = env.id;
460
+ if (!environmentMap.has(envId)) {
461
+ environmentMap.set(envId, env);
462
+ }
463
+ return envId;
464
+ };
465
+
466
+ // Replace env objects with env IDs in nodes
467
+ const processedNodes = nodes.map(node => {
468
+ var _node$value, _node$value2, _node$value3;
469
+ const processedNode = {
470
+ ...node
471
+ };
472
+ if (node.type === 'asset' && (_node$value = node.value) !== null && _node$value !== void 0 && _node$value.env) {
473
+ processedNode.value = {
474
+ ...node.value,
475
+ env: extractEnvironment(node.value.env)
476
+ };
477
+ } else if (node.type === 'dependency' && (_node$value2 = node.value) !== null && _node$value2 !== void 0 && _node$value2.env) {
478
+ processedNode.value = {
479
+ ...node.value,
480
+ env: extractEnvironment(node.value.env)
481
+ };
482
+ } else if (node.type === 'bundle' && (_node$value3 = node.value) !== null && _node$value3 !== void 0 && _node$value3.env) {
483
+ processedNode.value = {
484
+ ...node.value,
485
+ env: extractEnvironment(node.value.env)
486
+ };
487
+ }
488
+ return processedNode;
489
+ });
490
+
491
+ // Optimize nodes by omitting null/undefined values to reduce JSON size
492
+ const optimizedNodes = processedNodes.map(node => this._omitNulls(node));
493
+ const nodesJson = JSON.stringify(optimizedNodes);
494
+
495
+ // Serialize environments as array
496
+ const environments = Array.from(environmentMap.values());
497
+ const environmentsJson = JSON.stringify(environments);
498
+
499
+ // Convert Map to plain object for serialization
500
+ const publicIdByAssetId = {};
501
+ for (const [assetId, publicId] of this._publicIdByAssetId) {
502
+ publicIdByAssetId[assetId] = publicId;
503
+ }
504
+ const duration = performance.now() - start;
505
+ const nodesSizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
506
+ const envsSizeMB = (environmentsJson.length / (1024 * 1024)).toFixed(2);
507
+ _logger().default.verbose({
508
+ origin: '@atlaspack/core',
509
+ message: `serializeForNative: ${duration.toFixed(1)}ms, ${nodesSizeMB}MB nodes, ${envsSizeMB}MB envs (${environmentMap.size} unique), ${nodes.length} nodes, ${edges.length} edges`
510
+ });
511
+ return {
512
+ nodesJson,
513
+ edges,
514
+ publicIdByAssetId,
515
+ environmentsJson
516
+ };
517
+ }
518
+
519
+ /**
520
+ * Remove null and undefined values from an object to reduce JSON size.
521
+ * Preserves false, 0, empty strings, and arrays.
522
+ */
523
+ _omitNulls(obj) {
524
+ if (obj === null || obj === undefined) return obj;
525
+ if (typeof obj !== 'object') return obj;
526
+ if (Array.isArray(obj)) {
527
+ return obj.map(item => this._omitNulls(item));
528
+ }
529
+ const result = {};
530
+ for (const [key, value] of Object.entries(obj)) {
531
+ if (value === null || value === undefined) {
532
+ continue;
533
+ }
534
+ if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
535
+ continue;
536
+ }
537
+ if (typeof value === 'object') {
538
+ const processed = this._omitNulls(value);
539
+ if (processed !== undefined) {
540
+ result[key] = processed;
541
+ }
542
+ } else {
543
+ result[key] = value;
544
+ }
545
+ }
546
+ return result;
547
+ }
431
548
  createBundle(opts) {
432
549
  // @ts-expect-error TS2339
433
550
  let {
@@ -1084,8 +1201,36 @@ class BundleGraph {
1084
1201
  }
1085
1202
 
1086
1203
  /**
1087
- * TODO: Document why this works like this & why visitor order matters
1088
- * on these use-cases.
1204
+ * Performs a depth-first traversal of all assets and dependencies contained
1205
+ * within a bundle. Only visits nodes that are directly contained in the bundle
1206
+ * (connected via a `contains` edge).
1207
+ *
1208
+ * Entry Asset Ordering:
1209
+ * The traversal guarantees that entry assets are visited in the exact order they
1210
+ * appear in `bundle.entryAssetIds`. This ordering is critical for several reasons:
1211
+ *
1212
+ * 1. **Code Execution Order in Packagers**: Packagers (ScopeHoistingPackager,
1213
+ * DevPackager) use this traversal to concatenate assets into the final bundle.
1214
+ * The traversal order determines the execution order of code in the output.
1215
+ * Entry assets must be processed in their defined order to ensure correct
1216
+ * initialization sequences.
1217
+ *
1218
+ * 2. **Runtime Injection**: Runtime assets (HMR, bundle manifests) are prepended
1219
+ * to `entryAssetIds` via `unshift()` in `applyRuntimes.ts`. By honoring the
1220
+ * array order, runtimes are guaranteed to be visited (and thus output) before
1221
+ * application entry points, ensuring the runtime infrastructure is available
1222
+ * when application code executes.
1223
+ *
1224
+ * 3. **Deterministic Builds**: Consistent traversal order ensures reproducible
1225
+ * bundle output, which is essential for caching and build verification.
1226
+ *
1227
+ * The sorting only applies at the first traversal level (direct children of the
1228
+ * start node). Subsequent levels follow standard DFS order based on the graph's
1229
+ * edge structure.
1230
+ *
1231
+ * @param bundle - The bundle to traverse
1232
+ * @param visit - Visitor callback receiving asset or dependency nodes
1233
+ * @param startAsset - Optional asset to start traversal from (defaults to bundle root)
1089
1234
  */
1090
1235
  traverseBundle(bundle, visit, startAsset) {
1091
1236
  let entries = !startAsset;
@@ -72,6 +72,18 @@ class AtlaspackV3 {
72
72
  buildAssetGraph() {
73
73
  return (0, _rust().atlaspackNapiBuildAssetGraph)(this._atlaspack_napi);
74
74
  }
75
+ loadBundleGraph(bundleGraph) {
76
+ const {
77
+ nodesJson,
78
+ edges,
79
+ publicIdByAssetId,
80
+ environmentsJson
81
+ } = bundleGraph.serializeForNative();
82
+ return (0, _rust().atlaspackNapiLoadBundleGraph)(this._atlaspack_napi, nodesJson, edges, publicIdByAssetId, environmentsJson);
83
+ }
84
+ package(bundleId) {
85
+ return (0, _rust().atlaspackNapiPackage)(this._atlaspack_napi, bundleId);
86
+ }
75
87
  async respondToFsEvents(events) {
76
88
  // @ts-expect-error TS2488
77
89
  let [needsRebuild, error] = await (0, _rust().atlaspackNapiRespondToFsEvents)(this._atlaspack_napi, events);
@@ -21,6 +21,14 @@ function _profiler() {
21
21
  return data;
22
22
  }
23
23
  var _RequestTracker = require("../RequestTracker");
24
+ function _featureFlags() {
25
+ const data = require("@atlaspack/feature-flags");
26
+ _featureFlags = function () {
27
+ return data;
28
+ };
29
+ return data;
30
+ }
31
+ var _EnvironmentManager = require("../EnvironmentManager");
24
32
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
25
33
  function createAtlaspackBuildRequest(input) {
26
34
  return {
@@ -53,6 +61,18 @@ async function run({
53
61
  } = await api.runRequest(bundleGraphRequest, {
54
62
  force: Boolean(rustAtlaspack) || options.shouldBuildLazily && requestedAssetIds.size > 0
55
63
  });
64
+ if ((0, _featureFlags().getFeatureFlag)('nativePackager') && (0, _featureFlags().getFeatureFlag)('nativePackagerSSRDev') && rustAtlaspack) {
65
+ let hasSupportedTarget = false;
66
+ bundleGraph.traverseBundles((bundle, ctx, actions) => {
67
+ if ((0, _EnvironmentManager.fromEnvironmentId)(bundle.env).context === 'tesseract' && bundle.type === 'js') {
68
+ hasSupportedTarget = true;
69
+ actions.stop();
70
+ }
71
+ });
72
+ if (hasSupportedTarget) {
73
+ await rustAtlaspack.loadBundleGraph(bundleGraph);
74
+ }
75
+ }
56
76
 
57
77
  // @ts-expect-error TS2345
58
78
  (0, _dumpGraphToGraphViz.default)(bundleGraph._graph, 'BundleGraph', _BundleGraph.bundleGraphEdgeTypes);
@@ -138,7 +138,7 @@ function createBundleGraphRequest(input) {
138
138
  signal
139
139
  } = input.input;
140
140
  let measurement = _profiler().tracer.createMeasurement('building');
141
- let createAssetGraphRequest = input.rustAtlaspack ? (0, _AssetGraphRequestRust.createAssetGraphRequestRust)(input.rustAtlaspack) : _AssetGraphRequest.default;
141
+ let createAssetGraphRequest = (0, _featureFlags().getFeatureFlag)('atlaspackV3') && input.rustAtlaspack ? (0, _AssetGraphRequestRust.createAssetGraphRequestRust)(input.rustAtlaspack) : _AssetGraphRequest.default;
142
142
  let request = createAssetGraphRequest({
143
143
  name: 'Main',
144
144
  entries: options.entries,