@atlaspack/core 2.12.1-canary.3354

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 (215) hide show
  1. package/LICENSE +201 -0
  2. package/index.d.ts +22 -0
  3. package/lib/AssetGraph.js +518 -0
  4. package/lib/Atlaspack.js +587 -0
  5. package/lib/AtlaspackConfig.js +298 -0
  6. package/lib/AtlaspackConfig.schema.js +125 -0
  7. package/lib/BundleGraph.js +1445 -0
  8. package/lib/CommittedAsset.js +133 -0
  9. package/lib/Dependency.js +88 -0
  10. package/lib/Environment.js +128 -0
  11. package/lib/InternalConfig.js +48 -0
  12. package/lib/PackagerRunner.js +519 -0
  13. package/lib/ReporterRunner.js +151 -0
  14. package/lib/RequestTracker.js +1089 -0
  15. package/lib/SymbolPropagation.js +625 -0
  16. package/lib/TargetDescriptor.schema.js +115 -0
  17. package/lib/Transformation.js +536 -0
  18. package/lib/UncommittedAsset.js +342 -0
  19. package/lib/Validation.js +215 -0
  20. package/lib/applyRuntimes.js +279 -0
  21. package/lib/assetUtils.js +189 -0
  22. package/lib/atlaspack-v3/AtlaspackV3.js +74 -0
  23. package/lib/atlaspack-v3/fs.js +30 -0
  24. package/lib/atlaspack-v3/index.js +19 -0
  25. package/lib/atlaspack-v3/jsCallable.js +15 -0
  26. package/lib/atlaspack-v3/plugins/Resolver.js +12 -0
  27. package/lib/atlaspack-v3/plugins/index.js +16 -0
  28. package/lib/atlaspack-v3/worker/index.js +3 -0
  29. package/lib/atlaspack-v3/worker/worker.js +30 -0
  30. package/lib/buildCache.js +18 -0
  31. package/lib/constants.js +21 -0
  32. package/lib/dumpGraphToGraphViz.js +206 -0
  33. package/lib/index.js +106 -0
  34. package/lib/loadAtlaspackPlugin.js +148 -0
  35. package/lib/loadDotEnv.js +54 -0
  36. package/lib/projectPath.js +86 -0
  37. package/lib/public/Asset.js +259 -0
  38. package/lib/public/Bundle.js +231 -0
  39. package/lib/public/BundleGraph.js +193 -0
  40. package/lib/public/BundleGroup.js +44 -0
  41. package/lib/public/Config.js +202 -0
  42. package/lib/public/Dependency.js +131 -0
  43. package/lib/public/Environment.js +244 -0
  44. package/lib/public/MutableBundleGraph.js +184 -0
  45. package/lib/public/PluginOptions.js +71 -0
  46. package/lib/public/Symbols.js +247 -0
  47. package/lib/public/Target.js +64 -0
  48. package/lib/registerCoreWithSerializer.js +45 -0
  49. package/lib/requests/AssetGraphRequest.js +427 -0
  50. package/lib/requests/AssetGraphRequestRust.js +187 -0
  51. package/lib/requests/AssetRequest.js +137 -0
  52. package/lib/requests/AtlaspackBuildRequest.js +78 -0
  53. package/lib/requests/AtlaspackConfigRequest.js +473 -0
  54. package/lib/requests/BundleGraphRequest.js +419 -0
  55. package/lib/requests/ConfigRequest.js +198 -0
  56. package/lib/requests/DevDepRequest.js +166 -0
  57. package/lib/requests/EntryRequest.js +295 -0
  58. package/lib/requests/PackageRequest.js +88 -0
  59. package/lib/requests/PathRequest.js +349 -0
  60. package/lib/requests/TargetRequest.js +1177 -0
  61. package/lib/requests/ValidationRequest.js +66 -0
  62. package/lib/requests/WriteBundleRequest.js +252 -0
  63. package/lib/requests/WriteBundlesRequest.js +153 -0
  64. package/lib/resolveOptions.js +234 -0
  65. package/lib/serializer.js +216 -0
  66. package/lib/serializerCore.browser.js +29 -0
  67. package/lib/serializerCore.js +16 -0
  68. package/lib/summarizeRequest.js +55 -0
  69. package/lib/types.js +35 -0
  70. package/lib/utils.js +160 -0
  71. package/lib/worker.js +170 -0
  72. package/package.json +59 -0
  73. package/src/AssetGraph.js +646 -0
  74. package/src/Atlaspack.js +632 -0
  75. package/src/AtlaspackConfig.js +490 -0
  76. package/src/AtlaspackConfig.schema.js +141 -0
  77. package/src/BundleGraph.js +2193 -0
  78. package/src/CommittedAsset.js +143 -0
  79. package/src/Dependency.js +142 -0
  80. package/src/Environment.js +151 -0
  81. package/src/InternalConfig.js +72 -0
  82. package/src/PackagerRunner.js +790 -0
  83. package/src/ReporterRunner.js +158 -0
  84. package/src/RequestTracker.js +1697 -0
  85. package/src/SymbolPropagation.js +794 -0
  86. package/src/TargetDescriptor.schema.js +136 -0
  87. package/src/Transformation.js +752 -0
  88. package/src/UncommittedAsset.js +426 -0
  89. package/src/Validation.js +223 -0
  90. package/src/applyRuntimes.js +341 -0
  91. package/src/assetUtils.js +254 -0
  92. package/src/atlaspack-v3/AtlaspackV3.js +73 -0
  93. package/src/atlaspack-v3/fs.js +36 -0
  94. package/src/atlaspack-v3/index.js +5 -0
  95. package/src/atlaspack-v3/jsCallable.js +13 -0
  96. package/src/atlaspack-v3/plugins/Resolver.js +9 -0
  97. package/src/atlaspack-v3/plugins/index.js +3 -0
  98. package/src/atlaspack-v3/worker/index.js +8 -0
  99. package/src/atlaspack-v3/worker/worker.js +14 -0
  100. package/src/buildCache.js +15 -0
  101. package/src/constants.js +22 -0
  102. package/src/dumpGraphToGraphViz.js +244 -0
  103. package/src/index.js +22 -0
  104. package/src/loadAtlaspackPlugin.js +239 -0
  105. package/src/loadDotEnv.js +56 -0
  106. package/src/projectPath.js +87 -0
  107. package/src/public/Asset.js +359 -0
  108. package/src/public/Bundle.js +337 -0
  109. package/src/public/BundleGraph.js +335 -0
  110. package/src/public/BundleGroup.js +55 -0
  111. package/src/public/Config.js +261 -0
  112. package/src/public/Dependency.js +176 -0
  113. package/src/public/Environment.js +316 -0
  114. package/src/public/MutableBundleGraph.js +320 -0
  115. package/src/public/PluginOptions.js +99 -0
  116. package/src/public/Symbols.js +315 -0
  117. package/src/public/Target.js +71 -0
  118. package/src/registerCoreWithSerializer.js +34 -0
  119. package/src/requests/AssetGraphRequest.js +577 -0
  120. package/src/requests/AssetGraphRequestRust.js +222 -0
  121. package/src/requests/AssetRequest.js +179 -0
  122. package/src/requests/AtlaspackBuildRequest.js +109 -0
  123. package/src/requests/AtlaspackConfigRequest.js +709 -0
  124. package/src/requests/BundleGraphRequest.js +547 -0
  125. package/src/requests/ConfigRequest.js +287 -0
  126. package/src/requests/DevDepRequest.js +246 -0
  127. package/src/requests/EntryRequest.js +385 -0
  128. package/src/requests/PackageRequest.js +105 -0
  129. package/src/requests/PathRequest.js +454 -0
  130. package/src/requests/TargetRequest.js +1632 -0
  131. package/src/requests/ValidationRequest.js +79 -0
  132. package/src/requests/WriteBundleRequest.js +362 -0
  133. package/src/requests/WriteBundlesRequest.js +209 -0
  134. package/src/resolveOptions.js +278 -0
  135. package/src/serializer.js +255 -0
  136. package/src/serializerCore.browser.js +8 -0
  137. package/src/serializerCore.js +5 -0
  138. package/src/summarizeRequest.js +47 -0
  139. package/src/types.js +581 -0
  140. package/src/utils.js +211 -0
  141. package/src/worker.js +189 -0
  142. package/test/AssetGraph.test.js +679 -0
  143. package/test/Atlaspack.test.js +142 -0
  144. package/test/AtlaspackConfig.test.js +405 -0
  145. package/test/AtlaspackConfigRequest.test.js +993 -0
  146. package/test/BundleGraph.test.js +121 -0
  147. package/test/EntryRequest.test.js +215 -0
  148. package/test/Environment.test.js +99 -0
  149. package/test/InternalAsset.test.js +76 -0
  150. package/test/PackagerRunner.test.js +27 -0
  151. package/test/PublicAsset.test.js +40 -0
  152. package/test/PublicBundle.test.js +68 -0
  153. package/test/PublicDependency.test.js +22 -0
  154. package/test/PublicEnvironment.test.js +27 -0
  155. package/test/PublicMutableBundleGraph.test.js +192 -0
  156. package/test/RequestTracker.test.js +448 -0
  157. package/test/SymbolPropagation.test.js +716 -0
  158. package/test/TargetRequest.test.js +1715 -0
  159. package/test/fixtures/application-targets/package.json +3 -0
  160. package/test/fixtures/atlaspack/index.js +1 -0
  161. package/test/fixtures/atlaspack/other.js +3 -0
  162. package/test/fixtures/atlaspack/package.json +1 -0
  163. package/test/fixtures/atlaspack/yarn.lock +0 -0
  164. package/test/fixtures/bundle.js +10 -0
  165. package/test/fixtures/common-targets/package.json +24 -0
  166. package/test/fixtures/common-targets-ignore/package.json +13 -0
  167. package/test/fixtures/config/.atlaspackrc +6 -0
  168. package/test/fixtures/config/subfolder/.atlaspackrc +6 -0
  169. package/test/fixtures/config-extends-not-found/.atlaspackrc +3 -0
  170. package/test/fixtures/config-extends-not-found/.atlaspackrc-json5 +3 -0
  171. package/test/fixtures/config-extends-not-found/.atlaspackrc-multiple +3 -0
  172. package/test/fixtures/config-extends-not-found/.atlaspackrc-node-modules +3 -0
  173. package/test/fixtures/config-malformed/.atlaspackrc +3 -0
  174. package/test/fixtures/config-node-pipeline/.atlaspackrc +6 -0
  175. package/test/fixtures/config-plugin-not-found/.atlaspackrc +6 -0
  176. package/test/fixtures/context/package.json +8 -0
  177. package/test/fixtures/custom-format-infer-ext/package.json +6 -0
  178. package/test/fixtures/custom-format-infer-type/package.json +7 -0
  179. package/test/fixtures/custom-format-mismatch/package.json +8 -0
  180. package/test/fixtures/custom-targets/package.json +20 -0
  181. package/test/fixtures/custom-targets-distdir/package.json +11 -0
  182. package/test/fixtures/duplicate-targets/package.json +4 -0
  183. package/test/fixtures/glob-like/[entry].js +0 -0
  184. package/test/fixtures/invalid-distpath/package.json +11 -0
  185. package/test/fixtures/invalid-engines/package.json +12 -0
  186. package/test/fixtures/invalid-source-missing/package.json +5 -0
  187. package/test/fixtures/invalid-source-not-file/package.json +5 -0
  188. package/test/fixtures/invalid-source-not-file/src/index.js +1 -0
  189. package/test/fixtures/invalid-target-source-missing/package.json +9 -0
  190. package/test/fixtures/invalid-target-source-not-file/package.json +9 -0
  191. package/test/fixtures/invalid-target-source-not-file/src/index.js +1 -0
  192. package/test/fixtures/invalid-targets/package.json +19 -0
  193. package/test/fixtures/library-custom-scopehoist/package.json +9 -0
  194. package/test/fixtures/library-scopehoist/package.json +8 -0
  195. package/test/fixtures/local-plugin-config-pkg/.atlaspackrc +3 -0
  196. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/index.json +8 -0
  197. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/local-plugin.js +7 -0
  198. package/test/fixtures/local-plugin-config-pkg/node_modules/atlaspack-config-local/package.json +7 -0
  199. package/test/fixtures/main-format-mismatch/package.json +8 -0
  200. package/test/fixtures/main-global/package.json +8 -0
  201. package/test/fixtures/main-mjs/package.json +8 -0
  202. package/test/fixtures/module-a.js +1 -0
  203. package/test/fixtures/module-b.js +1 -0
  204. package/test/fixtures/plugins/local-plugin.js +7 -0
  205. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/index.js +7 -0
  206. package/test/fixtures/plugins/node_modules/atlaspack-transformer-bad-engines/package.json +7 -0
  207. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/index.js +7 -0
  208. package/test/fixtures/plugins/node_modules/atlaspack-transformer-no-engines/package.json +4 -0
  209. package/test/fixtures/targets-default-distdir-none/package.json +5 -0
  210. package/test/fixtures/targets-default-distdir-one/package.json +8 -0
  211. package/test/fixtures/targets-default-distdir-two/package.json +18 -0
  212. package/test/requests/ConfigRequest.test.js +254 -0
  213. package/test/serializer.test.js +302 -0
  214. package/test/test-utils.js +80 -0
  215. package/test/utils.test.js +43 -0
