@atlaspack/core 2.32.0 → 2.33.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.
Files changed (32) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/BundleGraph.js +78 -8
  3. package/dist/atlaspack-v3/AtlaspackV3.js +7 -4
  4. package/dist/atlaspack-v3/worker/worker.js +1 -0
  5. package/dist/requests/AtlaspackBuildRequest.js +12 -5
  6. package/dist/requests/BundleGraphRequest.js +15 -78
  7. package/dist/requests/BundleGraphRequestRust.js +320 -0
  8. package/dist/requests/BundleGraphRequestUtils.js +131 -0
  9. package/dist/requests/PackageRequest.js +27 -10
  10. package/lib/BundleGraph.js +85 -8
  11. package/lib/atlaspack-v3/AtlaspackV3.js +9 -4
  12. package/lib/atlaspack-v3/worker/worker.js +2 -1
  13. package/lib/requests/AtlaspackBuildRequest.js +6 -1
  14. package/lib/requests/BundleGraphRequest.js +15 -87
  15. package/lib/requests/BundleGraphRequestRust.js +378 -0
  16. package/lib/requests/BundleGraphRequestUtils.js +151 -0
  17. package/lib/requests/PackageRequest.js +38 -10
  18. package/lib/types/BundleGraph.d.ts +34 -4
  19. package/lib/types/atlaspack-v3/AtlaspackV3.d.ts +4 -1
  20. package/lib/types/atlaspack-v3/worker/worker.d.ts +1 -0
  21. package/lib/types/requests/BundleGraphRequestRust.d.ts +34 -0
  22. package/lib/types/requests/BundleGraphRequestUtils.d.ts +31 -0
  23. package/package.json +15 -15
  24. package/src/BundleGraph.ts +83 -8
  25. package/src/atlaspack-v3/AtlaspackV3.ts +17 -5
  26. package/src/atlaspack-v3/worker/worker.ts +1 -0
  27. package/src/requests/AtlaspackBuildRequest.ts +13 -5
  28. package/src/requests/BundleGraphRequest.ts +25 -100
  29. package/src/requests/BundleGraphRequestRust.ts +464 -0
  30. package/src/requests/BundleGraphRequestUtils.ts +167 -0
  31. package/src/requests/PackageRequest.ts +20 -5
  32. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.default = createBundleGraphRequestRust;
