@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 +52 -0
- package/dist/Atlaspack.js +4 -3
- package/dist/BundleGraph.js +134 -3
- package/dist/atlaspack-v3/AtlaspackV3.js +7 -0
- package/dist/requests/AtlaspackBuildRequest.js +17 -0
- package/dist/requests/BundleGraphRequest.js +1 -1
- package/dist/requests/PackageRequest.js +37 -10
- package/dist/resolveOptions.js +1 -1
- package/lib/Atlaspack.js +3 -3
- package/lib/BundleGraph.js +148 -3
- package/lib/atlaspack-v3/AtlaspackV3.js +12 -0
- package/lib/requests/AtlaspackBuildRequest.js +20 -0
- package/lib/requests/BundleGraphRequest.js +1 -1
- package/lib/requests/PackageRequest.js +51 -10
- package/lib/resolveOptions.js +1 -1
- package/lib/types/BundleGraph.d.ts +46 -3
- package/lib/types/atlaspack-v3/AtlaspackV3.d.ts +5 -0
- package/package.json +15 -15
- package/src/Atlaspack.ts +11 -4
- package/src/BundleGraph.ts +149 -3
- package/src/atlaspack-v3/AtlaspackV3.ts +26 -1
- package/src/requests/AtlaspackBuildRequest.ts +23 -0
- package/src/requests/BundleGraphRequest.ts +4 -3
- package/src/requests/PackageRequest.ts +32 -3
- package/src/resolveOptions.ts +2 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -15,6 +15,28 @@ function _nullthrows() {
|
|
|
15
15
|
var _ConfigRequest = require("./ConfigRequest");
|
|
16
16
|
var _DevDepRequest = require("./DevDepRequest");
|
|
17
17
|
var _AtlaspackConfigRequest = _interopRequireDefault(require("./AtlaspackConfigRequest"));
|
|
18
|
+
var _EnvironmentManager = require("../EnvironmentManager");
|
|
19
|
+
function _featureFlags() {
|
|
20
|
+
const data = require("@atlaspack/feature-flags");
|
|
21
|
+
_featureFlags = function () {
|
|
22
|
+
return data;
|
|
23
|
+
};
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
function _logger() {
|
|
27
|
+
const data = _interopRequireDefault(require("@atlaspack/logger"));
|
|
28
|
+
_logger = function () {
|
|
29
|
+
return data;
|
|
30
|
+
};
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
function _diagnostic() {
|
|
34
|
+
const data = _interopRequireDefault(require("@atlaspack/diagnostic"));
|
|
35
|
+
_diagnostic = function () {
|
|
36
|
+
return data;
|
|
37
|
+
};
|
|
38
|
+
return data;
|
|
39
|
+
}
|
|
18
40
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
41
|
function createPackageRequest(input) {
|
|
20
42
|
return {
|
|
@@ -27,7 +49,8 @@ function createPackageRequest(input) {
|
|
|
27
49
|
async function run({
|
|
28
50
|
input,
|
|
29
51
|
api,
|
|
30
|
-
farm
|
|
52
|
+
farm,
|
|
53
|
+
rustAtlaspack
|
|
31
54
|
}) {
|
|
32
55
|
let {
|
|
33
56
|
bundleGraphReference,
|
|
@@ -44,20 +67,38 @@ async function run({
|
|
|
44
67
|
let {
|
|
45
68
|
cachePath
|
|
46
69
|
} = (0, _nullthrows().default)(await api.runRequest((0, _AtlaspackConfigRequest.default)()));
|
|
70
|
+
let packagingResult;
|
|
71
|
+
if ((0, _featureFlags().getFeatureFlag)('nativePackager') && (0, _featureFlags().getFeatureFlag)('nativePackagerSSRDev') && rustAtlaspack && (0, _EnvironmentManager.fromEnvironmentId)(bundle.env).context === 'tesseract' && bundle.type === 'js') {
|
|
72
|
+
// Once this actually does something, the code below will be in an `else` block (i.e. we'll only run one or the other)
|
|
73
|
+
let result = await rustAtlaspack.package(bundle.id);
|
|
74
|
+
let error = null;
|
|
75
|
+
[packagingResult, error] = result;
|
|
76
|
+
if (error) {
|
|
77
|
+
throw new (_diagnostic().default)({
|
|
78
|
+
diagnostic: error
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
_logger().default.verbose({
|
|
82
|
+
message: JSON.stringify(packagingResult, null, 2),
|
|
83
|
+
origin: '@atlaspack/core'
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
packagingResult = await runPackage({
|
|
87
|
+
bundle,
|
|
88
|
+
bundleGraphReference,
|
|
89
|
+
optionsRef,
|
|
90
|
+
configCachePath: cachePath,
|
|
91
|
+
previousDevDeps: devDeps,
|
|
92
|
+
invalidDevDeps,
|
|
93
|
+
previousInvalidations: api.getInvalidations()
|
|
94
|
+
});
|
|
95
|
+
}
|
|
47
96
|
let {
|
|
48
97
|
devDepRequests,
|
|
49
98
|
configRequests,
|
|
50
99
|
bundleInfo,
|
|
51
100
|
invalidations
|
|
52
|
-
} =
|
|
53
|
-
bundle,
|
|
54
|
-
bundleGraphReference,
|
|
55
|
-
optionsRef,
|
|
56
|
-
configCachePath: cachePath,
|
|
57
|
-
previousDevDeps: devDeps,
|
|
58
|
-
invalidDevDeps,
|
|
59
|
-
previousInvalidations: api.getInvalidations()
|
|
60
|
-
});
|
|
101
|
+
} = packagingResult;
|
|
61
102
|
for (let devDepRequest of devDepRequests) {
|
|
62
103
|
await (0, _DevDepRequest.runDevDepRequest)(api, devDepRequest);
|
|
63
104
|
}
|
package/lib/resolveOptions.js
CHANGED
|
@@ -166,7 +166,7 @@ async function resolveOptions(initialOptions) {
|
|
|
166
166
|
if (initialOptions.cache) {
|
|
167
167
|
return initialOptions.cache;
|
|
168
168
|
}
|
|
169
|
-
const needsRustLmdbCache = (0, _featureFlags().getFeatureFlag)('atlaspackV3');
|
|
169
|
+
const needsRustLmdbCache = (0, _featureFlags().getFeatureFlag)('atlaspackV3') || (0, _featureFlags().getFeatureFlag)('nativePackager');
|
|
170
170
|
if (!(0, _featureFlags().getFeatureFlag)('cachePerformanceImprovements')) {
|
|
171
171
|
if (!needsRustLmdbCache && !(outputFS instanceof _fs().NodeFS)) {
|
|
172
172
|
return new (_cache().FSCache)(outputFS, cacheDir);
|
|
@@ -11,7 +11,7 @@ export declare const bundleGraphEdgeTypes: {
|
|
|
11
11
|
readonly bundle: 3;
|
|
12
12
|
readonly references: 4;
|
|
13
13
|
readonly internal_async: 5;
|
|
14
|
-
readonly conditional:
|
|
14
|
+
readonly conditional: 6;
|
|
15
15
|
};
|
|
16
16
|
export type BundleGraphEdgeType = (typeof bundleGraphEdgeTypes)[keyof typeof bundleGraphEdgeTypes];
|
|
17
17
|
type InternalSymbolResolution = {
|
|
@@ -77,6 +77,21 @@ export default class BundleGraph {
|
|
|
77
77
|
static fromAssetGraph(assetGraph: AssetGraph, isProduction: boolean, publicIdByAssetId?: Map<string, string>, assetPublicIds?: Set<string>): BundleGraph;
|
|
78
78
|
serialize(): SerializedBundleGraph;
|
|
79
79
|
static deserialize(serialized: BundleGraphOpts): BundleGraph;
|
|
80
|
+
/**
|
|
81
|
+
* Serialize the bundle graph for efficient transfer to native Rust code.
|
|
82
|
+
* Returns a JSON string of nodes, an array of edges, and a map of asset IDs to public IDs.
|
|
83
|
+
*/
|
|
84
|
+
serializeForNative(): {
|
|
85
|
+
nodesJson: string;
|
|
86
|
+
edges: [number, number, BundleGraphEdgeType][];
|
|
87
|
+
publicIdByAssetId: Record<string, string>;
|
|
88
|
+
environmentsJson: string;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Remove null and undefined values from an object to reduce JSON size.
|
|
92
|
+
* Preserves false, 0, empty strings, and arrays.
|
|
93
|
+
*/
|
|
94
|
+
private _omitNulls;
|
|
80
95
|
createBundle(opts: {
|
|
81
96
|
readonly entryAsset: Asset;
|
|
82
97
|
readonly bundleRoots?: Array<Asset>;
|
|
@@ -135,8 +150,36 @@ export default class BundleGraph {
|
|
|
135
150
|
getParentBundles(bundle: Bundle): Array<Bundle>;
|
|
136
151
|
isAssetReachableFromBundle(asset: Asset, bundle: Bundle): boolean;
|
|
137
152
|
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
153
|
+
* Performs a depth-first traversal of all assets and dependencies contained
|
|
154
|
+
* within a bundle. Only visits nodes that are directly contained in the bundle
|
|
155
|
+
* (connected via a `contains` edge).
|
|
156
|
+
*
|
|
157
|
+
* Entry Asset Ordering:
|
|
158
|
+
* The traversal guarantees that entry assets are visited in the exact order they
|
|
159
|
+
* appear in `bundle.entryAssetIds`. This ordering is critical for several reasons:
|
|
160
|
+
*
|
|
161
|
+
* 1. **Code Execution Order in Packagers**: Packagers (ScopeHoistingPackager,
|
|
162
|
+
* DevPackager) use this traversal to concatenate assets into the final bundle.
|
|
163
|
+
* The traversal order determines the execution order of code in the output.
|
|
164
|
+
* Entry assets must be processed in their defined order to ensure correct
|
|
165
|
+
* initialization sequences.
|
|
166
|
+
*
|
|
167
|
+
* 2. **Runtime Injection**: Runtime assets (HMR, bundle manifests) are prepended
|
|
168
|
+
* to `entryAssetIds` via `unshift()` in `applyRuntimes.ts`. By honoring the
|
|
169
|
+
* array order, runtimes are guaranteed to be visited (and thus output) before
|
|
170
|
+
* application entry points, ensuring the runtime infrastructure is available
|
|
171
|
+
* when application code executes.
|
|
172
|
+
*
|
|
173
|
+
* 3. **Deterministic Builds**: Consistent traversal order ensures reproducible
|
|
174
|
+
* bundle output, which is essential for caching and build verification.
|
|
175
|
+
*
|
|
176
|
+
* The sorting only applies at the first traversal level (direct children of the
|
|
177
|
+
* start node). Subsequent levels follow standard DFS order based on the graph's
|
|
178
|
+
* edge structure.
|
|
179
|
+
*
|
|
180
|
+
* @param bundle - The bundle to traverse
|
|
181
|
+
* @param visit - Visitor callback receiving asset or dependency nodes
|
|
182
|
+
* @param startAsset - Optional asset to start traversal from (defaults to bundle root)
|
|
140
183
|
*/
|
|
141
184
|
traverseBundle<TContext>(bundle: Bundle, visit: GraphVisitor<AssetNode | DependencyNode, TContext>, startAsset?: Asset): TContext | null | undefined;
|
|
142
185
|
traverse<TContext>(visit: GraphVisitor<AssetNode | DependencyNode, TContext>, start?: Asset): TContext | null | undefined;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { AtlaspackNapi, Lmdb, AtlaspackNapiOptions, CacheStats } from '@atlaspack/rust';
|
|
2
|
+
import { Diagnostic } from '@atlaspack/diagnostic';
|
|
2
3
|
import type { Event } from '@parcel/watcher';
|
|
3
4
|
import type { NapiWorkerPool as INapiWorkerPool } from '@atlaspack/types';
|
|
5
|
+
import type BundleGraph from '../BundleGraph';
|
|
6
|
+
import { RunPackagerRunnerResult } from '../PackagerRunner';
|
|
4
7
|
export type AtlaspackV3Options = {
|
|
5
8
|
fs?: AtlaspackNapiOptions['fs'];
|
|
6
9
|
packageManager?: AtlaspackNapiOptions['packageManager'];
|
|
@@ -22,6 +25,8 @@ export declare class AtlaspackV3 {
|
|
|
22
25
|
static create({ fs, packageManager, threads, lmdb, napiWorkerPool, ...options }: AtlaspackV3Options): Promise<AtlaspackV3>;
|
|
23
26
|
end(): void;
|
|
24
27
|
buildAssetGraph(): Promise<any>;
|
|
28
|
+
loadBundleGraph(bundleGraph: BundleGraph): Promise<void>;
|
|
29
|
+
package(bundleId: string): Promise<[RunPackagerRunnerResult, Diagnostic | null]>;
|
|
25
30
|
respondToFsEvents(events: Array<Event>): Promise<boolean>;
|
|
26
31
|
completeCacheSession(): Promise<CacheStats>;
|
|
27
32
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaspack/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.32.1",
|
|
4
4
|
"license": "(MIT OR Apache-2.0)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -23,22 +23,22 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@mischnic/json-sourcemap": "^0.1.0",
|
|
26
|
-
"@atlaspack/build-cache": "2.13.
|
|
27
|
-
"@atlaspack/cache": "3.2.
|
|
26
|
+
"@atlaspack/build-cache": "2.13.9",
|
|
27
|
+
"@atlaspack/cache": "3.2.46",
|
|
28
28
|
"@atlaspack/diagnostic": "2.14.4",
|
|
29
29
|
"@atlaspack/events": "2.14.4",
|
|
30
|
-
"@atlaspack/feature-flags": "2.
|
|
31
|
-
"@atlaspack/fs": "2.15.
|
|
32
|
-
"@atlaspack/graph": "3.6.
|
|
33
|
-
"@atlaspack/logger": "2.14.
|
|
34
|
-
"@atlaspack/package-manager": "2.14.
|
|
35
|
-
"@atlaspack/plugin": "2.14.
|
|
36
|
-
"@atlaspack/profiler": "2.15.
|
|
37
|
-
"@atlaspack/rust": "3.
|
|
38
|
-
"@atlaspack/types": "2.15.
|
|
39
|
-
"@atlaspack/utils": "3.3.
|
|
40
|
-
"@atlaspack/workers": "2.14.
|
|
41
|
-
"@atlaspack/source-map": "3.2.
|
|
30
|
+
"@atlaspack/feature-flags": "2.28.0",
|
|
31
|
+
"@atlaspack/fs": "2.15.46",
|
|
32
|
+
"@atlaspack/graph": "3.6.13",
|
|
33
|
+
"@atlaspack/logger": "2.14.43",
|
|
34
|
+
"@atlaspack/package-manager": "2.14.51",
|
|
35
|
+
"@atlaspack/plugin": "2.14.51",
|
|
36
|
+
"@atlaspack/profiler": "2.15.12",
|
|
37
|
+
"@atlaspack/rust": "3.21.0",
|
|
38
|
+
"@atlaspack/types": "2.15.41",
|
|
39
|
+
"@atlaspack/utils": "3.3.3",
|
|
40
|
+
"@atlaspack/workers": "2.14.51",
|
|
41
|
+
"@atlaspack/source-map": "3.2.6",
|
|
42
42
|
"base-x": "^3.0.8",
|
|
43
43
|
"browserslist": "^4.6.6",
|
|
44
44
|
"clone": "^2.1.1",
|
package/src/Atlaspack.ts
CHANGED
|
@@ -58,7 +58,11 @@ import {
|
|
|
58
58
|
fromProjectPathRelative,
|
|
59
59
|
} from './projectPath';
|
|
60
60
|
import {tracer, NativeProfiler} from '@atlaspack/profiler';
|
|
61
|
-
import {
|
|
61
|
+
import {
|
|
62
|
+
setFeatureFlags,
|
|
63
|
+
DEFAULT_FEATURE_FLAGS,
|
|
64
|
+
getFeatureFlag,
|
|
65
|
+
} from '@atlaspack/feature-flags';
|
|
62
66
|
import {AtlaspackV3, FileSystemV3} from './atlaspack-v3';
|
|
63
67
|
import createAssetGraphRequestJS from './requests/AssetGraphRequest';
|
|
64
68
|
import {createAssetGraphRequestRust} from './requests/AssetGraphRequestRust';
|
|
@@ -165,7 +169,10 @@ export default class Atlaspack {
|
|
|
165
169
|
this.#resolvedOptions = resolvedOptions;
|
|
166
170
|
|
|
167
171
|
let rustAtlaspack: AtlaspackV3;
|
|
168
|
-
if (
|
|
172
|
+
if (
|
|
173
|
+
resolvedOptions.featureFlags.atlaspackV3 ||
|
|
174
|
+
resolvedOptions.featureFlags.nativePackager
|
|
175
|
+
) {
|
|
169
176
|
// eslint-disable-next-line no-unused-vars
|
|
170
177
|
let {entries, inputFS, outputFS, ...options} = this.#initialOptions;
|
|
171
178
|
|
|
@@ -585,7 +592,7 @@ export default class Atlaspack {
|
|
|
585
592
|
});
|
|
586
593
|
|
|
587
594
|
let nativeInvalid = false;
|
|
588
|
-
if (this.rustAtlaspack) {
|
|
595
|
+
if (getFeatureFlag('atlaspackV3') && this.rustAtlaspack) {
|
|
589
596
|
nativeInvalid = await this.rustAtlaspack.respondToFsEvents(events);
|
|
590
597
|
}
|
|
591
598
|
|
|
@@ -681,7 +688,7 @@ export default class Atlaspack {
|
|
|
681
688
|
|
|
682
689
|
const start = Date.now();
|
|
683
690
|
const result = await this.#requestTracker.runRequest(
|
|
684
|
-
this.rustAtlaspack != null
|
|
691
|
+
getFeatureFlag('atlaspackV3') && this.rustAtlaspack != null
|
|
685
692
|
? // @ts-expect-error TS2345
|
|
686
693
|
createAssetGraphRequestRust(this.rustAtlaspack)(input)
|
|
687
694
|
: // @ts-expect-error TS2345
|
package/src/BundleGraph.ts
CHANGED
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
BundleNode,
|
|
23
23
|
Dependency,
|
|
24
24
|
DependencyNode,
|
|
25
|
+
Environment,
|
|
25
26
|
InternalSourceLocation,
|
|
26
27
|
Target,
|
|
27
28
|
Condition,
|
|
@@ -46,6 +47,7 @@ import {ISOLATED_ENVS} from './public/Environment';
|
|
|
46
47
|
import {fromProjectPath, fromProjectPathRelative} from './projectPath';
|
|
47
48
|
import {HASH_REF_PREFIX} from './constants';
|
|
48
49
|
import {getFeatureFlag} from '@atlaspack/feature-flags';
|
|
50
|
+
import logger from '@atlaspack/logger';
|
|
49
51
|
import {fromEnvironmentId} from './EnvironmentManager';
|
|
50
52
|
import type {EnvironmentRef} from './EnvironmentManager';
|
|
51
53
|
|
|
@@ -74,7 +76,7 @@ export const bundleGraphEdgeTypes = {
|
|
|
74
76
|
internal_async: 5,
|
|
75
77
|
// This type is used to mark an edge between a bundle and a conditional bundle.
|
|
76
78
|
// This allows efficient discovery of conditional bundles in packaging
|
|
77
|
-
conditional:
|
|
79
|
+
conditional: 6,
|
|
78
80
|
} as const;
|
|
79
81
|
|
|
80
82
|
export type BundleGraphEdgeType =
|
|
@@ -571,6 +573,122 @@ export default class BundleGraph {
|
|
|
571
573
|
});
|
|
572
574
|
}
|
|
573
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Serialize the bundle graph for efficient transfer to native Rust code.
|
|
578
|
+
* Returns a JSON string of nodes, an array of edges, and a map of asset IDs to public IDs.
|
|
579
|
+
*/
|
|
580
|
+
serializeForNative(): {
|
|
581
|
+
nodesJson: string;
|
|
582
|
+
edges: [number, number, BundleGraphEdgeType][];
|
|
583
|
+
publicIdByAssetId: Record<string, string>;
|
|
584
|
+
environmentsJson: string;
|
|
585
|
+
} {
|
|
586
|
+
const start = performance.now();
|
|
587
|
+
|
|
588
|
+
const nodes = this._graph.nodes as BundleGraphNode[];
|
|
589
|
+
const edges: [number, number, BundleGraphEdgeType][] = [];
|
|
590
|
+
|
|
591
|
+
const edgeIterator = this._graph.getAllEdges();
|
|
592
|
+
let next = edgeIterator.next();
|
|
593
|
+
while (!next.done) {
|
|
594
|
+
const edge = next.value;
|
|
595
|
+
edges.push([edge.from, edge.to, edge.type]);
|
|
596
|
+
next = edgeIterator.next();
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Extract and deduplicate environments
|
|
600
|
+
const environmentMap = new Map<string, Environment>();
|
|
601
|
+
const extractEnvironment = (envRef: EnvironmentRef): string => {
|
|
602
|
+
const env = fromEnvironmentId(envRef);
|
|
603
|
+
const envId = env.id;
|
|
604
|
+
if (!environmentMap.has(envId)) {
|
|
605
|
+
environmentMap.set(envId, env);
|
|
606
|
+
}
|
|
607
|
+
return envId;
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// Replace env objects with env IDs in nodes
|
|
611
|
+
const processedNodes = nodes.map((node) => {
|
|
612
|
+
const processedNode = {...node};
|
|
613
|
+
if (node.type === 'asset' && node.value?.env) {
|
|
614
|
+
processedNode.value = {
|
|
615
|
+
...node.value,
|
|
616
|
+
env: extractEnvironment(node.value.env),
|
|
617
|
+
};
|
|
618
|
+
} else if (node.type === 'dependency' && node.value?.env) {
|
|
619
|
+
processedNode.value = {
|
|
620
|
+
...node.value,
|
|
621
|
+
env: extractEnvironment(node.value.env),
|
|
622
|
+
};
|
|
623
|
+
} else if (node.type === 'bundle' && node.value?.env) {
|
|
624
|
+
processedNode.value = {
|
|
625
|
+
...node.value,
|
|
626
|
+
env: extractEnvironment(node.value.env),
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
return processedNode;
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
// Optimize nodes by omitting null/undefined values to reduce JSON size
|
|
633
|
+
const optimizedNodes = processedNodes.map((node) => this._omitNulls(node));
|
|
634
|
+
const nodesJson = JSON.stringify(optimizedNodes);
|
|
635
|
+
|
|
636
|
+
// Serialize environments as array
|
|
637
|
+
const environments = Array.from(environmentMap.values());
|
|
638
|
+
const environmentsJson = JSON.stringify(environments);
|
|
639
|
+
|
|
640
|
+
// Convert Map to plain object for serialization
|
|
641
|
+
const publicIdByAssetId: Record<string, string> = {};
|
|
642
|
+
for (const [assetId, publicId] of this._publicIdByAssetId) {
|
|
643
|
+
publicIdByAssetId[assetId] = publicId;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const duration = performance.now() - start;
|
|
647
|
+
const nodesSizeMB = (nodesJson.length / (1024 * 1024)).toFixed(2);
|
|
648
|
+
const envsSizeMB = (environmentsJson.length / (1024 * 1024)).toFixed(2);
|
|
649
|
+
logger.verbose({
|
|
650
|
+
origin: '@atlaspack/core',
|
|
651
|
+
message: `serializeForNative: ${duration.toFixed(1)}ms, ${nodesSizeMB}MB nodes, ${envsSizeMB}MB envs (${environmentMap.size} unique), ${nodes.length} nodes, ${edges.length} edges`,
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
return {nodesJson, edges, publicIdByAssetId, environmentsJson};
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Remove null and undefined values from an object to reduce JSON size.
|
|
659
|
+
* Preserves false, 0, empty strings, and arrays.
|
|
660
|
+
*/
|
|
661
|
+
private _omitNulls(obj: unknown): unknown {
|
|
662
|
+
if (obj === null || obj === undefined) return obj;
|
|
663
|
+
if (typeof obj !== 'object') return obj;
|
|
664
|
+
if (Array.isArray(obj)) {
|
|
665
|
+
return obj.map((item) => this._omitNulls(item));
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
const result: Record<string, unknown> = {};
|
|
669
|
+
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
|
670
|
+
if (value === null || value === undefined) {
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (
|
|
674
|
+
typeof value === 'object' &&
|
|
675
|
+
!Array.isArray(value) &&
|
|
676
|
+
Object.keys(value as object).length === 0
|
|
677
|
+
) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (typeof value === 'object') {
|
|
681
|
+
const processed = this._omitNulls(value);
|
|
682
|
+
if (processed !== undefined) {
|
|
683
|
+
result[key] = processed;
|
|
684
|
+
}
|
|
685
|
+
} else {
|
|
686
|
+
result[key] = value;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return result;
|
|
690
|
+
}
|
|
691
|
+
|
|
574
692
|
createBundle(
|
|
575
693
|
opts:
|
|
576
694
|
| {
|
|
@@ -1702,8 +1820,36 @@ export default class BundleGraph {
|
|
|
1702
1820
|
}
|
|
1703
1821
|
|
|
1704
1822
|
/**
|
|
1705
|
-
*
|
|
1706
|
-
*
|
|
1823
|
+
* Performs a depth-first traversal of all assets and dependencies contained
|
|
1824
|
+
* within a bundle. Only visits nodes that are directly contained in the bundle
|
|
1825
|
+
* (connected via a `contains` edge).
|
|
1826
|
+
*
|
|
1827
|
+
* Entry Asset Ordering:
|
|
1828
|
+
* The traversal guarantees that entry assets are visited in the exact order they
|
|
1829
|
+
* appear in `bundle.entryAssetIds`. This ordering is critical for several reasons:
|
|
1830
|
+
*
|
|
1831
|
+
* 1. **Code Execution Order in Packagers**: Packagers (ScopeHoistingPackager,
|
|
1832
|
+
* DevPackager) use this traversal to concatenate assets into the final bundle.
|
|
1833
|
+
* The traversal order determines the execution order of code in the output.
|
|
1834
|
+
* Entry assets must be processed in their defined order to ensure correct
|
|
1835
|
+
* initialization sequences.
|
|
1836
|
+
*
|
|
1837
|
+
* 2. **Runtime Injection**: Runtime assets (HMR, bundle manifests) are prepended
|
|
1838
|
+
* to `entryAssetIds` via `unshift()` in `applyRuntimes.ts`. By honoring the
|
|
1839
|
+
* array order, runtimes are guaranteed to be visited (and thus output) before
|
|
1840
|
+
* application entry points, ensuring the runtime infrastructure is available
|
|
1841
|
+
* when application code executes.
|
|
1842
|
+
*
|
|
1843
|
+
* 3. **Deterministic Builds**: Consistent traversal order ensures reproducible
|
|
1844
|
+
* bundle output, which is essential for caching and build verification.
|
|
1845
|
+
*
|
|
1846
|
+
* The sorting only applies at the first traversal level (direct children of the
|
|
1847
|
+
* start node). Subsequent levels follow standard DFS order based on the graph's
|
|
1848
|
+
* edge structure.
|
|
1849
|
+
*
|
|
1850
|
+
* @param bundle - The bundle to traverse
|
|
1851
|
+
* @param visit - Visitor callback receiving asset or dependency nodes
|
|
1852
|
+
* @param startAsset - Optional asset to start traversal from (defaults to bundle root)
|
|
1707
1853
|
*/
|
|
1708
1854
|
traverseBundle<TContext>(
|
|
1709
1855
|
bundle: Bundle,
|
|
@@ -3,15 +3,19 @@ import {
|
|
|
3
3
|
atlaspackNapiBuildAssetGraph,
|
|
4
4
|
atlaspackNapiRespondToFsEvents,
|
|
5
5
|
atlaspackNapiCompleteSession,
|
|
6
|
+
atlaspackNapiLoadBundleGraph,
|
|
7
|
+
atlaspackNapiPackage,
|
|
6
8
|
AtlaspackNapi,
|
|
7
9
|
Lmdb,
|
|
8
10
|
AtlaspackNapiOptions,
|
|
9
11
|
CacheStats,
|
|
10
12
|
} from '@atlaspack/rust';
|
|
11
13
|
import {NapiWorkerPool} from './NapiWorkerPool';
|
|
12
|
-
import ThrowableDiagnostic from '@atlaspack/diagnostic';
|
|
14
|
+
import ThrowableDiagnostic, {Diagnostic} from '@atlaspack/diagnostic';
|
|
13
15
|
import type {Event} from '@parcel/watcher';
|
|
14
16
|
import type {NapiWorkerPool as INapiWorkerPool} from '@atlaspack/types';
|
|
17
|
+
import type BundleGraph from '../BundleGraph';
|
|
18
|
+
import {RunPackagerRunnerResult} from '../PackagerRunner';
|
|
15
19
|
|
|
16
20
|
export type AtlaspackV3Options = {
|
|
17
21
|
fs?: AtlaspackNapiOptions['fs'];
|
|
@@ -97,6 +101,27 @@ 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, publicIdByAssetId, environmentsJson} =
|
|
106
|
+
bundleGraph.serializeForNative();
|
|
107
|
+
|
|
108
|
+
return atlaspackNapiLoadBundleGraph(
|
|
109
|
+
this._atlaspack_napi,
|
|
110
|
+
nodesJson,
|
|
111
|
+
edges,
|
|
112
|
+
publicIdByAssetId,
|
|
113
|
+
environmentsJson,
|
|
114
|
+
) as Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
package(
|
|
118
|
+
bundleId: string,
|
|
119
|
+
): Promise<[RunPackagerRunnerResult, Diagnostic | null]> {
|
|
120
|
+
return atlaspackNapiPackage(this._atlaspack_napi, bundleId) as Promise<
|
|
121
|
+
[RunPackagerRunnerResult, Diagnostic | null]
|
|
122
|
+
>;
|
|
123
|
+
}
|
|
124
|
+
|
|
100
125
|
async respondToFsEvents(events: Array<Event>): Promise<boolean> {
|
|
101
126
|
// @ts-expect-error TS2488
|
|
102
127
|
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 =
|
|
145
|
-
|
|
146
|
-
|
|
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,10 @@ 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';
|
|
18
|
+
import logger from '@atlaspack/logger';
|
|
19
|
+
import ThrowableDiagnostic, {Diagnostic} from '@atlaspack/diagnostic';
|
|
16
20
|
|
|
17
21
|
type PackageRequestInput = {
|
|
18
22
|
bundleGraph: BundleGraph;
|
|
@@ -46,8 +50,9 @@ export function createPackageRequest(
|
|
|
46
50
|
};
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
async function run({input, api, farm}: RunInput<BundleInfo>) {
|
|
53
|
+
async function run({input, api, farm, rustAtlaspack}: RunInput<BundleInfo>) {
|
|
50
54
|
let {bundleGraphReference, optionsRef, bundle, useMainThread} = input;
|
|
55
|
+
|
|
51
56
|
let runPackage = farm.createHandle('runPackage', useMainThread);
|
|
52
57
|
|
|
53
58
|
let start = Date.now();
|
|
@@ -58,8 +63,29 @@ async function run({input, api, farm}: RunInput<BundleInfo>) {
|
|
|
58
63
|
),
|
|
59
64
|
);
|
|
60
65
|
|
|
61
|
-
let
|
|
62
|
-
|
|
66
|
+
let packagingResult: RunPackagerRunnerResult;
|
|
67
|
+
if (
|
|
68
|
+
getFeatureFlag('nativePackager') &&
|
|
69
|
+
getFeatureFlag('nativePackagerSSRDev') &&
|
|
70
|
+
rustAtlaspack &&
|
|
71
|
+
fromEnvironmentId(bundle.env).context === 'tesseract' &&
|
|
72
|
+
bundle.type === 'js'
|
|
73
|
+
) {
|
|
74
|
+
// Once this actually does something, the code below will be in an `else` block (i.e. we'll only run one or the other)
|
|
75
|
+
let result = await rustAtlaspack.package(bundle.id);
|
|
76
|
+
let error: Diagnostic | null = null;
|
|
77
|
+
[packagingResult, error] = result;
|
|
78
|
+
if (error) {
|
|
79
|
+
throw new ThrowableDiagnostic({
|
|
80
|
+
diagnostic: error,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
logger.verbose({
|
|
84
|
+
message: JSON.stringify(packagingResult, null, 2),
|
|
85
|
+
origin: '@atlaspack/core',
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
packagingResult = (await runPackage({
|
|
63
89
|
bundle,
|
|
64
90
|
bundleGraphReference,
|
|
65
91
|
optionsRef,
|
|
@@ -68,7 +94,10 @@ async function run({input, api, farm}: RunInput<BundleInfo>) {
|
|
|
68
94
|
invalidDevDeps,
|
|
69
95
|
previousInvalidations: api.getInvalidations(),
|
|
70
96
|
})) as RunPackagerRunnerResult;
|
|
97
|
+
}
|
|
71
98
|
|
|
99
|
+
let {devDepRequests, configRequests, bundleInfo, invalidations} =
|
|
100
|
+
packagingResult;
|
|
72
101
|
for (let devDepRequest of devDepRequests) {
|
|
73
102
|
await runDevDepRequest(api, devDepRequest);
|
|
74
103
|
}
|
package/src/resolveOptions.ts
CHANGED
|
@@ -181,7 +181,8 @@ export default async function resolveOptions(
|
|
|
181
181
|
return initialOptions.cache;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
const needsRustLmdbCache =
|
|
184
|
+
const needsRustLmdbCache =
|
|
185
|
+
getFeatureFlag('atlaspackV3') || getFeatureFlag('nativePackager');
|
|
185
186
|
|
|
186
187
|
if (!getFeatureFlag('cachePerformanceImprovements')) {
|
|
187
188
|
if (!needsRustLmdbCache && !(outputFS instanceof NodeFS)) {
|