@@ -0,0 +1,646 @@
1
+ // @flow strict-local
2
+
3
+ import type {GraphVisitor} from '@atlaspack/types';
4
+ import type {
5
+ ContentGraphOpts,
6
+ ContentKey,
7
+ NodeId,
8
+ SerializedContentGraph,
9
+ } from '@atlaspack/graph';
10
+ import type {
11
+ Asset,
12
+ AssetGraphNode,
13
+ AssetGroup,
14
+ AssetGroupNode,
15
+ AssetNode,
16
+ Dependency,
17
+ DependencyNode,
18
+ Entry,
19
+ EntryFileNode,
20
+ EntrySpecifierNode,
21
+ Environment,
22
+ Target,
23
+ } from './types';
24
+
25
+ import invariant from 'assert';
26
+ import {hashString, Hash} from '@atlaspack/rust';
27
+ import {hashObject} from '@atlaspack/utils';
28
+ import nullthrows from 'nullthrows';
29
+ import {ContentGraph} from '@atlaspack/graph';
30
+ import {createDependency} from './Dependency';
31
+ import {type ProjectPath, fromProjectPathRelative} from './projectPath';
32
+
33
+ type InitOpts = {|
34
+ entries?: Array<ProjectPath>,
35
+ targets?: Array<Target>,
36
+ assetGroups?: Array<AssetGroup>,
37
+ |};
38
+
39
+ type AssetGraphOpts = {|
40
+ ...ContentGraphOpts<AssetGraphNode>,
41
+ hash?: ?string,
42
+ |};
43
+
44
+ type SerializedAssetGraph = {|
45
+ ...SerializedContentGraph<AssetGraphNode>,
46
+ hash?: ?string,
47
+ |};
48
+
49
+ export function nodeFromDep(dep: Dependency): DependencyNode {
50
+ return {
51
+ id: dep.id,
52
+ type: 'dependency',
53
+ value: dep,
54
+ deferred: false,
55
+ excluded: false,
56
+ usedSymbolsDown: new Set(),
57
+ usedSymbolsUp: new Map(),
58
+ usedSymbolsDownDirty: true,
59
+ usedSymbolsUpDirtyDown: true,
60
+ usedSymbolsUpDirtyUp: true,
61
+ };
62
+ }
63
+
64
+ export function nodeFromAssetGroup(assetGroup: AssetGroup): AssetGroupNode {
65
+ return {
66
+ id: hashString(
67
+ fromProjectPathRelative(assetGroup.filePath) +
68
+ assetGroup.env.id +
69
+ String(assetGroup.isSource) +
70
+ String(assetGroup.sideEffects) +
71
+ (assetGroup.code ?? '') +
72
+ ':' +
73
+ (assetGroup.pipeline ?? '') +
74
+ ':' +
75
+ (assetGroup.query ?? ''),
76
+ ),
77
+ type: 'asset_group',
78
+ value: assetGroup,
79
+ usedSymbolsDownDirty: true,
80
+ };
81
+ }
82
+
83
+ export function nodeFromAsset(asset: Asset): AssetNode {
84
+ return {
85
+ id: asset.id,
86
+ type: 'asset',
87
+ value: asset,
88
+ usedSymbols: new Set(),
89
+ usedSymbolsDownDirty: true,
90
+ usedSymbolsUpDirty: true,
91
+ };
92
+ }
93
+
94
+ export function nodeFromEntrySpecifier(entry: ProjectPath): EntrySpecifierNode {
95
+ return {
96
+ id: 'entry_specifier:' + fromProjectPathRelative(entry),
97
+ type: 'entry_specifier',
98
+ value: entry,
99
+ };
100
+ }
101
+
102
+ export function nodeFromEntryFile(entry: Entry): EntryFileNode {
103
+ return {
104
+ id: 'entry_file:' + hashObject(entry),
105
+ type: 'entry_file',
106
+ value: entry,
107
+ };
108
+ }
109
+
110
+ export default class AssetGraph extends ContentGraph<AssetGraphNode> {
111
+ onNodeRemoved: ?(nodeId: NodeId) => mixed;
112
+ hash: ?string;
113
+ envCache: Map<string, Environment>;
114
+ safeToIncrementallyBundle: boolean = true;
115
+ undeferredDependencies: Set<Dependency>;
116
+
117
+ constructor(opts: ?AssetGraphOpts) {
118
+ if (opts) {
119
+ let {hash, ...rest} = opts;
120
+ super(rest);
121
+ this.hash = hash;
122
+ } else {
123
+ super();
124
+ this.setRootNodeId(
125
+ this.addNode({
126
+ id: '@@root',
127
+ type: 'root',
128
+ value: null,
129
+ }),
130
+ );
131
+ }
132
+
133
+ this.undeferredDependencies = new Set();
134
+ this.envCache = new Map();
135
+ }
136
+
137
+ // $FlowFixMe[prop-missing]
138
+ static deserialize(opts: AssetGraphOpts): AssetGraph {
139
+ return new AssetGraph(opts);
140
+ }
141
+
142
+ // $FlowFixMe[prop-missing]
143
+ serialize(): SerializedAssetGraph {
144
+ return {
145
+ ...super.serialize(),
146
+ hash: this.hash,
147
+ };
148
+ }
149
+
150
+ // Deduplicates Environments by making them referentially equal
151
+ normalizeEnvironment(input: Asset | Dependency | AssetGroup) {
152
+ let {id, context} = input.env;
153
+ let idAndContext = `${id}-${context}`;
154
+
155
+ let env = this.envCache.get(idAndContext);
156
+ if (env) {
157
+ input.env = env;
158
+ } else {
159
+ this.envCache.set(idAndContext, input.env);
160
+ }
161
+ }
162
+
163
+ setRootConnections({entries, assetGroups}: InitOpts) {
164
+ let nodes = [];
165
+ if (entries) {
166
+ for (let entry of entries) {
167
+ let node = nodeFromEntrySpecifier(entry);
168
+ nodes.push(node);
169
+ }
170
+ } else if (assetGroups) {
171
+ nodes.push(
172
+ ...assetGroups.map(assetGroup => nodeFromAssetGroup(assetGroup)),
173
+ );
174
+ }
175
+ this.replaceNodeIdsConnectedTo(
176
+ nullthrows(this.rootNodeId),
177
+ nodes.map(node => this.addNode(node)),
178
+ );
179
+ }
180
+
181
+ addNode(node: AssetGraphNode): NodeId {
182
+ this.hash = null;
183
+ let existing = this.getNodeByContentKey(node.id);
184
+ if (existing != null) {
185
+ invariant(existing.type === node.type);
186
+ // $FlowFixMe[incompatible-type] Checked above
187
+ // $FlowFixMe[prop-missing]
188
+ existing.value = node.value;
189
+ let existingId = this.getNodeIdByContentKey(node.id);
190
+ this.updateNode(existingId, existing);
191
+ return existingId;
192
+ }
193
+ return super.addNodeByContentKey(node.id, node);
194
+ }
195
+
196
+ removeNode(nodeId: NodeId): void {
197
+ this.hash = null;
198
+ this.onNodeRemoved && this.onNodeRemoved(nodeId);
199
+ return super.removeNode(nodeId);
200
+ }
201
+
202
+ resolveEntry(
203
+ entry: ProjectPath,
204
+ resolved: Array<Entry>,
205
+ correspondingRequest: ContentKey,
206
+ ) {
207
+ let entrySpecifierNodeId = this.getNodeIdByContentKey(
208
+ nodeFromEntrySpecifier(entry).id,
209
+ );
210
+ let entrySpecifierNode = nullthrows(this.getNode(entrySpecifierNodeId));
211
+ invariant(entrySpecifierNode.type === 'entry_specifier');
212
+ entrySpecifierNode.correspondingRequest = correspondingRequest;
213
+
214
+ this.replaceNodeIdsConnectedTo(
215
+ entrySpecifierNodeId,
216
+ resolved.map(file => this.addNode(nodeFromEntryFile(file))),
217
+ );
218
+ }
219
+
220
+ resolveTargets(
221
+ entry: Entry,
222
+ targets: Array<Target>,
223
+ correspondingRequest: string,
224
+ ) {
225
+ let depNodes = targets.map(target => {
226
+ let node = nodeFromDep(
227
+ // The passed project path is ignored in this case, because there is no `loc`
228
+ createDependency('', {
229
+ specifier: fromProjectPathRelative(entry.filePath),
230
+ specifierType: 'esm', // ???
231
+ pipeline: target.pipeline,
232
+ target: target,
233
+ env: target.env,
234
+ isEntry: true,
235
+ needsStableName: true,
236
+ symbols: target.env.isLibrary
237
+ ? new Map([['*', {local: '*', isWeak: true, loc: null}]])
238
+ : undefined,
239
+ }),
240
+ );
241
+
242
+ if (node.value.env.isLibrary) {
243
+ // in library mode, all of the entry's symbols are "used"
244
+ node.usedSymbolsDown.add('*');
245
+ node.usedSymbolsUp.set('*', undefined);
246
+ }
247
+ return node;
248
+ });
249
+
250
+ let entryNodeId = this.getNodeIdByContentKey(nodeFromEntryFile(entry).id);
251
+ let entryNode = nullthrows(this.getNode(entryNodeId));
252
+ invariant(entryNode.type === 'entry_file');
253
+ entryNode.correspondingRequest = correspondingRequest;
254
+
255
+ this.replaceNodeIdsConnectedTo(
256
+ entryNodeId,
257
+ depNodes.map(node => this.addNode(node)),
258
+ );
259
+ }
260
+
261
+ resolveDependency(
262
+ dependency: Dependency,
263
+ assetGroup: ?AssetGroup,
264
+ correspondingRequest: string,
265
+ ) {
266
+ let depNodeId = this.getNodeIdByContentKey(dependency.id);
267
+ let depNode = nullthrows(this.getNode(depNodeId));
268
+ invariant(depNode.type === 'dependency');
269
+ depNode.correspondingRequest = correspondingRequest;
270
+
271
+ if (!assetGroup) {
272
+ return;
273
+ }
274
+
275
+ let assetGroupNode = nodeFromAssetGroup(assetGroup);
276
+ let existing = this.getNodeByContentKey(assetGroupNode.id);
277
+ if (existing != null) {
278
+ invariant(existing.type === 'asset_group');
279
+ assetGroupNode.value.canDefer =
280
+ assetGroupNode.value.canDefer && existing.value.canDefer;
281
+ }
282
+
283
+ let assetGroupNodeId = this.addNode(assetGroupNode);
284
+ this.replaceNodeIdsConnectedTo(this.getNodeIdByContentKey(dependency.id), [
285
+ assetGroupNodeId,
286
+ ]);
287
+
288
+ this.replaceNodeIdsConnectedTo(depNodeId, [assetGroupNodeId]);
289
+ }
290
+
291
+ shouldVisitChild(nodeId: NodeId, childNodeId: NodeId): boolean {
292
+ let node = nullthrows(this.getNode(nodeId));
293
+ let childNode = nullthrows(this.getNode(childNodeId));
294
+ if (
295
+ node.type !== 'dependency' ||
296
+ childNode.type !== 'asset_group' ||
297
+ childNode.deferred === false
298
+ ) {
299
+ return true;
300
+ }
301
+ // Node types are proved above
302
+ let dependencyNode = node;
303
+ let assetGroupNode = childNode;
304
+
305
+ let {sideEffects, canDefer = true} = assetGroupNode.value;
306
+ let dependency = dependencyNode.value;
307
+ let dependencyPreviouslyDeferred = dependencyNode.hasDeferred;
308
+ let assetGroupPreviouslyDeferred = assetGroupNode.deferred;
309
+ let defer = this.shouldDeferDependency(dependency, sideEffects, canDefer);
310
+ dependencyNode.hasDeferred = defer;
311
+ assetGroupNode.deferred = defer;
312
+
313
+ if (!dependencyPreviouslyDeferred && defer) {
314
+ this.markParentsWithHasDeferred(nodeId);
315
+ } else if (assetGroupPreviouslyDeferred && !defer) {
316
+ this.unmarkParentsWithHasDeferred(childNodeId);
317
+ }
318
+
319
+ return !defer;
320
+ }
321
+
322
+ // Dependency: mark parent Asset <- AssetGroup with hasDeferred true
323
+ markParentsWithHasDeferred(nodeId: NodeId) {
324
+ this.traverseAncestors(nodeId, (traversedNodeId, _, actions) => {
325
+ let traversedNode = nullthrows(this.getNode(traversedNodeId));
326
+ if (traversedNode.type === 'asset') {
327
+ traversedNode.hasDeferred = true;
328
+ } else if (traversedNode.type === 'asset_group') {
329
+ traversedNode.hasDeferred = true;
330
+ actions.skipChildren();
331
+ } else if (nodeId !== traversedNodeId) {
332
+ actions.skipChildren();
333
+ }
334
+ });
335
+ }
336
+
337
+ // AssetGroup: update hasDeferred of all parent Dependency <- Asset <- AssetGroup
338
+ unmarkParentsWithHasDeferred(nodeId: NodeId) {
339
+ this.traverseAncestors(nodeId, (traversedNodeId, ctx, actions) => {
340
+ let traversedNode = nullthrows(this.getNode(traversedNodeId));
341
+ if (traversedNode.type === 'asset') {
342
+ let hasDeferred = this.getNodeIdsConnectedFrom(traversedNodeId).some(
343
+ childNodeId => {
344
+ let childNode = nullthrows(this.getNode(childNodeId));
345
+ return childNode.hasDeferred == null
346
+ ? false
347
+ : childNode.hasDeferred;
348
+ },
349
+ );
350
+ if (!hasDeferred) {
351
+ delete traversedNode.hasDeferred;
352
+ }
353
+ return {hasDeferred};
354
+ } else if (
355
+ traversedNode.type === 'asset_group' &&
356
+ nodeId !== traversedNodeId
357
+ ) {
358
+ if (!ctx?.hasDeferred) {
359
+ this.safeToIncrementallyBundle = false;
360
+ delete traversedNode.hasDeferred;
361
+ }
362
+ actions.skipChildren();
363
+ } else if (traversedNode.type === 'dependency') {
364
+ this.safeToIncrementallyBundle = false;
365
+ traversedNode.hasDeferred = false;
366
+ } else if (nodeId !== traversedNodeId) {
367
+ actions.skipChildren();
368
+ }
369
+ });
370
+ }
371
+
372
+ // Defer transforming this dependency if it is marked as weak, there are no side effects,
373
+ // no re-exported symbols are used by ancestor dependencies and the re-exporting asset isn't
374
+ // using a wildcard and isn't an entry (in library mode).
375
+ // This helps with performance building large libraries like `lodash-es`, which re-exports
376
+ // a huge number of functions since we can avoid even transforming the files that aren't used.
377
+ shouldDeferDependency(
378
+ dependency: Dependency,
379
+ sideEffects: ?boolean,
380
+ canDefer: boolean,
381
+ ): boolean {
382
+ let dependencySymbols = dependency.symbols;
383
+
384
+ // Doing this separately keeps Flow happy further down
385
+ if (!dependencySymbols) {
386
+ return false;
387
+ }
388
+
389
+ let isDeferrable =
390
+ [...dependencySymbols].every(([, {isWeak}]) => isWeak) &&
391
+ sideEffects === false &&
392
+ canDefer &&
393
+ !dependencySymbols.has('*');
394
+
395
+ if (!isDeferrable) {
396
+ return false;
397
+ }
398
+
399
+ let depNodeId = this.getNodeIdByContentKey(dependency.id);
400
+ let depNode = this.getNode(depNodeId);
401
+ invariant(depNode);
402
+
403
+ let assets = this.getNodeIdsConnectedTo(depNodeId);
404
+ let symbols = new Map(
405
+ [...dependencySymbols].map(([key, val]) => [val.local, key]),
406
+ );
407
+ invariant(assets.length === 1);
408
+ let firstAsset = nullthrows(this.getNode(assets[0]));
409
+ invariant(firstAsset.type === 'asset');
410
+ let resolvedAsset = firstAsset.value;
411
+
412
+ // This doesn't change from here, so checking it now saves
413
+ // us some calls to `getIncomingDependency`
414
+ if (!resolvedAsset.symbols) {
415
+ return true;
416
+ }
417
+
418
+ let deps = this.getIncomingDependencies(resolvedAsset);
419
+
420
+ return deps.every(d => {
421
+ // If this dependency has already been through this process, and we
422
+ // know it's not deferrable, then there's no need to re-check
423
+ if (this.undeferredDependencies.has(d)) {
424
+ return false;
425
+ }
426
+
427
+ let depIsDeferrable =
428
+ d.symbols &&
429
+ !(d.env.isLibrary && d.isEntry) &&
430
+ !d.symbols.has('*') &&
431
+ ![...d.symbols.keys()].some(symbol => {
432
+ let assetSymbol = resolvedAsset.symbols?.get(symbol)?.local;
433
+ return assetSymbol != null && symbols.has(assetSymbol);
434
+ });
435
+
436
+ if (!depIsDeferrable) {
437
+ // Mark this dep as not deferrable so it doesn't have to be re-checked
438
+ this.undeferredDependencies.add(d);
439
+ return false;
440
+ }
441
+ });
442
+ }
443
+
444
+ resolveAssetGroup(
445
+ assetGroup: AssetGroup,
446
+ assets: Array<Asset>,
447
+ correspondingRequest: ContentKey,
448
+ ) {
449
+ this.normalizeEnvironment(assetGroup);
450
+ let assetGroupNode = nodeFromAssetGroup(assetGroup);
451
+ assetGroupNode = this.getNodeByContentKey(assetGroupNode.id);
452
+ if (!assetGroupNode) {
453
+ return;
454
+ }
455
+ invariant(assetGroupNode.type === 'asset_group');
456
+ assetGroupNode.correspondingRequest = correspondingRequest;
457
+
458
+ let assetsByKey = new Map();
459
+ for (let asset of assets) {
460
+ if (asset.uniqueKey != null) {
461
+ assetsByKey.set(asset.uniqueKey, asset);
462
+ }
463
+ }
464
+
465
+ let dependentAssetKeys = new Set();
466
+ for (let asset of assets) {
467
+ for (let dep of asset.dependencies.values()) {
468
+ if (assetsByKey.has(dep.specifier)) {
469
+ dependentAssetKeys.add(dep.specifier);
470
+ }
471
+ }
472
+ }
473
+
474
+ let assetObjects: Array<{|
475
+ assetNodeId: NodeId,
476
+ dependentAssets: Array<Asset>,
477
+ |}> = [];
478
+ let assetNodeIds = [];
479
+ for (let asset of assets) {
480
+ this.normalizeEnvironment(asset);
481
+ let isDirect = !dependentAssetKeys.has(asset.uniqueKey);
482
+
483
+ let dependentAssets = [];
484
+ for (let dep of asset.dependencies.values()) {
485
+ let dependentAsset = assetsByKey.get(dep.specifier);
486
+ if (dependentAsset) {
487
+ dependentAssets.push(dependentAsset);
488
+ if (dependentAsset.id === asset.id) {
489
+ // Don't orphan circular dependencies.
490
+ isDirect = true;
491
+ }
492
+ }
493
+ }
494
+ let id = this.addNode(nodeFromAsset(asset));
495
+ assetObjects.push({
496
+ assetNodeId: id,
497
+ dependentAssets,
498
+ });
499
+
500
+ if (isDirect) {
501
+ assetNodeIds.push(id);
502
+ }
503
+ }
504
+
505
+ this.replaceNodeIdsConnectedTo(
506
+ this.getNodeIdByContentKey(assetGroupNode.id),
507
+ assetNodeIds,
508
+ );
509
+ for (let {assetNodeId, dependentAssets} of assetObjects) {
510
+ // replaceNodesConnectedTo has merged the value into the existing node, retrieve
511
+ // the actual current node.
512
+ let assetNode = nullthrows(this.getNode(assetNodeId));
513
+ invariant(assetNode.type === 'asset');
514
+ this.resolveAsset(assetNode, dependentAssets);
515
+ }
516
+ }
517
+
518
+ resolveAsset(assetNode: AssetNode, dependentAssets: Array<Asset>) {
519
+ let depNodeIds: Array<NodeId> = [];
520
+ let depNodesWithAssets = [];
521
+ for (let dep of assetNode.value.dependencies.values()) {
522
+ this.normalizeEnvironment(dep);
523
+ let depNode = nodeFromDep(dep);
524
+ let existing = this.getNodeByContentKey(depNode.id);
525
+ if (
526
+ existing?.type === 'dependency' &&
527
+ existing.value.resolverMeta != null
528
+ ) {
529
+ depNode.value.meta = {
530
+ ...depNode.value.meta,
531
+ ...existing.value.resolverMeta,
532
+ };
533
+ }
534
+ let dependentAsset = dependentAssets.find(
535
+ a => a.uniqueKey === dep.specifier,
536
+ );
537
+ if (dependentAsset) {
538
+ depNode.complete = true;
539
+ depNodesWithAssets.push([depNode, nodeFromAsset(dependentAsset)]);
540
+ }
541
+ depNode.value.sourceAssetType = assetNode.value.type;
542
+ depNodeIds.push(this.addNode(depNode));
543
+ }
544
+
545
+ assetNode.usedSymbolsUpDirty = true;
546
+ assetNode.usedSymbolsDownDirty = true;
547
+ this.replaceNodeIdsConnectedTo(
548
+ this.getNodeIdByContentKey(assetNode.id),
549
+ depNodeIds,
550
+ );
551
+
552
+ for (let [depNode, dependentAssetNode] of depNodesWithAssets) {
553
+ let depAssetNodeId = this.addNode(dependentAssetNode);
554
+
555
+ this.replaceNodeIdsConnectedTo(this.getNodeIdByContentKey(depNode.id), [
556
+ depAssetNodeId,
557
+ ]);
558
+ }
559
+ }
560
+
561
+ getIncomingDependencies(asset: Asset): Array<Dependency> {
562
+ let nodeId = this.getNodeIdByContentKey(asset.id);
563
+ let assetGroupIds = this.getNodeIdsConnectedTo(nodeId);
564
+ let dependencies = [];
565
+ for (let i = 0; i < assetGroupIds.length; i++) {
566
+ let assetGroupId = assetGroupIds[i];
567
+
568
+ // Sometimes assets are connected directly to dependencies
569
+ // rather than through an asset group. This happens due to
570
+ // inline dependencies on assets via uniqueKey. See resolveAsset.
571
+ let node = this.getNode(assetGroupId);
572
+ if (node?.type === 'dependency') {
573
+ dependencies.push(node.value);
574
+ continue;
575
+ }
576
+
577
+ let assetIds = this.getNodeIdsConnectedTo(assetGroupId);
578
+ for (let j = 0; j < assetIds.length; j++) {
579
+ let node = this.getNode(assetIds[j]);
580
+ if (!node || node.type !== 'dependency') {
581
+ continue;
582
+ }
583
+
584
+ dependencies.push(node.value);
585
+ }
586
+ }
587
+
588
+ return dependencies;
589
+ }
590
+
591
+ traverseAssets<TContext>(
592
+ visit: GraphVisitor<Asset, TContext>,
593
+ startNodeId: ?NodeId,
594
+ ): ?TContext {
595
+ return this.filteredTraverse(
596
+ nodeId => {
597
+ let node = nullthrows(this.getNode(nodeId));
598
+ return node.type === 'asset' ? node.value : null;
599
+ },
600
+ visit,
601
+ startNodeId,
602
+ );
603
+ }
604
+
605
+ getEntryAssetGroupNodes(): Array<AssetGroupNode> {
606
+ let entryNodes = [];
607
+ this.traverse((nodeId, _, actions) => {
608
+ let node = nullthrows(this.getNode(nodeId));
609
+ if (node.type === 'asset_group') {
610
+ entryNodes.push(node);
611
+ actions.skipChildren();
612
+ }
613
+ });
614
+ return entryNodes;
615
+ }
616
+
617
+ getEntryAssets(): Array<Asset> {
618
+ let entries = [];
619
+ this.traverseAssets((asset, ctx, traversal) => {
620
+ entries.push(asset);
621
+ traversal.skipChildren();
622
+ });
623
+
624
+ return entries;
625
+ }
626
+
627
+ getHash(): string {
628
+ if (this.hash != null) {
629
+ return this.hash;
630
+ }
631
+
632
+ let hash = new Hash();
633
+ // TODO: sort??
634
+ this.traverse(nodeId => {
635
+ let node = nullthrows(this.getNode(nodeId));
636
+ if (node.type === 'asset') {
637
+ hash.writeString(nullthrows(node.value.outputHash));
638
+ } else if (node.type === 'dependency' && node.value.target) {
639
+ hash.writeString(JSON.stringify(node.value.target));
640
+ }
641
+ });
642
+
643
+ this.hash = hash.finish();
644
+ return this.hash;
645
+ }
646
+ }