40
+ exports.getBundleGraph = getBundleGraph;
41
+ const assert_1 = __importDefault(require("assert"));
42
+ const diagnostic_1 = __importDefault(require("@atlaspack/diagnostic"));
43
+ const graph_1 = require("@atlaspack/graph");
44
+ const logger_1 = require("@atlaspack/logger");
45
+ const feature_flags_1 = require("@atlaspack/feature-flags");
46
+ const BundleGraph_1 = __importStar(require("../BundleGraph"));
47
+ const dumpGraphToGraphViz_1 = __importDefault(require("../dumpGraphToGraphViz"));
48
+ const nullthrows_1 = __importDefault(require("nullthrows"));
49
+ const rust_1 = require("@atlaspack/rust");
50
+ const PluginOptions_1 = __importDefault(require("../public/PluginOptions"));
51
+ const applyRuntimes_1 = __importDefault(require("../applyRuntimes"));
52
+ const constants_1 = require("../constants");
53
+ const utils_1 = require("../utils");
54
+ const DevDepRequest_1 = require("./DevDepRequest");
55
+ const RequestTracker_1 = require("../RequestTracker");
56
+ const AtlaspackConfigRequest_1 = __importStar(require("./AtlaspackConfigRequest"));
57
+ const BundleGraphRequestUtils_1 = require("./BundleGraphRequestUtils");
58
+ const EnvironmentManager_1 = require("../EnvironmentManager");
59
+ const Environment_1 = require("../Environment");
60
+ function createBundleGraphRequestRust(input) {
61
+ return {
62
+ type: RequestTracker_1.requestTypes.bundle_graph_request,
63
+ id: 'BundleGraphRust',
64
+ run: async (runInput) => {
65
+ const { api, options, rustAtlaspack } = runInput;
66
+ (0, assert_1.default)(rustAtlaspack, 'BundleGraphRequestRust requires rustAtlaspack');
67
+ let { bundleGraphPromise, commitPromise } = await rustAtlaspack.buildBundleGraph();
68
+ let [serializedBundleGraph, bundleGraphError] = (await bundleGraphPromise);
69
+ if (bundleGraphError) {
70
+ throw new diagnostic_1.default({ diagnostic: bundleGraphError });
71
+ }
72
+ // Don’t reuse previous JS result yet; we just rebuild from scratch.
73
+ let { bundleGraph, changedAssets } = (0, logger_1.instrument)('atlaspack_v3_getBundleGraph', () => getBundleGraph(serializedBundleGraph));
74
+ const runner = new NativeBundlerRunner({ api, options }, input.optionsRef);
75
+ await runner.loadConfigs();
76
+ // Name all bundles
77
+ const namers = await runner.config.getNamers();
78
+ const bundles = bundleGraph.getBundles({ includeInline: true });
79
+ await Promise.all(bundles.map((b) => (0, BundleGraphRequestUtils_1.nameBundle)(namers, b, bundleGraph, options, runner.pluginOptions, runner.configs)));
80
+ // Apply runtimes
81
+ const changedRuntimes = await (0, logger_1.instrumentAsync)('applyRuntimes', () => (0, applyRuntimes_1.default)({
82
+ bundleGraph,
83
+ api,
84
+ config: runner.config,
85
+ options,
86
+ optionsRef: input.optionsRef,
87
+ pluginOptions: runner.pluginOptions,
88
+ previousDevDeps: runner.previousDevDeps,
89
+ devDepRequests: runner.devDepRequests,
90
+ configs: runner.configs,
91
+ }));
92
+ // Add dev deps for namers
93
+ for (const namer of namers) {
94
+ const devDepRequest = await (0, DevDepRequest_1.createDevDependency)({
95
+ specifier: namer.name,
96
+ resolveFrom: namer.resolveFrom,
97
+ }, runner.previousDevDeps, options);
98
+ await (0, BundleGraphRequestUtils_1.runDevDepRequest)(api, devDepRequest, runner.devDepRequests);
99
+ }
100
+ (0, BundleGraphRequestUtils_1.validateBundles)(bundleGraph);
101
+ bundleGraph.getBundleGraphHash();
102
+ await (0, dumpGraphToGraphViz_1.default)(
103
+ // @ts-expect-error Accessing internal graph for debug output
104
+ bundleGraph._graph, 'after_runtimes_native', BundleGraph_1.bundleGraphEdgeTypes);
105
+ let [_commitResult, commitError] = await commitPromise;
106
+ if (commitError) {
107
+ throw new diagnostic_1.default({
108
+ diagnostic: {
109
+ message: 'Error committing bundle graph in Rust: ' + commitError.message,
110
+ },
111
+ });
112
+ }
113
+ return {
114
+ bundleGraph,
115
+ // Not accurate yet — ok for now.
116
+ assetGraphBundlingVersion: 0,
117
+ changedAssets: changedRuntimes,
118
+ assetRequests: [],
119
+ };
120
+ },
121
+ input,
122
+ };
123
+ }
124
+ function mapSymbols({ exported, ...symbol }) {
125
+ let jsSymbol = {
126
+ local: symbol.local ?? undefined,
127
+ loc: symbol.loc ?? undefined,
128
+ isWeak: symbol.isWeak,
129
+ meta: {
130
+ isEsm: symbol.isEsmExport,
131
+ isStaticBindingSafe: symbol.isStaticBindingSafe,
132
+ },
133
+ };
134
+ if (symbol.exported) {
135
+ jsSymbol.exported = symbol.exported;
136
+ }
137
+ return [exported, jsSymbol];
138
+ }
139
+ function normalizeEnv(env) {
140
+ if (!env)
141
+ return env;
142
+ env.id = env.id || (0, Environment_1.getEnvironmentHash)(env);
143
+ return (0, EnvironmentManager_1.toEnvironmentRef)(env);
144
+ }
145
+ function getBundleGraph(serializedGraph) {
146
+ // Build a fresh internal bundle graph.
147
+ const publicIdByAssetId = new Map(Object.entries(serializedGraph.publicIdByAssetId ?? {}));
148
+ const assetPublicIds = new Set(serializedGraph.assetPublicIds ?? []);
149
+ // BundleGraph constructor expects a ContentGraph under `_graph`.
150
+ // We reuse the internal graph class by creating an empty instance and then adding nodes.
151
+ const graph = new BundleGraph_1.default({
152
+ // We intentionally start with an empty graph and add nodes/edges from the Rust payload.
153
+ // `ContentGraph` will allocate as needed.
154
+ graph: new graph_1.ContentGraph(),
155
+ bundleContentHashes: new Map(),
156
+ publicIdByAssetId,
157
+ assetPublicIds,
158
+ conditions: new Map(),
159
+ });
160
+ // Root must exist at node id 0.
161
+ const rootNodeId = graph._graph.addNodeByContentKey('@@root', {
162
+ id: '@@root',
163
+ type: 'root',
164
+ value: null,
165
+ });
166
+ graph._graph.setRootNodeId(rootNodeId);
167
+ let entry = 0;
168
+ const changedAssets = new Map();
169
+ const decoder = new TextDecoder();
170
+ // Create nodes in order.
171
+ for (let i = 0; i < serializedGraph.nodes.length; i++) {
172
+ // Nodes come back as buffers (same as AssetGraphRequestRust)
173
+ let node = JSON.parse(decoder.decode(serializedGraph.nodes[i]));
174
+ if (node.type === 'root') {
175
+ continue;
176
+ }
177
+ if (node.type === 'entry') {
178
+ let id = 'entry:' + ++entry;
179
+ graph._graph.addNodeByContentKey(id, { id, type: 'root', value: null });
180
+ continue;
181
+ }
182
+ if (node.type === 'asset') {
183
+ let asset = node.value;
184
+ let id = asset.id;
185
+ asset.committed = true;
186
+ asset.contentKey = id;
187
+ asset.env = { ...asset.env };
188
+ asset.env.id = (0, feature_flags_1.getFeatureFlag)('environmentDeduplication')
189
+ ? (0, Environment_1.getEnvironmentHash)(asset.env)
190
+ : (0, Environment_1.getEnvironmentHash)(asset.env);
191
+ asset.env = normalizeEnv(asset.env);
192
+ asset.mapKey = `map:${asset.id}`;
193
+ asset.dependencies = new Map();
194
+ asset.meta.isV3 = true;
195
+ if (asset.symbols != null) {
196
+ asset.symbols = new Map(asset.symbols.map(mapSymbols));
197
+ }
198
+ changedAssets.set(id, asset);
199
+ const assetNode = {
200
+ id,
201
+ type: 'asset',
202
+ usedSymbols: new Set(),
203
+ usedSymbolsDownDirty: true,
204
+ usedSymbolsUpDirty: true,
205
+ value: asset,
206
+ };
207
+ graph._graph.addNodeByContentKey(id, assetNode);
208
+ continue;
209
+ }
210
+ if (node.type === 'dependency') {
211
+ let { dependency, id } = node.value;
212
+ dependency.id = id;
213
+ dependency.env = { ...dependency.env };
214
+ dependency.env.id = (0, Environment_1.getEnvironmentHash)(dependency.env);
215
+ dependency.env = normalizeEnv(dependency.env);
216
+ if (dependency.symbols != null) {
217
+ dependency.symbols = new Map(dependency.symbols?.map(mapSymbols));
218
+ }
219
+ let usedSymbolsDown = new Set();
220
+ let usedSymbolsUp = new Map();
221
+ if (dependency.isEntry && dependency.isLibrary) {
222
+ usedSymbolsDown.add('*');
223
+ usedSymbolsUp.set('*', undefined);
224
+ }
225
+ const depNode = {
226
+ id,
227
+ type: 'dependency',
228
+ deferred: false,
229
+ excluded: false,
230
+ hasDeferred: node.has_deferred,
231
+ // @ts-expect-error Flow types expect a more specific symbol set type
232
+ usedSymbolsDown,
233
+ usedSymbolsDownDirty: true,
234
+ usedSymbolsUp,
235
+ usedSymbolsUpDirtyDown: true,
236
+ usedSymbolsUpDirtyUp: true,
237
+ value: dependency,
238
+ };
239
+ graph._graph.addNodeByContentKey(id, depNode);
240
+ continue;
241
+ }
242
+ if (node.type === 'bundle') {
243
+ node.value.env = normalizeEnv(node.value.env);
244
+ node.value.target.env = normalizeEnv(node.value.target.env);
245
+ graph._graph.addNodeByContentKey(node.id, node);
246
+ continue;
247
+ }
248
+ if (node.type === 'bundle_group' || node.type === 'bundleGroup') {
249
+ // Rust serializer may emit bundleGroup nodes either as `{id,type,value:{...}}`
250
+ // or as `{type:"bundleGroup", id, target, entryAssetId}`.
251
+ if (node.value == null) {
252
+ node.value = {
253
+ target: node.target,
254
+ entryAssetId: node.entryAssetId ?? node.entry_asset_id,
255
+ };
256
+ }
257
+ // Normalize entry asset id field naming
258
+ if (node.value.entryAssetId == null &&
259
+ node.value.entry_asset_id != null) {
260
+ node.value.entryAssetId = node.value.entry_asset_id;
261
+ }
262
+ node.value.target.env = normalizeEnv(node.value.target.env);
263
+ // Normalise to the expected snake_case type
264
+ node.type = 'bundle_group';
265
+ graph._graph.addNodeByContentKey(node.id, node);
266
+ continue;
267
+ }
268
+ }
269
+ // Apply edges
270
+ for (let i = 0; i < serializedGraph.edges.length; i += 3) {
271
+ const from = serializedGraph.edges[i];
272
+ const to = serializedGraph.edges[i + 1];
273
+ const type = serializedGraph.edges[i + 2];
274
+ const fromNode = graph._graph.getNode(from);
275
+ const toNode = graph._graph.getNode(to);
276
+ if (fromNode?.type === 'asset' && toNode?.type === 'dependency') {
277
+ fromNode.value.dependencies.set(toNode.value.id, toNode.value);
278
+ }
279
+ // If we are adding a references edge, remove existing null edge.
280
+ if (type === BundleGraph_1.bundleGraphEdgeTypes.references &&
281
+ graph._graph.hasEdge(from, to, BundleGraph_1.bundleGraphEdgeTypes.null)) {
282
+ graph._graph.removeEdge(from, to, BundleGraph_1.bundleGraphEdgeTypes.null);
283
+ }
284
+ graph._graph.addEdge(from, to, type);
285
+ }
286
+ return { bundleGraph: graph, changedAssets };
287
+ }
288
+ class NativeBundlerRunner {
289
+ constructor({ api, options }, optionsRef) {
290
+ this.options = options;
291
+ this.api = api;
292
+ this.optionsRef = optionsRef;
293
+ this.previousDevDeps = new Map();
294
+ this.devDepRequests = new Map();
295
+ this.configs = new Map();
296
+ this.pluginOptions = new PluginOptions_1.default((0, utils_1.optionsProxy)(this.options, api.invalidateOnOptionChange));
297
+ const key = (0, rust_1.hashString)(`${constants_1.ATLASPACK_VERSION}:BundleGraph:${JSON.stringify(options.entries) ?? ''}${options.mode}${options.shouldBuildLazily ? 'lazy' : 'eager'}`);
298
+ this.cacheKey = `BundleGraph/${constants_1.ATLASPACK_VERSION}/${options.mode}/${key}`;
299
+ }
300
+ async loadConfigs() {
301
+ const configResult = (0, nullthrows_1.default)(await this.api.runRequest((0, AtlaspackConfigRequest_1.default)()));
302
+ this.config = (0, AtlaspackConfigRequest_1.getCachedAtlaspackConfig)(configResult, this.options);
303
+ const { devDeps, invalidDevDeps } = await (0, DevDepRequest_1.getDevDepRequests)(this.api);
304
+ this.previousDevDeps = devDeps;
305
+ (0, DevDepRequest_1.invalidateDevDeps)(invalidDevDeps, this.options, this.config);
306
+ const bundler = await this.config.getBundler();
307
+ await this.loadPluginConfig(bundler);
308
+ const namers = await this.config.getNamers();
309
+ for (const namer of namers) {
310
+ await this.loadPluginConfig(namer);
311
+ }
312
+ const runtimes = await this.config.getRuntimes();
313
+ for (const runtime of runtimes) {
314
+ await this.loadPluginConfig(runtime);
315
+ }
316
+ }
317
+ async loadPluginConfig(plugin) {
318
+ await (0, BundleGraphRequestUtils_1.loadPluginConfigWithDevDeps)(plugin, this.options, this.api, this.previousDevDeps, this.devDepRequests, this.configs);
319
+ }
320
+ }
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.validateBundles = validateBundles;
40
+ exports.nameBundle = nameBundle;
41
+ exports.loadPluginConfigWithDevDeps = loadPluginConfigWithDevDeps;
42
+ exports.runDevDepRequest = runDevDepRequest;
43
+ const assert_1 = __importDefault(require("assert"));
44
+ const nullthrows_1 = __importDefault(require("nullthrows"));
45
+ const logger_1 = require("@atlaspack/logger");
46
+ const diagnostic_1 = __importStar(require("@atlaspack/diagnostic"));
47
+ const utils_1 = require("@atlaspack/utils");
48
+ const BundleGraph_1 = __importDefault(require("../public/BundleGraph"));
49
+ const Bundle_1 = require("../public/Bundle");
50
+ const InternalConfig_1 = require("../InternalConfig");
51
+ const DevDepRequest_1 = require("./DevDepRequest");
52
+ const ConfigRequest_1 = require("./ConfigRequest");
53
+ const projectPath_1 = require("../projectPath");
54
+ const profiler_1 = require("@atlaspack/profiler");
55
+ /**
56
+ * Validates that all bundles have unique names.
57
+ * Throws an assertion error if duplicate bundle names are found.
58
+ */
59
+ function validateBundles(bundleGraph) {
60
+ const bundles = bundleGraph.getBundles();
61
+ const bundleNames = bundles.map((b) => (0, projectPath_1.joinProjectPath)(b.target.distDir, (0, nullthrows_1.default)(b.name)));
62
+ assert_1.default.deepEqual(bundleNames, (0, utils_1.unique)(bundleNames), 'Bundles must have unique name. Conflicting names: ' +
63
+ [
64
+ ...(0, utils_1.setSymmetricDifference)(new Set(bundleNames), new Set((0, utils_1.unique)(bundleNames))),
65
+ ].join());
66
+ }
67
+ /**
68
+ * Names a bundle by running through the configured namers until one returns a name.
69
+ */
70
+ async function nameBundle(namers, internalBundle, internalBundleGraph, options, pluginOptions, configs) {
71
+ const bundle = Bundle_1.Bundle.get(internalBundle, internalBundleGraph, options);
72
+ const bundleGraph = new BundleGraph_1.default(internalBundleGraph, Bundle_1.NamedBundle.get.bind(Bundle_1.NamedBundle), options);
73
+ for (const namer of namers) {
74
+ let measurement;
75
+ try {
76
+ measurement = profiler_1.tracer.createMeasurement(namer.name, 'namer', bundle.id);
77
+ const name = await namer.plugin.name({
78
+ bundle,
79
+ bundleGraph,
80
+ config: configs.get(namer.name)?.result,
81
+ options: pluginOptions,
82
+ logger: new logger_1.PluginLogger({ origin: namer.name }),
83
+ tracer: new profiler_1.PluginTracer({ origin: namer.name, category: 'namer' }),
84
+ });
85
+ if (name != null) {
86
+ internalBundle.name = name;
87
+ const { hashReference } = internalBundle;
88
+ internalBundle.displayName = name.includes(hashReference)
89
+ ? name.replace(hashReference, '[hash]')
90
+ : name;
91
+ return;
92
+ }
93
+ }
94
+ catch (e) {
95
+ throw new diagnostic_1.default({
96
+ diagnostic: (0, diagnostic_1.errorToDiagnostic)(e, {
97
+ origin: namer.name,
98
+ }),
99
+ });
100
+ }
101
+ finally {
102
+ measurement && measurement.end();
103
+ }
104
+ }
105
+ throw new Error('Unable to name bundle');
106
+ }
107
+ /**
108
+ * Loads configuration for a plugin and tracks its dev dependencies.
109
+ */
110
+ async function loadPluginConfigWithDevDeps(plugin, options, api, previousDevDeps, devDepRequests, configs) {
111
+ const config = (0, InternalConfig_1.createConfig)({
112
+ plugin: plugin.name,
113
+ searchPath: (0, projectPath_1.toProjectPathUnsafe)('index'),
114
+ });
115
+ await (0, ConfigRequest_1.loadPluginConfig)(plugin, config, options);
116
+ await (0, ConfigRequest_1.runConfigRequest)(api, config);
117
+ for (const devDep of config.devDeps) {
118
+ const devDepRequest = await (0, DevDepRequest_1.createDevDependency)(devDep, previousDevDeps, options);
119
+ await runDevDepRequest(api, devDepRequest, devDepRequests);
120
+ }
121
+ configs.set(plugin.name, config);
122
+ }
123
+ /**
124
+ * Runs a dev dependency request and tracks it in the devDepRequests map.
125
+ */
126
+ async function runDevDepRequest(api, devDepRequest, devDepRequests) {
127
+ const { specifier, resolveFrom } = devDepRequest;
128
+ const key = `${specifier}:${(0, projectPath_1.fromProjectPathRelative)(resolveFrom)}`;
129
+ devDepRequests.set(key, devDepRequest);
130
+ await (0, DevDepRequest_1.runDevDepRequest)(api, devDepRequest);
131
+ }
@@ -11,6 +11,8 @@ const DevDepRequest_1 = require("./DevDepRequest");
11
11
  const AtlaspackConfigRequest_1 = __importDefault(require("./AtlaspackConfigRequest"));
