metro 0.71.2 → 0.72.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/package.json +21 -21
- package/src/Assets.js +3 -2
- package/src/Assets.js.flow +3 -2
- package/src/Bundler.js +11 -2
- package/src/Bundler.js.flow +7 -1
- package/src/DeltaBundler/DeltaCalculator.js +85 -21
- package/src/DeltaBundler/DeltaCalculator.js.flow +63 -8
- package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +1 -3
- package/src/DeltaBundler/Transformer.js +27 -4
- package/src/DeltaBundler/Transformer.js.flow +18 -2
- package/src/DeltaBundler/Worker.flow.js +45 -1
- package/src/DeltaBundler/Worker.flow.js.flow +42 -1
- package/src/DeltaBundler/WorkerFarm.js +3 -2
- package/src/DeltaBundler/WorkerFarm.js.flow +5 -3
- package/src/DeltaBundler/graphOperations.js +170 -63
- package/src/DeltaBundler/graphOperations.js.flow +144 -64
- package/src/DeltaBundler/types.flow.js.flow +11 -5
- package/src/HmrServer.js +2 -0
- package/src/HmrServer.js.flow +2 -0
- package/src/IncrementalBundler.js +6 -0
- package/src/IncrementalBundler.js.flow +6 -0
- package/src/ModuleGraph/node-haste/HasteFS.js.flow +1 -1
- package/src/ModuleGraph/node-haste/node-haste.js +14 -7
- package/src/ModuleGraph/node-haste/node-haste.js.flow +35 -10
- package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +5 -13
- package/src/ModuleGraph/output/multiple-files-ram-bundle.js.flow +4 -14
- package/src/ModuleGraph/output/util.js +1 -0
- package/src/ModuleGraph/output/util.js.flow +4 -3
- package/src/ModuleGraph/silent-console.js +5 -4
- package/src/ModuleGraph/silent-console.js.flow +8 -4
- package/src/ModuleGraph/worker/collectDependencies.js +19 -30
- package/src/ModuleGraph/worker/collectDependencies.js.flow +28 -43
- package/src/Server.js +8 -0
- package/src/Server.js.flow +48 -12
- package/src/cli-utils.js.flow +1 -1
- package/src/commands/build.js +1 -2
- package/src/commands/build.js.flow +6 -9
- package/src/commands/dependencies.js +1 -1
- package/src/commands/serve.js +2 -1
- package/src/commands/serve.js.flow +7 -8
- package/src/index.flow.js +11 -8
- package/src/index.flow.js.flow +10 -7
- package/src/integration_tests/basic_bundle/require-context/conflict.js +25 -0
- package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +27 -0
- package/src/integration_tests/basic_bundle/require-context/empty.js +29 -0
- package/src/integration_tests/basic_bundle/require-context/empty.js.flow +26 -0
- package/src/integration_tests/basic_bundle/require-context/matching.js +26 -0
- package/src/integration_tests/basic_bundle/require-context/matching.js.flow +27 -0
- package/src/integration_tests/basic_bundle/require-context/mode-eager.js +22 -0
- package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +24 -0
- package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js +22 -0
- package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +24 -0
- package/src/integration_tests/basic_bundle/require-context/mode-lazy.js +22 -0
- package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +24 -0
- package/src/integration_tests/basic_bundle/require-context/mode-sync.js +20 -0
- package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +22 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/a.js +12 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/a.js.flow +11 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/b.js +18 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/b.js.flow +11 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/c.js +12 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/c.js.flow +11 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js +12 -0
- package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js.flow +11 -0
- package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js +12 -0
- package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js.flow +11 -0
- package/src/integration_tests/basic_bundle/require-context/utils.js +29 -0
- package/src/integration_tests/basic_bundle/require-context/utils.js.flow +44 -0
- package/src/lib/CountingSet.js +1 -0
- package/src/lib/CountingSet.js.flow +1 -0
- package/src/lib/contextModule.js +80 -0
- package/src/lib/contextModule.js.flow +86 -0
- package/src/lib/contextModuleTemplates.js +186 -0
- package/src/lib/contextModuleTemplates.js.flow +148 -0
- package/src/lib/getGraphId.js +2 -1
- package/src/lib/getGraphId.js.flow +3 -0
- package/src/lib/getPrependedScripts.js +2 -0
- package/src/lib/getPrependedScripts.js.flow +2 -0
- package/src/lib/parseOptionsFromUrl.js.flow +7 -18
- package/src/lib/transformHelpers.js +41 -9
- package/src/lib/transformHelpers.js.flow +46 -9
- package/src/node-haste/DependencyGraph/ModuleResolution.js +1 -0
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +3 -2
- package/src/node-haste/DependencyGraph/createHasteMap.js +7 -1
- package/src/node-haste/DependencyGraph/createHasteMap.js.flow +8 -2
- package/src/node-haste/DependencyGraph.js +7 -0
- package/src/node-haste/DependencyGraph.js.flow +17 -2
- package/src/shared/output/bundle.flow.js +67 -0
- package/src/shared/output/bundle.flow.js.flow +89 -0
- package/src/shared/output/bundle.js +8 -55
- package/src/shared/output/bundle.js.flow +8 -75
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.72.1",
|
|
4
4
|
"description": "🚇 The JavaScript bundler for React Native.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": "src/cli.js",
|
|
@@ -36,22 +36,22 @@
|
|
|
36
36
|
"invariant": "^2.2.4",
|
|
37
37
|
"jest-worker": "^27.2.0",
|
|
38
38
|
"lodash.throttle": "^4.1.1",
|
|
39
|
-
"metro-babel-transformer": "0.
|
|
40
|
-
"metro-cache": "0.
|
|
41
|
-
"metro-cache-key": "0.
|
|
42
|
-
"metro-config": "0.
|
|
43
|
-
"metro-core": "0.
|
|
44
|
-
"metro-file-map": "0.
|
|
45
|
-
"metro-hermes-compiler": "0.
|
|
46
|
-
"metro-inspector-proxy": "0.
|
|
47
|
-
"metro-minify-uglify": "0.
|
|
48
|
-
"metro-react-native-babel-preset": "0.
|
|
49
|
-
"metro-resolver": "0.
|
|
50
|
-
"metro-runtime": "0.
|
|
51
|
-
"metro-source-map": "0.
|
|
52
|
-
"metro-symbolicate": "0.
|
|
53
|
-
"metro-transform-plugins": "0.
|
|
54
|
-
"metro-transform-worker": "0.
|
|
39
|
+
"metro-babel-transformer": "0.72.1",
|
|
40
|
+
"metro-cache": "0.72.1",
|
|
41
|
+
"metro-cache-key": "0.72.1",
|
|
42
|
+
"metro-config": "0.72.1",
|
|
43
|
+
"metro-core": "0.72.1",
|
|
44
|
+
"metro-file-map": "0.72.1",
|
|
45
|
+
"metro-hermes-compiler": "0.72.1",
|
|
46
|
+
"metro-inspector-proxy": "0.72.1",
|
|
47
|
+
"metro-minify-uglify": "0.72.1",
|
|
48
|
+
"metro-react-native-babel-preset": "0.72.1",
|
|
49
|
+
"metro-resolver": "0.72.1",
|
|
50
|
+
"metro-runtime": "0.72.1",
|
|
51
|
+
"metro-source-map": "0.72.1",
|
|
52
|
+
"metro-symbolicate": "0.72.1",
|
|
53
|
+
"metro-transform-plugins": "0.72.1",
|
|
54
|
+
"metro-transform-worker": "0.72.1",
|
|
55
55
|
"mime-types": "^2.1.27",
|
|
56
56
|
"node-fetch": "^2.2.0",
|
|
57
57
|
"nullthrows": "^1.1.1",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"babel-jest": "^26.6.3",
|
|
71
71
|
"dedent": "^0.7.0",
|
|
72
72
|
"jest-snapshot": "^26.5.2",
|
|
73
|
-
"metro-babel-register": "0.
|
|
74
|
-
"metro-memory-fs": "0.
|
|
75
|
-
"metro-react-native-babel-preset": "0.
|
|
76
|
-
"metro-react-native-babel-transformer": "0.
|
|
73
|
+
"metro-babel-register": "0.72.1",
|
|
74
|
+
"metro-memory-fs": "0.72.1",
|
|
75
|
+
"metro-react-native-babel-preset": "0.72.1",
|
|
76
|
+
"metro-react-native-babel-transformer": "0.72.1",
|
|
77
77
|
"stack-trace": "^0.0.10"
|
|
78
78
|
},
|
|
79
79
|
"license": "MIT"
|
package/src/Assets.js
CHANGED
|
@@ -108,8 +108,9 @@ async function getAbsoluteAssetRecord(assetPath, platform = null) {
|
|
|
108
108
|
|
|
109
109
|
if (!record) {
|
|
110
110
|
throw new Error(
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
`Asset not found: ${assetPath} for platform: ${
|
|
112
|
+
platform !== null && platform !== void 0 ? platform : "(unspecified)"
|
|
113
|
+
}`
|
|
113
114
|
);
|
|
114
115
|
}
|
|
115
116
|
|
package/src/Assets.js.flow
CHANGED
|
@@ -154,8 +154,9 @@ async function getAbsoluteAssetRecord(
|
|
|
154
154
|
|
|
155
155
|
if (!record) {
|
|
156
156
|
throw new Error(
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
`Asset not found: ${assetPath} for platform: ${
|
|
158
|
+
platform ?? '(unspecified)'
|
|
159
|
+
}`,
|
|
159
160
|
);
|
|
160
161
|
}
|
|
161
162
|
|
package/src/Bundler.js
CHANGED
|
@@ -55,11 +55,20 @@ class Bundler {
|
|
|
55
55
|
return this._depGraph;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
async transformFile(
|
|
58
|
+
async transformFile(
|
|
59
|
+
filePath,
|
|
60
|
+
transformOptions,
|
|
61
|
+
/** Optionally provide the file contents, this can be used to provide virtual contents for a file. */
|
|
62
|
+
fileBuffer
|
|
63
|
+
) {
|
|
59
64
|
// We need to be sure that the DependencyGraph has been initialized.
|
|
60
65
|
// TODO: Remove this ugly hack!
|
|
61
66
|
await this._depGraph.ready();
|
|
62
|
-
return this._transformer.transformFile(
|
|
67
|
+
return this._transformer.transformFile(
|
|
68
|
+
filePath,
|
|
69
|
+
transformOptions,
|
|
70
|
+
fileBuffer
|
|
71
|
+
);
|
|
63
72
|
} // Waits for the bundler to become ready.
|
|
64
73
|
|
|
65
74
|
async ready() {
|
package/src/Bundler.js.flow
CHANGED
|
@@ -68,12 +68,18 @@ class Bundler {
|
|
|
68
68
|
async transformFile(
|
|
69
69
|
filePath: string,
|
|
70
70
|
transformOptions: TransformOptions,
|
|
71
|
+
/** Optionally provide the file contents, this can be used to provide virtual contents for a file. */
|
|
72
|
+
fileBuffer?: Buffer,
|
|
71
73
|
): Promise<TransformResultWithSource<>> {
|
|
72
74
|
// We need to be sure that the DependencyGraph has been initialized.
|
|
73
75
|
// TODO: Remove this ugly hack!
|
|
74
76
|
await this._depGraph.ready();
|
|
75
77
|
|
|
76
|
-
return this._transformer.transformFile(
|
|
78
|
+
return this._transformer.transformFile(
|
|
79
|
+
filePath,
|
|
80
|
+
transformOptions,
|
|
81
|
+
fileBuffer,
|
|
82
|
+
);
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
// Waits for the bundler to become ready.
|
|
@@ -9,12 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
"use strict";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
createGraph,
|
|
14
|
-
initialTraverseDependencies,
|
|
15
|
-
reorderGraph,
|
|
16
|
-
traverseDependencies,
|
|
17
|
-
} = require("./graphOperations");
|
|
12
|
+
var _graphOperations = require("./graphOperations");
|
|
18
13
|
|
|
19
14
|
const { EventEmitter } = require("events");
|
|
20
15
|
/**
|
|
@@ -27,12 +22,13 @@ const { EventEmitter } = require("events");
|
|
|
27
22
|
class DeltaCalculator extends EventEmitter {
|
|
28
23
|
_deletedFiles = new Set();
|
|
29
24
|
_modifiedFiles = new Set();
|
|
25
|
+
_addedFiles = new Set();
|
|
30
26
|
|
|
31
27
|
constructor(entryPoints, changeEventSource, options) {
|
|
32
28
|
super();
|
|
33
29
|
this._options = options;
|
|
34
30
|
this._changeEventSource = changeEventSource;
|
|
35
|
-
this._graph = createGraph({
|
|
31
|
+
this._graph = (0, _graphOperations.createGraph)({
|
|
36
32
|
entryPoints,
|
|
37
33
|
transformOptions: this._options.transformOptions,
|
|
38
34
|
});
|
|
@@ -51,12 +47,13 @@ class DeltaCalculator extends EventEmitter {
|
|
|
51
47
|
|
|
52
48
|
this.removeAllListeners(); // Clean up all the cache data structures to deallocate memory.
|
|
53
49
|
|
|
54
|
-
this._graph = createGraph({
|
|
50
|
+
this._graph = (0, _graphOperations.createGraph)({
|
|
55
51
|
entryPoints: this._graph.entryPoints,
|
|
56
52
|
transformOptions: this._options.transformOptions,
|
|
57
53
|
});
|
|
58
54
|
this._modifiedFiles = new Set();
|
|
59
55
|
this._deletedFiles = new Set();
|
|
56
|
+
this._addedFiles = new Set();
|
|
60
57
|
}
|
|
61
58
|
/**
|
|
62
59
|
* Main method to calculate the delta of modules. It returns a DeltaResult,
|
|
@@ -75,13 +72,16 @@ class DeltaCalculator extends EventEmitter {
|
|
|
75
72
|
const modifiedFiles = this._modifiedFiles;
|
|
76
73
|
this._modifiedFiles = new Set();
|
|
77
74
|
const deletedFiles = this._deletedFiles;
|
|
78
|
-
this._deletedFiles = new Set();
|
|
75
|
+
this._deletedFiles = new Set();
|
|
76
|
+
const addedFiles = this._addedFiles;
|
|
77
|
+
this._addedFiles = new Set(); // Concurrent requests should reuse the same bundling process. To do so,
|
|
79
78
|
// this method stores the promise as an instance variable, and then it's
|
|
80
79
|
// removed after it gets resolved.
|
|
81
80
|
|
|
82
81
|
this._currentBuildPromise = this._getChangedDependencies(
|
|
83
82
|
modifiedFiles,
|
|
84
|
-
deletedFiles
|
|
83
|
+
deletedFiles,
|
|
84
|
+
addedFiles
|
|
85
85
|
);
|
|
86
86
|
let result;
|
|
87
87
|
const numDependencies = this._graph.dependencies.size;
|
|
@@ -94,7 +94,8 @@ class DeltaCalculator extends EventEmitter {
|
|
|
94
94
|
// do so, asking for a delta after an error will produce an empty Delta,
|
|
95
95
|
// which is not correct.
|
|
96
96
|
modifiedFiles.forEach((file) => this._modifiedFiles.add(file));
|
|
97
|
-
deletedFiles.forEach((file) => this._deletedFiles.add(file));
|
|
97
|
+
deletedFiles.forEach((file) => this._deletedFiles.add(file));
|
|
98
|
+
addedFiles.forEach((file) => this._addedFiles.add(file)); // If after an error the number of modules has changed, we could be in
|
|
98
99
|
// a weird state. As a safe net we clean the dependency modules to force
|
|
99
100
|
// a clean traversal of the graph next time.
|
|
100
101
|
|
|
@@ -108,7 +109,7 @@ class DeltaCalculator extends EventEmitter {
|
|
|
108
109
|
} // Return all the modules if the client requested a reset delta.
|
|
109
110
|
|
|
110
111
|
if (reset) {
|
|
111
|
-
reorderGraph(this._graph, {
|
|
112
|
+
(0, _graphOperations.reorderGraph)(this._graph, {
|
|
112
113
|
shallow,
|
|
113
114
|
});
|
|
114
115
|
return {
|
|
@@ -130,6 +131,8 @@ class DeltaCalculator extends EventEmitter {
|
|
|
130
131
|
getGraph() {
|
|
131
132
|
return this._graph;
|
|
132
133
|
}
|
|
134
|
+
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
|
135
|
+
* LTI update could not be added via codemod */
|
|
133
136
|
|
|
134
137
|
_handleMultipleFileChanges = ({ eventsQueue }) => {
|
|
135
138
|
eventsQueue.forEach(this._handleFileChange);
|
|
@@ -141,23 +144,68 @@ class DeltaCalculator extends EventEmitter {
|
|
|
141
144
|
*/
|
|
142
145
|
|
|
143
146
|
_handleFileChange = ({ type, filePath }) => {
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
let state;
|
|
148
|
+
|
|
149
|
+
if (this._deletedFiles.has(filePath)) {
|
|
150
|
+
state = "deleted";
|
|
151
|
+
} else if (this._modifiedFiles.has(filePath)) {
|
|
152
|
+
state = "modified";
|
|
153
|
+
} else if (this._addedFiles.has(filePath)) {
|
|
154
|
+
state = "added";
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let nextState;
|
|
146
158
|
|
|
147
|
-
|
|
159
|
+
if (type === "delete") {
|
|
160
|
+
nextState = "deleted";
|
|
161
|
+
} else if (type === "add") {
|
|
162
|
+
// A deleted+added file is modified
|
|
163
|
+
nextState = state === "deleted" ? "modified" : "added";
|
|
148
164
|
} else {
|
|
149
|
-
|
|
165
|
+
// type === 'change'
|
|
166
|
+
// An added+modified file is added
|
|
167
|
+
nextState = state === "added" ? "added" : "modified";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
switch (nextState) {
|
|
171
|
+
case "deleted":
|
|
172
|
+
this._deletedFiles.add(filePath);
|
|
173
|
+
|
|
174
|
+
this._modifiedFiles.delete(filePath);
|
|
175
|
+
|
|
176
|
+
this._addedFiles.delete(filePath);
|
|
177
|
+
|
|
178
|
+
break;
|
|
150
179
|
|
|
151
|
-
|
|
180
|
+
case "added":
|
|
181
|
+
this._addedFiles.add(filePath);
|
|
182
|
+
|
|
183
|
+
this._deletedFiles.delete(filePath);
|
|
184
|
+
|
|
185
|
+
this._modifiedFiles.delete(filePath);
|
|
186
|
+
|
|
187
|
+
break;
|
|
188
|
+
|
|
189
|
+
case "modified":
|
|
190
|
+
this._modifiedFiles.add(filePath);
|
|
191
|
+
|
|
192
|
+
this._deletedFiles.delete(filePath);
|
|
193
|
+
|
|
194
|
+
this._addedFiles.delete(filePath);
|
|
195
|
+
|
|
196
|
+
break;
|
|
197
|
+
|
|
198
|
+
default:
|
|
199
|
+
nextState;
|
|
152
200
|
} // Notify users that there is a change in some of the bundle files. This
|
|
153
201
|
// way the client can choose to refetch the bundle.
|
|
154
202
|
|
|
155
203
|
this.emit("change");
|
|
156
204
|
};
|
|
157
205
|
|
|
158
|
-
async _getChangedDependencies(modifiedFiles, deletedFiles) {
|
|
206
|
+
async _getChangedDependencies(modifiedFiles, deletedFiles, addedFiles) {
|
|
159
207
|
if (!this._graph.dependencies.size) {
|
|
160
|
-
const { added } = await initialTraverseDependencies(
|
|
208
|
+
const { added } = await (0, _graphOperations.initialTraverseDependencies)(
|
|
161
209
|
this._graph,
|
|
162
210
|
this._options
|
|
163
211
|
);
|
|
@@ -182,7 +230,22 @@ class DeltaCalculator extends EventEmitter {
|
|
|
182
230
|
}
|
|
183
231
|
});
|
|
184
232
|
}
|
|
185
|
-
}); //
|
|
233
|
+
}); // NOTE(EvanBacon): This check adds extra complexity so we feature gate it
|
|
234
|
+
// to enable users to opt out.
|
|
235
|
+
|
|
236
|
+
if (this._options.unstable_allowRequireContext) {
|
|
237
|
+
// Check if any added or removed files are matched in a context module.
|
|
238
|
+
// We only need to do this for added files because (1) deleted files will have a context
|
|
239
|
+
// module as an inverse dependency, (2) modified files don't invalidate the contents
|
|
240
|
+
// of the context module.
|
|
241
|
+
addedFiles.forEach((filePath) => {
|
|
242
|
+
(0, _graphOperations.markModifiedContextModules)(
|
|
243
|
+
this._graph,
|
|
244
|
+
filePath,
|
|
245
|
+
modifiedFiles
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
} // We only want to process files that are in the bundle.
|
|
186
249
|
|
|
187
250
|
const modifiedDependencies = Array.from(modifiedFiles).filter((filePath) =>
|
|
188
251
|
this._graph.dependencies.has(filePath)
|
|
@@ -197,7 +260,8 @@ class DeltaCalculator extends EventEmitter {
|
|
|
197
260
|
};
|
|
198
261
|
}
|
|
199
262
|
|
|
200
|
-
const { added, modified, deleted } = await
|
|
263
|
+
const { added, modified, deleted } = await (0,
|
|
264
|
+
_graphOperations.traverseDependencies)(
|
|
201
265
|
modifiedDependencies,
|
|
202
266
|
this._graph,
|
|
203
267
|
this._options
|
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
const {
|
|
13
|
+
import {
|
|
16
14
|
createGraph,
|
|
17
15
|
initialTraverseDependencies,
|
|
16
|
+
markModifiedContextModules,
|
|
18
17
|
reorderGraph,
|
|
19
18
|
traverseDependencies,
|
|
20
|
-
}
|
|
19
|
+
} from './graphOperations';
|
|
20
|
+
import type {DeltaResult, Graph, Options} from './types.flow';
|
|
21
|
+
|
|
21
22
|
const {EventEmitter} = require('events');
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -33,6 +34,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
33
34
|
_currentBuildPromise: ?Promise<DeltaResult<T>>;
|
|
34
35
|
_deletedFiles: Set<string> = new Set();
|
|
35
36
|
_modifiedFiles: Set<string> = new Set();
|
|
37
|
+
_addedFiles: Set<string> = new Set();
|
|
36
38
|
|
|
37
39
|
_graph: Graph<T>;
|
|
38
40
|
|
|
@@ -72,6 +74,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
72
74
|
});
|
|
73
75
|
this._modifiedFiles = new Set();
|
|
74
76
|
this._deletedFiles = new Set();
|
|
77
|
+
this._addedFiles = new Set();
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
/**
|
|
@@ -99,6 +102,8 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
99
102
|
this._modifiedFiles = new Set();
|
|
100
103
|
const deletedFiles = this._deletedFiles;
|
|
101
104
|
this._deletedFiles = new Set();
|
|
105
|
+
const addedFiles = this._addedFiles;
|
|
106
|
+
this._addedFiles = new Set();
|
|
102
107
|
|
|
103
108
|
// Concurrent requests should reuse the same bundling process. To do so,
|
|
104
109
|
// this method stores the promise as an instance variable, and then it's
|
|
@@ -106,6 +111,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
106
111
|
this._currentBuildPromise = this._getChangedDependencies(
|
|
107
112
|
modifiedFiles,
|
|
108
113
|
deletedFiles,
|
|
114
|
+
addedFiles,
|
|
109
115
|
);
|
|
110
116
|
|
|
111
117
|
let result;
|
|
@@ -121,6 +127,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
121
127
|
// which is not correct.
|
|
122
128
|
modifiedFiles.forEach((file: string) => this._modifiedFiles.add(file));
|
|
123
129
|
deletedFiles.forEach((file: string) => this._deletedFiles.add(file));
|
|
130
|
+
addedFiles.forEach((file: string) => this._addedFiles.add(file));
|
|
124
131
|
|
|
125
132
|
// If after an error the number of modules has changed, we could be in
|
|
126
133
|
// a weird state. As a safe net we clean the dependency modules to force
|
|
@@ -158,6 +165,8 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
158
165
|
return this._graph;
|
|
159
166
|
}
|
|
160
167
|
|
|
168
|
+
/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
|
|
169
|
+
* LTI update could not be added via codemod */
|
|
161
170
|
_handleMultipleFileChanges = ({eventsQueue}) => {
|
|
162
171
|
eventsQueue.forEach(this._handleFileChange);
|
|
163
172
|
};
|
|
@@ -175,12 +184,45 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
175
184
|
filePath: string,
|
|
176
185
|
...
|
|
177
186
|
}): mixed => {
|
|
187
|
+
let state: void | 'deleted' | 'modified' | 'added';
|
|
188
|
+
if (this._deletedFiles.has(filePath)) {
|
|
189
|
+
state = 'deleted';
|
|
190
|
+
} else if (this._modifiedFiles.has(filePath)) {
|
|
191
|
+
state = 'modified';
|
|
192
|
+
} else if (this._addedFiles.has(filePath)) {
|
|
193
|
+
state = 'added';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let nextState: 'deleted' | 'modified' | 'added';
|
|
178
197
|
if (type === 'delete') {
|
|
179
|
-
|
|
180
|
-
|
|
198
|
+
nextState = 'deleted';
|
|
199
|
+
} else if (type === 'add') {
|
|
200
|
+
// A deleted+added file is modified
|
|
201
|
+
nextState = state === 'deleted' ? 'modified' : 'added';
|
|
181
202
|
} else {
|
|
182
|
-
|
|
183
|
-
|
|
203
|
+
// type === 'change'
|
|
204
|
+
// An added+modified file is added
|
|
205
|
+
nextState = state === 'added' ? 'added' : 'modified';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
switch (nextState) {
|
|
209
|
+
case 'deleted':
|
|
210
|
+
this._deletedFiles.add(filePath);
|
|
211
|
+
this._modifiedFiles.delete(filePath);
|
|
212
|
+
this._addedFiles.delete(filePath);
|
|
213
|
+
break;
|
|
214
|
+
case 'added':
|
|
215
|
+
this._addedFiles.add(filePath);
|
|
216
|
+
this._deletedFiles.delete(filePath);
|
|
217
|
+
this._modifiedFiles.delete(filePath);
|
|
218
|
+
break;
|
|
219
|
+
case 'modified':
|
|
220
|
+
this._modifiedFiles.add(filePath);
|
|
221
|
+
this._deletedFiles.delete(filePath);
|
|
222
|
+
this._addedFiles.delete(filePath);
|
|
223
|
+
break;
|
|
224
|
+
default:
|
|
225
|
+
(nextState: empty);
|
|
184
226
|
}
|
|
185
227
|
|
|
186
228
|
// Notify users that there is a change in some of the bundle files. This
|
|
@@ -191,6 +233,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
191
233
|
async _getChangedDependencies(
|
|
192
234
|
modifiedFiles: Set<string>,
|
|
193
235
|
deletedFiles: Set<string>,
|
|
236
|
+
addedFiles: Set<string>,
|
|
194
237
|
): Promise<DeltaResult<T>> {
|
|
195
238
|
if (!this._graph.dependencies.size) {
|
|
196
239
|
const {added} = await initialTraverseDependencies(
|
|
@@ -222,6 +265,18 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
222
265
|
}
|
|
223
266
|
});
|
|
224
267
|
|
|
268
|
+
// NOTE(EvanBacon): This check adds extra complexity so we feature gate it
|
|
269
|
+
// to enable users to opt out.
|
|
270
|
+
if (this._options.unstable_allowRequireContext) {
|
|
271
|
+
// Check if any added or removed files are matched in a context module.
|
|
272
|
+
// We only need to do this for added files because (1) deleted files will have a context
|
|
273
|
+
// module as an inverse dependency, (2) modified files don't invalidate the contents
|
|
274
|
+
// of the context module.
|
|
275
|
+
addedFiles.forEach(filePath => {
|
|
276
|
+
markModifiedContextModules(this._graph, filePath, modifiedFiles);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
225
280
|
// We only want to process files that are in the bundle.
|
|
226
281
|
const modifiedDependencies = Array.from(modifiedFiles).filter(
|
|
227
282
|
(filePath: string) => this._graph.dependencies.has(filePath),
|
|
@@ -36,9 +36,7 @@ function generateModules(
|
|
|
36
36
|
for (const module of sourceModules) {
|
|
37
37
|
if (isJsModule(module)) {
|
|
38
38
|
// Construct a bundle URL for this specific module only
|
|
39
|
-
const getURL = (
|
|
40
|
-
extension: $TEMPORARY$string<'bundle'> | $TEMPORARY$string<'map'>,
|
|
41
|
-
) => {
|
|
39
|
+
const getURL = (extension: 'bundle' | 'map') => {
|
|
42
40
|
options.clientUrl.pathname = path.relative(
|
|
43
41
|
options.projectRoot,
|
|
44
42
|
path.join(
|
|
@@ -9,6 +9,12 @@
|
|
|
9
9
|
*/
|
|
10
10
|
"use strict";
|
|
11
11
|
|
|
12
|
+
var _crypto = _interopRequireDefault(require("crypto"));
|
|
13
|
+
|
|
14
|
+
function _interopRequireDefault(obj) {
|
|
15
|
+
return obj && obj.__esModule ? obj : { default: obj };
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
const getTransformCacheKey = require("./getTransformCacheKey");
|
|
13
19
|
|
|
14
20
|
const WorkerFarm = require("./WorkerFarm");
|
|
@@ -53,7 +59,7 @@ class Transformer {
|
|
|
53
59
|
this._baseHash = stableHash([globalCacheKey]).toString("binary");
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
async transformFile(filePath, transformerOptions) {
|
|
62
|
+
async transformFile(filePath, transformerOptions, fileBuffer) {
|
|
57
63
|
const cache = this._cache;
|
|
58
64
|
const {
|
|
59
65
|
customTransformOptions,
|
|
@@ -100,8 +106,17 @@ class Transformer {
|
|
|
100
106
|
unstable_disableES6Transforms,
|
|
101
107
|
unstable_transformProfile,
|
|
102
108
|
]);
|
|
103
|
-
|
|
104
|
-
|
|
109
|
+
let sha1;
|
|
110
|
+
|
|
111
|
+
if (fileBuffer) {
|
|
112
|
+
// Shortcut for virtual modules which provide the contents with the filename.
|
|
113
|
+
sha1 = _crypto.default
|
|
114
|
+
.createHash("sha1")
|
|
115
|
+
.update(fileBuffer)
|
|
116
|
+
.digest("hex");
|
|
117
|
+
} else {
|
|
118
|
+
sha1 = this._getSha1(filePath);
|
|
119
|
+
}
|
|
105
120
|
|
|
106
121
|
let fullKey = Buffer.concat([partialKey, Buffer.from(sha1, "hex")]);
|
|
107
122
|
const result = await cache.get(fullKey); // A valid result from the cache is used directly; otherwise we call into
|
|
@@ -112,7 +127,11 @@ class Transformer {
|
|
|
112
127
|
result,
|
|
113
128
|
sha1,
|
|
114
129
|
}
|
|
115
|
-
: await this._workerFarm.transform(
|
|
130
|
+
: await this._workerFarm.transform(
|
|
131
|
+
localPath,
|
|
132
|
+
transformerOptions,
|
|
133
|
+
fileBuffer
|
|
134
|
+
); // Only re-compute the full key if the SHA-1 changed. This is because
|
|
116
135
|
// references are used by the cache implementation in a weak map to keep
|
|
117
136
|
// track of the cache that returned the result.
|
|
118
137
|
|
|
@@ -125,6 +144,10 @@ class Transformer {
|
|
|
125
144
|
...data.result,
|
|
126
145
|
|
|
127
146
|
getSource() {
|
|
147
|
+
if (fileBuffer) {
|
|
148
|
+
return fileBuffer;
|
|
149
|
+
}
|
|
150
|
+
|
|
128
151
|
return fs.readFileSync(filePath);
|
|
129
152
|
},
|
|
130
153
|
};
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import type {TransformResult, TransformResultWithSource} from '../DeltaBundler';
|
|
14
14
|
import type {TransformerConfig, TransformOptions} from './Worker';
|
|
15
15
|
import type {ConfigT} from 'metro-config/src/configTypes.flow';
|
|
16
|
+
import crypto from 'crypto';
|
|
16
17
|
|
|
17
18
|
const getTransformCacheKey = require('./getTransformCacheKey');
|
|
18
19
|
const WorkerFarm = require('./WorkerFarm');
|
|
@@ -66,6 +67,7 @@ class Transformer {
|
|
|
66
67
|
async transformFile(
|
|
67
68
|
filePath: string,
|
|
68
69
|
transformerOptions: TransformOptions,
|
|
70
|
+
fileBuffer?: Buffer,
|
|
69
71
|
): Promise<TransformResultWithSource<>> {
|
|
70
72
|
const cache = this._cache;
|
|
71
73
|
|
|
@@ -119,7 +121,14 @@ class Transformer {
|
|
|
119
121
|
unstable_transformProfile,
|
|
120
122
|
]);
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
let sha1: string;
|
|
125
|
+
if (fileBuffer) {
|
|
126
|
+
// Shortcut for virtual modules which provide the contents with the filename.
|
|
127
|
+
sha1 = crypto.createHash('sha1').update(fileBuffer).digest('hex');
|
|
128
|
+
} else {
|
|
129
|
+
sha1 = this._getSha1(filePath);
|
|
130
|
+
}
|
|
131
|
+
|
|
123
132
|
let fullKey = Buffer.concat([partialKey, Buffer.from(sha1, 'hex')]);
|
|
124
133
|
const result = await cache.get(fullKey);
|
|
125
134
|
|
|
@@ -127,7 +136,11 @@ class Transformer {
|
|
|
127
136
|
// the transformer to computed the corresponding result.
|
|
128
137
|
const data = result
|
|
129
138
|
? {result, sha1}
|
|
130
|
-
: await this._workerFarm.transform(
|
|
139
|
+
: await this._workerFarm.transform(
|
|
140
|
+
localPath,
|
|
141
|
+
transformerOptions,
|
|
142
|
+
fileBuffer,
|
|
143
|
+
);
|
|
131
144
|
|
|
132
145
|
// Only re-compute the full key if the SHA-1 changed. This is because
|
|
133
146
|
// references are used by the cache implementation in a weak map to keep
|
|
@@ -141,6 +154,9 @@ class Transformer {
|
|
|
141
154
|
return {
|
|
142
155
|
...data.result,
|
|
143
156
|
getSource(): Buffer {
|
|
157
|
+
if (fileBuffer) {
|
|
158
|
+
return fileBuffer;
|
|
159
|
+
}
|
|
144
160
|
return fs.readFileSync(filePath);
|
|
145
161
|
},
|
|
146
162
|
};
|
|
@@ -17,10 +17,55 @@ const fs = require("fs");
|
|
|
17
17
|
|
|
18
18
|
const path = require("path");
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* When the `Buffer` is sent over the worker thread it gets serialized into a JSON object.
|
|
22
|
+
* This helper method will deserialize it if needed.
|
|
23
|
+
*
|
|
24
|
+
* @returns `Buffer` representation of the JSON object.
|
|
25
|
+
* @returns `null` if the given object is nullish or not a serialized `Buffer` object.
|
|
26
|
+
*/
|
|
27
|
+
function asDeserializedBuffer(value) {
|
|
28
|
+
if (Buffer.isBuffer(value)) {
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (value && value.type === "Buffer") {
|
|
33
|
+
return Buffer.from(value.data);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
20
39
|
async function transform(
|
|
21
40
|
filename,
|
|
22
41
|
transformOptions,
|
|
23
42
|
projectRoot,
|
|
43
|
+
transformerConfig,
|
|
44
|
+
fileBuffer
|
|
45
|
+
) {
|
|
46
|
+
let data;
|
|
47
|
+
const fileBufferObject = asDeserializedBuffer(fileBuffer);
|
|
48
|
+
|
|
49
|
+
if (fileBufferObject) {
|
|
50
|
+
data = fileBufferObject;
|
|
51
|
+
} else {
|
|
52
|
+
data = fs.readFileSync(path.resolve(projectRoot, filename));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return transformFile(
|
|
56
|
+
filename,
|
|
57
|
+
data,
|
|
58
|
+
transformOptions,
|
|
59
|
+
projectRoot,
|
|
60
|
+
transformerConfig
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function transformFile(
|
|
65
|
+
filename,
|
|
66
|
+
data,
|
|
67
|
+
transformOptions,
|
|
68
|
+
projectRoot,
|
|
24
69
|
transformerConfig
|
|
25
70
|
) {
|
|
26
71
|
// eslint-disable-next-line no-useless-call
|
|
@@ -33,7 +78,6 @@ async function transform(
|
|
|
33
78
|
log_entry_label: "Transforming file",
|
|
34
79
|
start_timestamp: process.hrtime(),
|
|
35
80
|
};
|
|
36
|
-
const data = fs.readFileSync(path.resolve(projectRoot, filename));
|
|
37
81
|
const sha1 = crypto.createHash("sha1").update(data).digest("hex");
|
|
38
82
|
const result = await Transformer.transform(
|
|
39
83
|
transformerConfig.transformerConfig,
|