12
12
  const EnvironmentManager_1 = require("../EnvironmentManager");
13
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"));
14
16
  function createPackageRequest(input) {
15
17
  return {
16
18
  type: RequestTracker_1.requestTypes.package_request,
@@ -25,23 +27,38 @@ async function run({ input, api, farm, rustAtlaspack }) {
25
27
  let start = Date.now();
26
28
  let { devDeps, invalidDevDeps } = await (0, DevDepRequest_1.getDevDepRequests)(api);
27
29
  let { cachePath } = (0, nullthrows_1.default)(await api.runRequest((0, AtlaspackConfigRequest_1.default)()));
30
+ let packagingResult;
28
31
  if ((0, feature_flags_1.getFeatureFlag)('nativePackager') &&
29
32
  (0, feature_flags_1.getFeatureFlag)('nativePackagerSSRDev') &&
30
33
  rustAtlaspack &&
31
34
  (0, EnvironmentManager_1.fromEnvironmentId)(bundle.env).context === 'tesseract' &&
32
35
  bundle.type === 'js') {
33
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)
34
- await rustAtlaspack.package();
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
+ }));
35
60
  }
36
- let { devDepRequests, configRequests, bundleInfo, invalidations } = (await runPackage({
37
- bundle,
38
- bundleGraphReference,
39
- optionsRef,
40
- configCachePath: cachePath,
41
- previousDevDeps: devDeps,
42
- invalidDevDeps,
43
- previousInvalidations: api.getInvalidations(),
44
- }));
61
+ let { devDepRequests, configRequests, bundleInfo, invalidations } = packagingResult;
45
62
  for (let devDepRequest of devDepRequests) {
46
63
  await (0, DevDepRequest_1.runDevDepRequest)(api, devDepRequest);
47
64
  }
@@ -85,7 +85,7 @@ const bundleGraphEdgeTypes = exports.bundleGraphEdgeTypes = {
85
85
  internal_async: 5,
86
86
  // This type is used to mark an edge between a bundle and a conditional bundle.
87
87
  // This allows efficient discovery of conditional bundles in packaging
88
- conditional: 5
88
+ conditional: 6
89
89
  };
90
90
  function makeReadOnlySet(set) {
91
91
  return new Proxy(set, {
@@ -438,7 +438,7 @@ class BundleGraph {
438
438
 
439
439
  /**
440
440
  * Serialize the bundle graph for efficient transfer to native Rust code.
441
- * Returns a JSON string of nodes and an array of edges.
441
+ * Returns a JSON string of nodes, an array of edges, and a map of asset IDs to public IDs.
442
442
  */
443
443
  serializeForNative() {
444
444
  const start = performance.now();
@@ -452,18 +452,67 @@ class BundleGraph {
452
452
  next = edgeIterator.next();
453
453
  }
454
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
+
455
491
  // Optimize nodes by omitting null/undefined values to reduce JSON size
456
- const optimizedNodes = nodes.map(node => this._omitNulls(node));
492
+ const optimizedNodes = processedNodes.map(node => this._omitNulls(node));
457
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
+ }
458
504
  const duration = performance.now() - start;
459
- const sizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
505
+ const nodesSizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
506
+ const envsSizeMB = (environmentsJson.length / (1024 * 1024)).toFixed(2);
460
507
  _logger().default.verbose({
461
508
  origin: '@atlaspack/core',
462
- message: `serializeForNative: ${duration.toFixed(1)}ms, ${sizeMB}MB JSON, ${nodes.length} nodes, ${edges.length} edges`
509
+ message: `serializeForNative: ${duration.toFixed(1)}ms, ${nodesSizeMB}MB nodes, ${envsSizeMB}MB envs (${environmentMap.size} unique), ${nodes.length} nodes, ${edges.length} edges`
463
510
  });
464
511
  return {
465
512
  nodesJson,
466
- edges
513
+ edges,
514
+ publicIdByAssetId,
515
+ environmentsJson
467
516
  };
468
517
  }
469
518
 
@@ -1152,8 +1201,36 @@ class BundleGraph {
1152
1201
  }
1153
1202
 
1154
1203
  /**
1155
- * TODO: Document why this works like this & why visitor order matters
1156
- * 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)
1157
1234
  */
1158
1235
  traverseBundle(bundle, visit, startAsset) {
1159
1236
  let entries = !startAsset;
@@ -72,15 +72,20 @@ class AtlaspackV3 {
72
72
  buildAssetGraph() {
73
73
  return (0, _rust().atlaspackNapiBuildAssetGraph)(this._atlaspack_napi);
74
74
  }
75
+ buildBundleGraph() {
76
+ return (0, _rust().atlaspackNapiBuildBundleGraph)(this._atlaspack_napi);
77
+ }
75
78
  loadBundleGraph(bundleGraph) {
76
79
  const {
77
80
  nodesJson,
78
- edges
81
+ edges,
82
+ publicIdByAssetId,
83
+ environmentsJson
79
84
  } = bundleGraph.serializeForNative();
80
- return (0, _rust().atlaspackNapiLoadBundleGraph)(this._atlaspack_napi, nodesJson, edges);
85
+ return (0, _rust().atlaspackNapiLoadBundleGraph)(this._atlaspack_napi, nodesJson, edges, publicIdByAssetId, environmentsJson);
81
86
  }
82
- package() {
83
- return (0, _rust().atlaspackNapiPackage)(this._atlaspack_napi);
87
+ package(bundleId) {
88
+ return (0, _rust().atlaspackNapiPackage)(this._atlaspack_napi, bundleId);
84
89
  }
85
90
  async respondToFsEvents(events) {
86
91
  // @ts-expect-error TS2488
@@ -381,7 +381,8 @@ class AtlaspackWorker {
381
381
  setup = {
382
382
  conditions: setupResult === null || setupResult === void 0 ? void 0 : setupResult.conditions,
383
383
  config,
384
- env: allowedEnv
384
+ env: allowedEnv,
385
+ disableCache: setupResult === null || setupResult === void 0 ? void 0 : setupResult.disableCache
385
386
  };
386
387
  }
387
388
  this.#transformers.set(specifier, {