metro 0.74.1 → 0.75.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 +26 -23
- package/src/DeltaBundler/DeltaCalculator.js +34 -3
- package/src/DeltaBundler/DeltaCalculator.js.flow +29 -3
- package/src/DeltaBundler/WorkerFarm.js +1 -0
- package/src/DeltaBundler/WorkerFarm.js.flow +1 -0
- package/src/DeltaBundler/types.flow.js.flow +1 -0
- package/src/IncrementalBundler.js +4 -0
- package/src/IncrementalBundler.js.flow +4 -0
- package/src/Server.js +6 -1
- package/src/Server.js.flow +6 -1
- package/src/integration_tests/basic_bundle/require-context/mode-sync.js +1 -0
- package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +1 -0
- package/src/lib/TerminalReporter.js +6 -0
- package/src/lib/TerminalReporter.js.flow +7 -0
- package/src/lib/formatBundlingError.js +3 -0
- package/src/lib/formatBundlingError.js.flow +3 -0
- package/src/lib/getPrependedScripts.js +2 -0
- package/src/lib/getPrependedScripts.js.flow +2 -0
- package/src/lib/reporting.js.flow +4 -0
- package/src/lib/transformHelpers.js +2 -0
- package/src/lib/transformHelpers.js.flow +2 -0
- package/src/node-haste/DependencyGraph/ModuleResolution.js +67 -60
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +83 -72
- package/src/node-haste/DependencyGraph/createHasteMap.js +1 -1
- package/src/node-haste/DependencyGraph/createHasteMap.js.flow +1 -1
- package/src/node-haste/DependencyGraph.js +22 -5
- package/src/node-haste/DependencyGraph.js.flow +24 -4
- package/src/node-haste/Package.js +0 -92
- package/src/node-haste/Package.js.flow +4 -126
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.1",
|
|
4
4
|
"description": "🚇 The JavaScript bundler for React Native.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": "src/cli.js",
|
|
@@ -35,23 +35,23 @@
|
|
|
35
35
|
"invariant": "^2.2.4",
|
|
36
36
|
"jest-worker": "^27.2.0",
|
|
37
37
|
"lodash.throttle": "^4.1.1",
|
|
38
|
-
"metro-babel-transformer": "0.
|
|
39
|
-
"metro-cache": "0.
|
|
40
|
-
"metro-cache-key": "0.
|
|
41
|
-
"metro-config": "0.
|
|
42
|
-
"metro-core": "0.
|
|
43
|
-
"metro-file-map": "0.
|
|
44
|
-
"metro-hermes-compiler": "0.
|
|
45
|
-
"metro-inspector-proxy": "0.
|
|
46
|
-
"metro-minify-terser": "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.
|
|
38
|
+
"metro-babel-transformer": "0.75.1",
|
|
39
|
+
"metro-cache": "0.75.1",
|
|
40
|
+
"metro-cache-key": "0.75.1",
|
|
41
|
+
"metro-config": "0.75.1",
|
|
42
|
+
"metro-core": "0.75.1",
|
|
43
|
+
"metro-file-map": "0.75.1",
|
|
44
|
+
"metro-hermes-compiler": "0.75.1",
|
|
45
|
+
"metro-inspector-proxy": "0.75.1",
|
|
46
|
+
"metro-minify-terser": "0.75.1",
|
|
47
|
+
"metro-minify-uglify": "0.75.1",
|
|
48
|
+
"metro-react-native-babel-preset": "0.75.1",
|
|
49
|
+
"metro-resolver": "0.75.1",
|
|
50
|
+
"metro-runtime": "0.75.1",
|
|
51
|
+
"metro-source-map": "0.75.1",
|
|
52
|
+
"metro-symbolicate": "0.75.1",
|
|
53
|
+
"metro-transform-plugins": "0.75.1",
|
|
54
|
+
"metro-transform-worker": "0.75.1",
|
|
55
55
|
"mime-types": "^2.1.27",
|
|
56
56
|
"node-fetch": "^2.2.0",
|
|
57
57
|
"nullthrows": "^1.1.1",
|
|
@@ -70,13 +70,16 @@
|
|
|
70
70
|
"dedent": "^0.7.0",
|
|
71
71
|
"jest-snapshot": "^26.5.2",
|
|
72
72
|
"jest-snapshot-serializer-raw": "^1.2.0",
|
|
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.75.1",
|
|
74
|
+
"metro-memory-fs": "0.75.1",
|
|
75
|
+
"metro-react-native-babel-preset": "0.75.1",
|
|
76
|
+
"metro-react-native-babel-transformer": "0.75.1",
|
|
77
77
|
"mock-req": "^0.2.0",
|
|
78
78
|
"mock-res": "^0.6.0",
|
|
79
79
|
"stack-trace": "^0.0.10"
|
|
80
80
|
},
|
|
81
|
-
"license": "MIT"
|
|
81
|
+
"license": "MIT",
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=14.17.0"
|
|
84
|
+
}
|
|
82
85
|
}
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
"use strict";
|
|
13
13
|
|
|
14
|
+
var _path = _interopRequireDefault(require("path"));
|
|
14
15
|
var _Graph = require("./Graph");
|
|
16
|
+
function _interopRequireDefault(obj) {
|
|
17
|
+
return obj && obj.__esModule ? obj : { default: obj };
|
|
18
|
+
}
|
|
15
19
|
const debug = require("debug")("Metro:DeltaCalculator");
|
|
16
20
|
const { EventEmitter } = require("events");
|
|
17
21
|
|
|
@@ -25,6 +29,7 @@ class DeltaCalculator extends EventEmitter {
|
|
|
25
29
|
_deletedFiles = new Set();
|
|
26
30
|
_modifiedFiles = new Set();
|
|
27
31
|
_addedFiles = new Set();
|
|
32
|
+
_requiresReset = false;
|
|
28
33
|
constructor(entryPoints, changeEventSource, options) {
|
|
29
34
|
super();
|
|
30
35
|
this._options = options;
|
|
@@ -61,6 +66,7 @@ class DeltaCalculator extends EventEmitter {
|
|
|
61
66
|
* which contain the modified/added modules and the removed modules.
|
|
62
67
|
*/
|
|
63
68
|
async getDelta({ reset, shallow }) {
|
|
69
|
+
debug("Calculating delta (reset: %s, shallow: %s)", reset, shallow);
|
|
64
70
|
// If there is already a build in progress, wait until it finish to start
|
|
65
71
|
// processing a new one (delta server doesn't support concurrent builds).
|
|
66
72
|
if (this._currentBuildPromise) {
|
|
@@ -76,6 +82,21 @@ class DeltaCalculator extends EventEmitter {
|
|
|
76
82
|
this._deletedFiles = new Set();
|
|
77
83
|
const addedFiles = this._addedFiles;
|
|
78
84
|
this._addedFiles = new Set();
|
|
85
|
+
const requiresReset = this._requiresReset;
|
|
86
|
+
this._requiresReset = false;
|
|
87
|
+
|
|
88
|
+
// Revisit all files if changes require a graph reset - resolutions may be
|
|
89
|
+
// invalidated but we don't yet know which. This should be optimized in the
|
|
90
|
+
// future.
|
|
91
|
+
if (requiresReset) {
|
|
92
|
+
const markModified = (file) => {
|
|
93
|
+
if (!addedFiles.has(file) && !deletedFiles.has(file)) {
|
|
94
|
+
modifiedFiles.add(file);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
this._graph.dependencies.forEach((_, key) => markModified(key));
|
|
98
|
+
this._graph.entryPoints.forEach(markModified);
|
|
99
|
+
}
|
|
79
100
|
|
|
80
101
|
// Concurrent requests should reuse the same bundling process. To do so,
|
|
81
102
|
// this method stores the promise as an instance variable, and then it's
|
|
@@ -148,6 +169,16 @@ class DeltaCalculator extends EventEmitter {
|
|
|
148
169
|
*/
|
|
149
170
|
_handleFileChange = ({ type, filePath, metadata }, logger) => {
|
|
150
171
|
debug("Handling %s: %s (type: %s)", type, filePath, metadata.type);
|
|
172
|
+
if (
|
|
173
|
+
metadata.type === "l" ||
|
|
174
|
+
(this._options.unstable_enablePackageExports &&
|
|
175
|
+
filePath.endsWith(_path.default.sep + "package.json"))
|
|
176
|
+
) {
|
|
177
|
+
this._requiresReset = true;
|
|
178
|
+
this.emit("change", {
|
|
179
|
+
logger,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
151
182
|
let state;
|
|
152
183
|
if (this._deletedFiles.has(filePath)) {
|
|
153
184
|
state = "deleted";
|
|
@@ -209,13 +240,13 @@ class DeltaCalculator extends EventEmitter {
|
|
|
209
240
|
// If a file has been deleted, we want to invalidate any other file that
|
|
210
241
|
// depends on it, so we can process it and correctly return an error.
|
|
211
242
|
deletedFiles.forEach((filePath) => {
|
|
212
|
-
for (const
|
|
243
|
+
for (const modifiedModulePath of this._graph.getModifiedModulesForDeletedPath(
|
|
213
244
|
filePath
|
|
214
245
|
)) {
|
|
215
246
|
// Only mark the inverse dependency as modified if it's not already
|
|
216
247
|
// marked as deleted (in that case we can just ignore it).
|
|
217
|
-
if (!deletedFiles.has(
|
|
218
|
-
modifiedFiles.add(
|
|
248
|
+
if (!deletedFiles.has(modifiedModulePath)) {
|
|
249
|
+
modifiedFiles.add(modifiedModulePath);
|
|
219
250
|
}
|
|
220
251
|
}
|
|
221
252
|
});
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
import path from 'path';
|
|
14
15
|
import {Graph} from './Graph';
|
|
15
16
|
import type {DeltaResult, Options} from './types.flow';
|
|
16
17
|
import type {RootPerfLogger} from 'metro-config';
|
|
@@ -33,6 +34,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
33
34
|
_deletedFiles: Set<string> = new Set();
|
|
34
35
|
_modifiedFiles: Set<string> = new Set();
|
|
35
36
|
_addedFiles: Set<string> = new Set();
|
|
37
|
+
_requiresReset = false;
|
|
36
38
|
|
|
37
39
|
_graph: Graph<T>;
|
|
38
40
|
|
|
@@ -87,6 +89,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
87
89
|
shallow: boolean,
|
|
88
90
|
...
|
|
89
91
|
}): Promise<DeltaResult<T>> {
|
|
92
|
+
debug('Calculating delta (reset: %s, shallow: %s)', reset, shallow);
|
|
90
93
|
// If there is already a build in progress, wait until it finish to start
|
|
91
94
|
// processing a new one (delta server doesn't support concurrent builds).
|
|
92
95
|
if (this._currentBuildPromise) {
|
|
@@ -102,6 +105,21 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
102
105
|
this._deletedFiles = new Set();
|
|
103
106
|
const addedFiles = this._addedFiles;
|
|
104
107
|
this._addedFiles = new Set();
|
|
108
|
+
const requiresReset = this._requiresReset;
|
|
109
|
+
this._requiresReset = false;
|
|
110
|
+
|
|
111
|
+
// Revisit all files if changes require a graph reset - resolutions may be
|
|
112
|
+
// invalidated but we don't yet know which. This should be optimized in the
|
|
113
|
+
// future.
|
|
114
|
+
if (requiresReset) {
|
|
115
|
+
const markModified = (file: string) => {
|
|
116
|
+
if (!addedFiles.has(file) && !deletedFiles.has(file)) {
|
|
117
|
+
modifiedFiles.add(file);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
this._graph.dependencies.forEach((_, key) => markModified(key));
|
|
121
|
+
this._graph.entryPoints.forEach(markModified);
|
|
122
|
+
}
|
|
105
123
|
|
|
106
124
|
// Concurrent requests should reuse the same bundling process. To do so,
|
|
107
125
|
// this method stores the promise as an instance variable, and then it's
|
|
@@ -190,6 +208,14 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
190
208
|
logger: ?RootPerfLogger,
|
|
191
209
|
): mixed => {
|
|
192
210
|
debug('Handling %s: %s (type: %s)', type, filePath, metadata.type);
|
|
211
|
+
if (
|
|
212
|
+
metadata.type === 'l' ||
|
|
213
|
+
(this._options.unstable_enablePackageExports &&
|
|
214
|
+
filePath.endsWith(path.sep + 'package.json'))
|
|
215
|
+
) {
|
|
216
|
+
this._requiresReset = true;
|
|
217
|
+
this.emit('change', {logger});
|
|
218
|
+
}
|
|
193
219
|
let state: void | 'deleted' | 'modified' | 'added';
|
|
194
220
|
if (this._deletedFiles.has(filePath)) {
|
|
195
221
|
state = 'deleted';
|
|
@@ -259,13 +285,13 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
259
285
|
// If a file has been deleted, we want to invalidate any other file that
|
|
260
286
|
// depends on it, so we can process it and correctly return an error.
|
|
261
287
|
deletedFiles.forEach((filePath: string) => {
|
|
262
|
-
for (const
|
|
288
|
+
for (const modifiedModulePath of this._graph.getModifiedModulesForDeletedPath(
|
|
263
289
|
filePath,
|
|
264
290
|
)) {
|
|
265
291
|
// Only mark the inverse dependency as modified if it's not already
|
|
266
292
|
// marked as deleted (in that case we can just ignore it).
|
|
267
|
-
if (!deletedFiles.has(
|
|
268
|
-
modifiedFiles.add(
|
|
293
|
+
if (!deletedFiles.has(modifiedModulePath)) {
|
|
294
|
+
modifiedFiles.add(modifiedModulePath);
|
|
269
295
|
}
|
|
270
296
|
}
|
|
271
297
|
});
|
|
@@ -78,6 +78,7 @@ class WorkerFarm {
|
|
|
78
78
|
return new JestWorker(workerPath, {
|
|
79
79
|
computeWorkerKey: this._config.stickyWorkers
|
|
80
80
|
? // $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
|
81
|
+
// $FlowFixMe[incompatible-call]
|
|
81
82
|
this._computeWorkerKey
|
|
82
83
|
: undefined,
|
|
83
84
|
exposedMethods,
|
|
@@ -120,6 +120,7 @@ class WorkerFarm {
|
|
|
120
120
|
return new JestWorker(workerPath, {
|
|
121
121
|
computeWorkerKey: this._config.stickyWorkers
|
|
122
122
|
? // $FlowFixMe[method-unbinding] added when improving typing for this parameters
|
|
123
|
+
// $FlowFixMe[incompatible-call]
|
|
123
124
|
this._computeWorkerKey
|
|
124
125
|
: undefined,
|
|
125
126
|
exposedMethods,
|
|
@@ -138,6 +138,7 @@ export type Options<T = MixedOutput> = {
|
|
|
138
138
|
+onProgress: ?(numProcessed: number, total: number) => mixed,
|
|
139
139
|
+experimentalImportBundleSupport: boolean,
|
|
140
140
|
+unstable_allowRequireContext: boolean,
|
|
141
|
+
+unstable_enablePackageExports: boolean,
|
|
141
142
|
+shallow: boolean,
|
|
142
143
|
};
|
|
143
144
|
|
|
@@ -81,6 +81,8 @@ class IncrementalBundler {
|
|
|
81
81
|
this._config.server.experimentalImportBundleSupport,
|
|
82
82
|
unstable_allowRequireContext:
|
|
83
83
|
this._config.transformer.unstable_allowRequireContext,
|
|
84
|
+
unstable_enablePackageExports:
|
|
85
|
+
this._config.resolver.unstable_enablePackageExports,
|
|
84
86
|
shallow: otherOptions.shallow,
|
|
85
87
|
});
|
|
86
88
|
this._config.serializer.experimentalSerializerHook(graph, {
|
|
@@ -123,6 +125,8 @@ class IncrementalBundler {
|
|
|
123
125
|
this._config.server.experimentalImportBundleSupport,
|
|
124
126
|
unstable_allowRequireContext:
|
|
125
127
|
this._config.transformer.unstable_allowRequireContext,
|
|
128
|
+
unstable_enablePackageExports:
|
|
129
|
+
this._config.resolver.unstable_enablePackageExports,
|
|
126
130
|
shallow: otherOptions.shallow,
|
|
127
131
|
}
|
|
128
132
|
);
|
|
@@ -130,6 +130,8 @@ class IncrementalBundler {
|
|
|
130
130
|
this._config.server.experimentalImportBundleSupport,
|
|
131
131
|
unstable_allowRequireContext:
|
|
132
132
|
this._config.transformer.unstable_allowRequireContext,
|
|
133
|
+
unstable_enablePackageExports:
|
|
134
|
+
this._config.resolver.unstable_enablePackageExports,
|
|
133
135
|
shallow: otherOptions.shallow,
|
|
134
136
|
});
|
|
135
137
|
|
|
@@ -176,6 +178,8 @@ class IncrementalBundler {
|
|
|
176
178
|
this._config.server.experimentalImportBundleSupport,
|
|
177
179
|
unstable_allowRequireContext:
|
|
178
180
|
this._config.transformer.unstable_allowRequireContext,
|
|
181
|
+
unstable_enablePackageExports:
|
|
182
|
+
this._config.resolver.unstable_enablePackageExports,
|
|
179
183
|
shallow: otherOptions.shallow,
|
|
180
184
|
},
|
|
181
185
|
);
|
package/src/Server.js
CHANGED
|
@@ -392,7 +392,7 @@ class Server {
|
|
|
392
392
|
bundlePerfLogger:
|
|
393
393
|
(_this$_config$unstabl =
|
|
394
394
|
(_this$_config$unstabl2 = (_this$_config = this._config)
|
|
395
|
-
.
|
|
395
|
+
.unstable_perfLoggerFactory) === null ||
|
|
396
396
|
_this$_config$unstabl2 === void 0
|
|
397
397
|
? void 0
|
|
398
398
|
: _this$_config$unstabl2.call(
|
|
@@ -668,6 +668,11 @@ class Server {
|
|
|
668
668
|
});
|
|
669
669
|
const revPromise = this._bundler.getRevisionByGraphId(graphId);
|
|
670
670
|
bundlePerfLogger.point("resolvingAndTransformingDependencies_start");
|
|
671
|
+
bundlePerfLogger.annotate({
|
|
672
|
+
bool: {
|
|
673
|
+
initial_build: revPromise == null,
|
|
674
|
+
},
|
|
675
|
+
});
|
|
671
676
|
const { delta, revision } = await (revPromise != null
|
|
672
677
|
? this._bundler.updateGraph(await revPromise, false)
|
|
673
678
|
: this._bundler.initializeGraph(
|
package/src/Server.js.flow
CHANGED
|
@@ -519,7 +519,7 @@ class Server {
|
|
|
519
519
|
await this._processBundleRequest(req, res, options, {
|
|
520
520
|
buildNumber,
|
|
521
521
|
bundlePerfLogger:
|
|
522
|
-
this._config.
|
|
522
|
+
this._config.unstable_perfLoggerFactory?.('BUNDLING_REQUEST', {
|
|
523
523
|
key: buildNumber,
|
|
524
524
|
}) ?? noopLogger,
|
|
525
525
|
});
|
|
@@ -832,6 +832,11 @@ class Server {
|
|
|
832
832
|
const revPromise = this._bundler.getRevisionByGraphId(graphId);
|
|
833
833
|
|
|
834
834
|
bundlePerfLogger.point('resolvingAndTransformingDependencies_start');
|
|
835
|
+
bundlePerfLogger.annotate({
|
|
836
|
+
bool: {
|
|
837
|
+
initial_build: revPromise == null,
|
|
838
|
+
},
|
|
839
|
+
});
|
|
835
840
|
const {delta, revision} = await (revPromise != null
|
|
836
841
|
? this._bundler.updateGraph(await revPromise, false)
|
|
837
842
|
: this._bundler.initializeGraph(
|
|
@@ -203,6 +203,9 @@ class TerminalReporter {
|
|
|
203
203
|
case "global_cache_disabled":
|
|
204
204
|
this._logCacheDisabled(event.reason);
|
|
205
205
|
break;
|
|
206
|
+
case "resolver_warning":
|
|
207
|
+
this._logWarning(event.message);
|
|
208
|
+
break;
|
|
206
209
|
case "transform_cache_reset":
|
|
207
210
|
reporting.logWarning(this.terminal, "the transform cache was reset.");
|
|
208
211
|
break;
|
|
@@ -360,6 +363,9 @@ class TerminalReporter {
|
|
|
360
363
|
e
|
|
361
364
|
);
|
|
362
365
|
}
|
|
366
|
+
_logWarning(message) {
|
|
367
|
+
reporting.logWarning(this.terminal, message);
|
|
368
|
+
}
|
|
363
369
|
_logWatcherHealthCheckResult(result) {
|
|
364
370
|
var _result$pauseReason, _this$_prevHealthChec;
|
|
365
371
|
// Don't be spammy; only report changes in status.
|
|
@@ -260,6 +260,9 @@ class TerminalReporter {
|
|
|
260
260
|
case 'global_cache_disabled':
|
|
261
261
|
this._logCacheDisabled(event.reason);
|
|
262
262
|
break;
|
|
263
|
+
case 'resolver_warning':
|
|
264
|
+
this._logWarning(event.message);
|
|
265
|
+
break;
|
|
263
266
|
case 'transform_cache_reset':
|
|
264
267
|
reporting.logWarning(this.terminal, 'the transform cache was reset.');
|
|
265
268
|
break;
|
|
@@ -435,6 +438,10 @@ class TerminalReporter {
|
|
|
435
438
|
);
|
|
436
439
|
}
|
|
437
440
|
|
|
441
|
+
_logWarning(message: string): void {
|
|
442
|
+
reporting.logWarning(this.terminal, message);
|
|
443
|
+
}
|
|
444
|
+
|
|
438
445
|
_logWatcherHealthCheckResult(result: HealthCheckResult) {
|
|
439
446
|
// Don't be spammy; only report changes in status.
|
|
440
447
|
if (
|
|
@@ -60,6 +60,7 @@ function formatBundlingError(error) {
|
|
|
60
60
|
return {
|
|
61
61
|
type: "ResourceNotFoundError",
|
|
62
62
|
// $FlowFixMe[missing-empty-array-annot]
|
|
63
|
+
// $FlowFixMe[incompatible-return]
|
|
63
64
|
errors: [],
|
|
64
65
|
message: error.message,
|
|
65
66
|
};
|
|
@@ -67,6 +68,7 @@ function formatBundlingError(error) {
|
|
|
67
68
|
return {
|
|
68
69
|
type: "GraphNotFoundError",
|
|
69
70
|
// $FlowFixMe[missing-empty-array-annot]
|
|
71
|
+
// $FlowFixMe[incompatible-return]
|
|
70
72
|
errors: [],
|
|
71
73
|
message: error.message,
|
|
72
74
|
};
|
|
@@ -74,6 +76,7 @@ function formatBundlingError(error) {
|
|
|
74
76
|
return {
|
|
75
77
|
type: "RevisionNotFoundError",
|
|
76
78
|
// $FlowFixMe[missing-empty-array-annot]
|
|
79
|
+
// $FlowFixMe[incompatible-return]
|
|
77
80
|
errors: [],
|
|
78
81
|
message: error.message,
|
|
79
82
|
};
|
|
@@ -75,6 +75,7 @@ function formatBundlingError(error: CustomError): FormattedError {
|
|
|
75
75
|
return {
|
|
76
76
|
type: 'ResourceNotFoundError',
|
|
77
77
|
// $FlowFixMe[missing-empty-array-annot]
|
|
78
|
+
// $FlowFixMe[incompatible-return]
|
|
78
79
|
errors: [],
|
|
79
80
|
message: error.message,
|
|
80
81
|
};
|
|
@@ -82,6 +83,7 @@ function formatBundlingError(error: CustomError): FormattedError {
|
|
|
82
83
|
return {
|
|
83
84
|
type: 'GraphNotFoundError',
|
|
84
85
|
// $FlowFixMe[missing-empty-array-annot]
|
|
86
|
+
// $FlowFixMe[incompatible-return]
|
|
85
87
|
errors: [],
|
|
86
88
|
message: error.message,
|
|
87
89
|
};
|
|
@@ -89,6 +91,7 @@ function formatBundlingError(error: CustomError): FormattedError {
|
|
|
89
91
|
return {
|
|
90
92
|
type: 'RevisionNotFoundError',
|
|
91
93
|
// $FlowFixMe[missing-empty-array-annot]
|
|
94
|
+
// $FlowFixMe[incompatible-return]
|
|
92
95
|
errors: [],
|
|
93
96
|
message: error.message,
|
|
94
97
|
};
|
|
@@ -67,6 +67,8 @@ async function calcTransformerOptions(
|
|
|
67
67
|
config.server.experimentalImportBundleSupport,
|
|
68
68
|
unstable_allowRequireContext:
|
|
69
69
|
config.transformer.unstable_allowRequireContext,
|
|
70
|
+
unstable_enablePackageExports:
|
|
71
|
+
config.resolver.unstable_enablePackageExports,
|
|
70
72
|
shallow: false,
|
|
71
73
|
});
|
|
72
74
|
return Array.from(dependencies.keys());
|
|
@@ -90,6 +90,8 @@ async function calcTransformerOptions(
|
|
|
90
90
|
config.server.experimentalImportBundleSupport,
|
|
91
91
|
unstable_allowRequireContext:
|
|
92
92
|
config.transformer.unstable_allowRequireContext,
|
|
93
|
+
unstable_enablePackageExports:
|
|
94
|
+
config.resolver.unstable_enablePackageExports,
|
|
93
95
|
shallow: false,
|
|
94
96
|
});
|
|
95
97
|
|
|
@@ -15,6 +15,7 @@ const { codeFrameColumns } = require("@babel/code-frame");
|
|
|
15
15
|
const fs = require("fs");
|
|
16
16
|
const invariant = require("invariant");
|
|
17
17
|
const Resolver = require("metro-resolver");
|
|
18
|
+
const createDefaultContext = require("metro-resolver/src/createDefaultContext");
|
|
18
19
|
const path = require("path");
|
|
19
20
|
const util = require("util");
|
|
20
21
|
class ModuleResolver {
|
|
@@ -52,53 +53,6 @@ class ModuleResolver {
|
|
|
52
53
|
}
|
|
53
54
|
return emptyModule;
|
|
54
55
|
}
|
|
55
|
-
_redirectRequire(fromModule, modulePath) {
|
|
56
|
-
const moduleCache = this._options.moduleCache;
|
|
57
|
-
try {
|
|
58
|
-
if (modulePath.startsWith(".")) {
|
|
59
|
-
const fromPackage = fromModule.getPackage();
|
|
60
|
-
if (fromPackage) {
|
|
61
|
-
// We need to convert the module path from module-relative to
|
|
62
|
-
// package-relative, so that we can easily match it against the
|
|
63
|
-
// "browser" map (where all paths are relative to the package root)
|
|
64
|
-
const fromPackagePath =
|
|
65
|
-
"./" +
|
|
66
|
-
path.relative(
|
|
67
|
-
path.dirname(fromPackage.path),
|
|
68
|
-
path.resolve(path.dirname(fromModule.path), modulePath)
|
|
69
|
-
);
|
|
70
|
-
let redirectedPath = fromPackage.redirectRequire(
|
|
71
|
-
fromPackagePath,
|
|
72
|
-
this._options.mainFields
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
// Since the redirected path is still relative to the package root,
|
|
76
|
-
// we have to transform it back to be module-relative (as it
|
|
77
|
-
// originally was)
|
|
78
|
-
if (redirectedPath !== false) {
|
|
79
|
-
redirectedPath =
|
|
80
|
-
"./" +
|
|
81
|
-
path.relative(
|
|
82
|
-
path.dirname(fromModule.path),
|
|
83
|
-
path.resolve(path.dirname(fromPackage.path), redirectedPath)
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
return redirectedPath;
|
|
87
|
-
}
|
|
88
|
-
} else {
|
|
89
|
-
const pck = path.isAbsolute(modulePath)
|
|
90
|
-
? moduleCache.getPackageOf(modulePath)
|
|
91
|
-
: fromModule.getPackage();
|
|
92
|
-
if (pck) {
|
|
93
|
-
return pck.redirectRequire(modulePath, this._options.mainFields);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
} catch (err) {
|
|
97
|
-
// Do nothing. The standard module cache does not trigger any error, but
|
|
98
|
-
// the ModuleGraph one does, if the module does not exist.
|
|
99
|
-
}
|
|
100
|
-
return modulePath;
|
|
101
|
-
}
|
|
102
56
|
resolveDependency(
|
|
103
57
|
fromModule,
|
|
104
58
|
moduleName,
|
|
@@ -106,29 +60,56 @@ class ModuleResolver {
|
|
|
106
60
|
platform,
|
|
107
61
|
resolverOptions
|
|
108
62
|
) {
|
|
63
|
+
const {
|
|
64
|
+
disableHierarchicalLookup,
|
|
65
|
+
doesFileExist,
|
|
66
|
+
extraNodeModules,
|
|
67
|
+
isAssetFile,
|
|
68
|
+
mainFields,
|
|
69
|
+
nodeModulesPaths,
|
|
70
|
+
preferNativePlatform,
|
|
71
|
+
resolveAsset,
|
|
72
|
+
resolveRequest,
|
|
73
|
+
sourceExts,
|
|
74
|
+
unstable_conditionNames,
|
|
75
|
+
unstable_conditionsByPlatform,
|
|
76
|
+
unstable_enablePackageExports,
|
|
77
|
+
unstable_getRealPath,
|
|
78
|
+
} = this._options;
|
|
109
79
|
try {
|
|
110
80
|
var _resolverOptions$cust;
|
|
111
81
|
const result = Resolver.resolve(
|
|
112
|
-
{
|
|
113
|
-
|
|
82
|
+
createDefaultContext({
|
|
83
|
+
allowHaste,
|
|
84
|
+
disableHierarchicalLookup,
|
|
85
|
+
doesFileExist,
|
|
86
|
+
extraNodeModules,
|
|
87
|
+
isAssetFile,
|
|
88
|
+
mainFields,
|
|
89
|
+
nodeModulesPaths,
|
|
90
|
+
preferNativePlatform,
|
|
91
|
+
resolveAsset,
|
|
92
|
+
resolveRequest,
|
|
93
|
+
sourceExts,
|
|
94
|
+
unstable_conditionNames,
|
|
95
|
+
unstable_conditionsByPlatform,
|
|
96
|
+
unstable_enablePackageExports,
|
|
97
|
+
unstable_getRealPath,
|
|
98
|
+
unstable_logWarning: this._logWarning,
|
|
114
99
|
customResolverOptions:
|
|
115
100
|
(_resolverOptions$cust = resolverOptions.customResolverOptions) !==
|
|
116
101
|
null && _resolverOptions$cust !== void 0
|
|
117
102
|
? _resolverOptions$cust
|
|
118
103
|
: {},
|
|
119
104
|
originModulePath: fromModule.path,
|
|
120
|
-
redirectModulePath: (modulePath) =>
|
|
121
|
-
this._redirectRequire(fromModule, modulePath),
|
|
122
|
-
allowHaste,
|
|
123
|
-
platform,
|
|
124
105
|
resolveHasteModule: (name) =>
|
|
125
106
|
this._options.getHasteModulePath(name, platform),
|
|
126
107
|
resolveHastePackage: (name) =>
|
|
127
108
|
this._options.getHastePackagePath(name, platform),
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.
|
|
131
|
-
},
|
|
109
|
+
getPackage: this._getPackage,
|
|
110
|
+
getPackageForModule: (modulePath) =>
|
|
111
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
112
|
+
}),
|
|
132
113
|
moduleName,
|
|
133
114
|
platform
|
|
134
115
|
);
|
|
@@ -176,9 +157,29 @@ class ModuleResolver {
|
|
|
176
157
|
throw error;
|
|
177
158
|
}
|
|
178
159
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
160
|
+
_getPackage = (packageJsonPath) => {
|
|
161
|
+
try {
|
|
162
|
+
return this._options.moduleCache.getPackage(packageJsonPath).read();
|
|
163
|
+
} catch (e) {
|
|
164
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
165
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
};
|
|
169
|
+
_getPackageForModule = (fromModule, modulePath) => {
|
|
170
|
+
let pkg;
|
|
171
|
+
try {
|
|
172
|
+
pkg = this._options.moduleCache.getPackageOf(modulePath);
|
|
173
|
+
} catch (e) {
|
|
174
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
175
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
176
|
+
}
|
|
177
|
+
return pkg != null
|
|
178
|
+
? {
|
|
179
|
+
rootPath: path.dirname(pkg.path),
|
|
180
|
+
packageJson: pkg.read(),
|
|
181
|
+
}
|
|
182
|
+
: null;
|
|
182
183
|
};
|
|
183
184
|
|
|
184
185
|
/**
|
|
@@ -204,6 +205,12 @@ class ModuleResolver {
|
|
|
204
205
|
throw new Error("invalid type");
|
|
205
206
|
}
|
|
206
207
|
}
|
|
208
|
+
_logWarning = (message) => {
|
|
209
|
+
this._options.reporter.update({
|
|
210
|
+
type: "resolver_warning",
|
|
211
|
+
message,
|
|
212
|
+
});
|
|
213
|
+
};
|
|
207
214
|
_removeRoot(candidates) {
|
|
208
215
|
if (candidates.filePathPrefix) {
|
|
209
216
|
candidates.filePathPrefix = path.relative(
|
|
@@ -15,29 +15,29 @@ import type {
|
|
|
15
15
|
CustomResolver,
|
|
16
16
|
DoesFileExist,
|
|
17
17
|
FileCandidates,
|
|
18
|
+
GetRealPath,
|
|
18
19
|
IsAssetFile,
|
|
19
20
|
Resolution,
|
|
20
21
|
ResolveAsset,
|
|
21
22
|
} from 'metro-resolver';
|
|
23
|
+
import type {ResolverInputOptions} from '../../shared/types.flow';
|
|
24
|
+
import type {PackageInfo, PackageJson} from 'metro-resolver/src/types';
|
|
22
25
|
|
|
23
26
|
const {codeFrameColumns} = require('@babel/code-frame');
|
|
24
27
|
const fs = require('fs');
|
|
25
28
|
const invariant = require('invariant');
|
|
26
29
|
const Resolver = require('metro-resolver');
|
|
30
|
+
const createDefaultContext = require('metro-resolver/src/createDefaultContext');
|
|
27
31
|
const path = require('path');
|
|
28
32
|
const util = require('util');
|
|
29
|
-
import type {ResolverInputOptions} from '../../shared/types.flow';
|
|
30
33
|
import type {BundlerResolution} from '../../DeltaBundler/types.flow';
|
|
34
|
+
import type {Reporter} from '../../lib/reporting';
|
|
31
35
|
|
|
32
36
|
export type DirExistsFn = (filePath: string) => boolean;
|
|
33
37
|
|
|
34
38
|
export type Packageish = interface {
|
|
35
39
|
path: string,
|
|
36
|
-
|
|
37
|
-
toModuleName: string,
|
|
38
|
-
mainFields: $ReadOnlyArray<string>,
|
|
39
|
-
): string | false,
|
|
40
|
-
getMain(mainFields: $ReadOnlyArray<string>): string,
|
|
40
|
+
read(): PackageJson,
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export type Moduleish = interface {
|
|
@@ -68,6 +68,7 @@ type Options<TPackage> = $ReadOnly<{
|
|
|
68
68
|
nodeModulesPaths: $ReadOnlyArray<string>,
|
|
69
69
|
preferNativePlatform: boolean,
|
|
70
70
|
projectRoot: string,
|
|
71
|
+
reporter: Reporter,
|
|
71
72
|
resolveAsset: ResolveAsset,
|
|
72
73
|
resolveRequest: ?CustomResolver,
|
|
73
74
|
sourceExts: $ReadOnlyArray<string>,
|
|
@@ -76,6 +77,7 @@ type Options<TPackage> = $ReadOnly<{
|
|
|
76
77
|
[platform: string]: $ReadOnlyArray<string>,
|
|
77
78
|
}>,
|
|
78
79
|
unstable_enablePackageExports: boolean,
|
|
80
|
+
unstable_getRealPath: ?GetRealPath,
|
|
79
81
|
}>;
|
|
80
82
|
|
|
81
83
|
class ModuleResolver<TPackage: Packageish> {
|
|
@@ -117,59 +119,6 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
117
119
|
return emptyModule;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
|
-
_redirectRequire(fromModule: Moduleish, modulePath: string): string | false {
|
|
121
|
-
const moduleCache = this._options.moduleCache;
|
|
122
|
-
try {
|
|
123
|
-
if (modulePath.startsWith('.')) {
|
|
124
|
-
const fromPackage = fromModule.getPackage();
|
|
125
|
-
|
|
126
|
-
if (fromPackage) {
|
|
127
|
-
// We need to convert the module path from module-relative to
|
|
128
|
-
// package-relative, so that we can easily match it against the
|
|
129
|
-
// "browser" map (where all paths are relative to the package root)
|
|
130
|
-
const fromPackagePath =
|
|
131
|
-
'./' +
|
|
132
|
-
path.relative(
|
|
133
|
-
path.dirname(fromPackage.path),
|
|
134
|
-
path.resolve(path.dirname(fromModule.path), modulePath),
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
let redirectedPath = fromPackage.redirectRequire(
|
|
138
|
-
fromPackagePath,
|
|
139
|
-
this._options.mainFields,
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
// Since the redirected path is still relative to the package root,
|
|
143
|
-
// we have to transform it back to be module-relative (as it
|
|
144
|
-
// originally was)
|
|
145
|
-
if (redirectedPath !== false) {
|
|
146
|
-
redirectedPath =
|
|
147
|
-
'./' +
|
|
148
|
-
path.relative(
|
|
149
|
-
path.dirname(fromModule.path),
|
|
150
|
-
path.resolve(path.dirname(fromPackage.path), redirectedPath),
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return redirectedPath;
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
const pck = path.isAbsolute(modulePath)
|
|
158
|
-
? moduleCache.getPackageOf(modulePath)
|
|
159
|
-
: fromModule.getPackage();
|
|
160
|
-
|
|
161
|
-
if (pck) {
|
|
162
|
-
return pck.redirectRequire(modulePath, this._options.mainFields);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
} catch (err) {
|
|
166
|
-
// Do nothing. The standard module cache does not trigger any error, but
|
|
167
|
-
// the ModuleGraph one does, if the module does not exist.
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return modulePath;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
122
|
resolveDependency(
|
|
174
123
|
fromModule: Moduleish,
|
|
175
124
|
moduleName: string,
|
|
@@ -177,24 +126,52 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
177
126
|
platform: string | null,
|
|
178
127
|
resolverOptions: ResolverInputOptions,
|
|
179
128
|
): BundlerResolution {
|
|
129
|
+
const {
|
|
130
|
+
disableHierarchicalLookup,
|
|
131
|
+
doesFileExist,
|
|
132
|
+
extraNodeModules,
|
|
133
|
+
isAssetFile,
|
|
134
|
+
mainFields,
|
|
135
|
+
nodeModulesPaths,
|
|
136
|
+
preferNativePlatform,
|
|
137
|
+
resolveAsset,
|
|
138
|
+
resolveRequest,
|
|
139
|
+
sourceExts,
|
|
140
|
+
unstable_conditionNames,
|
|
141
|
+
unstable_conditionsByPlatform,
|
|
142
|
+
unstable_enablePackageExports,
|
|
143
|
+
unstable_getRealPath,
|
|
144
|
+
} = this._options;
|
|
145
|
+
|
|
180
146
|
try {
|
|
181
147
|
const result = Resolver.resolve(
|
|
182
|
-
{
|
|
183
|
-
|
|
148
|
+
createDefaultContext({
|
|
149
|
+
allowHaste,
|
|
150
|
+
disableHierarchicalLookup,
|
|
151
|
+
doesFileExist,
|
|
152
|
+
extraNodeModules,
|
|
153
|
+
isAssetFile,
|
|
154
|
+
mainFields,
|
|
155
|
+
nodeModulesPaths,
|
|
156
|
+
preferNativePlatform,
|
|
157
|
+
resolveAsset,
|
|
158
|
+
resolveRequest,
|
|
159
|
+
sourceExts,
|
|
160
|
+
unstable_conditionNames,
|
|
161
|
+
unstable_conditionsByPlatform,
|
|
162
|
+
unstable_enablePackageExports,
|
|
163
|
+
unstable_getRealPath,
|
|
164
|
+
unstable_logWarning: this._logWarning,
|
|
184
165
|
customResolverOptions: resolverOptions.customResolverOptions ?? {},
|
|
185
166
|
originModulePath: fromModule.path,
|
|
186
|
-
redirectModulePath: (modulePath: string) =>
|
|
187
|
-
this._redirectRequire(fromModule, modulePath),
|
|
188
|
-
allowHaste,
|
|
189
|
-
platform,
|
|
190
167
|
resolveHasteModule: (name: string) =>
|
|
191
168
|
this._options.getHasteModulePath(name, platform),
|
|
192
169
|
resolveHastePackage: (name: string) =>
|
|
193
170
|
this._options.getHastePackagePath(name, platform),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.
|
|
197
|
-
},
|
|
171
|
+
getPackage: this._getPackage,
|
|
172
|
+
getPackageForModule: (modulePath: string) =>
|
|
173
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
174
|
+
}),
|
|
198
175
|
moduleName,
|
|
199
176
|
platform,
|
|
200
177
|
);
|
|
@@ -245,9 +222,36 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
245
222
|
}
|
|
246
223
|
}
|
|
247
224
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
225
|
+
_getPackage = (packageJsonPath: string): ?PackageJson => {
|
|
226
|
+
try {
|
|
227
|
+
return this._options.moduleCache.getPackage(packageJsonPath).read();
|
|
228
|
+
} catch (e) {
|
|
229
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
230
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
_getPackageForModule = (
|
|
237
|
+
fromModule: Moduleish,
|
|
238
|
+
modulePath: string,
|
|
239
|
+
): ?PackageInfo => {
|
|
240
|
+
let pkg;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
pkg = this._options.moduleCache.getPackageOf(modulePath);
|
|
244
|
+
} catch (e) {
|
|
245
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
246
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return pkg != null
|
|
250
|
+
? {
|
|
251
|
+
rootPath: path.dirname(pkg.path),
|
|
252
|
+
packageJson: pkg.read(),
|
|
253
|
+
}
|
|
254
|
+
: null;
|
|
251
255
|
};
|
|
252
256
|
|
|
253
257
|
/**
|
|
@@ -271,6 +275,13 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
271
275
|
}
|
|
272
276
|
}
|
|
273
277
|
|
|
278
|
+
_logWarning = (message: string): void => {
|
|
279
|
+
this._options.reporter.update({
|
|
280
|
+
type: 'resolver_warning',
|
|
281
|
+
message,
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
|
|
274
285
|
_removeRoot(candidates: FileCandidates): FileCandidates {
|
|
275
286
|
if (candidates.filePathPrefix) {
|
|
276
287
|
candidates.filePathPrefix = path.relative(
|
|
@@ -108,7 +108,7 @@ function createHasteMap(config, options) {
|
|
|
108
108
|
: options.cacheFilePrefix,
|
|
109
109
|
});
|
|
110
110
|
},
|
|
111
|
-
perfLoggerFactory: config.
|
|
111
|
+
perfLoggerFactory: config.unstable_perfLoggerFactory,
|
|
112
112
|
computeDependencies,
|
|
113
113
|
computeSha1: true,
|
|
114
114
|
dependencyExtractor: config.resolver.dependencyExtractor,
|
|
@@ -66,7 +66,7 @@ function createHasteMap(
|
|
|
66
66
|
config.fileMapCacheDirectory ?? config.hasteMapCacheDirectory,
|
|
67
67
|
cacheFilePrefix: options?.cacheFilePrefix,
|
|
68
68
|
})),
|
|
69
|
-
perfLoggerFactory: config.
|
|
69
|
+
perfLoggerFactory: config.unstable_perfLoggerFactory,
|
|
70
70
|
computeDependencies,
|
|
71
71
|
computeSha1: true,
|
|
72
72
|
dependencyExtractor: config.resolver.dependencyExtractor,
|
|
@@ -150,14 +150,24 @@ class DependencyGraph extends EventEmitter {
|
|
|
150
150
|
nodeModulesPaths: this._config.resolver.nodeModulesPaths,
|
|
151
151
|
preferNativePlatform: true,
|
|
152
152
|
projectRoot: this._config.projectRoot,
|
|
153
|
+
reporter: this._config.reporter,
|
|
153
154
|
resolveAsset: (dirPath, assetName, extension) => {
|
|
154
155
|
const basePath = dirPath + path.sep + assetName;
|
|
155
|
-
|
|
156
|
+
let assets = [
|
|
156
157
|
basePath + extension,
|
|
157
158
|
...this._config.resolver.assetResolutions.map(
|
|
158
159
|
(resolution) => basePath + "@" + resolution + "x" + extension
|
|
159
160
|
),
|
|
160
|
-
]
|
|
161
|
+
];
|
|
162
|
+
if (this._config.resolver.unstable_enableSymlinks) {
|
|
163
|
+
assets = assets
|
|
164
|
+
.map((candidate) => this._fileSystem.getRealPath(candidate))
|
|
165
|
+
.filter(Boolean);
|
|
166
|
+
} else {
|
|
167
|
+
assets = assets.filter((candidate) =>
|
|
168
|
+
this._fileSystem.exists(candidate)
|
|
169
|
+
);
|
|
170
|
+
}
|
|
161
171
|
return assets.length ? assets : null;
|
|
162
172
|
},
|
|
163
173
|
resolveRequest: this._config.resolver.resolveRequest,
|
|
@@ -167,6 +177,9 @@ class DependencyGraph extends EventEmitter {
|
|
|
167
177
|
this._config.resolver.unstable_conditionsByPlatform,
|
|
168
178
|
unstable_enablePackageExports:
|
|
169
179
|
this._config.resolver.unstable_enablePackageExports,
|
|
180
|
+
unstable_getRealPath: this._config.resolver.unstable_enableSymlinks
|
|
181
|
+
? (path) => this._fileSystem.getRealPath(path)
|
|
182
|
+
: null,
|
|
170
183
|
});
|
|
171
184
|
}
|
|
172
185
|
_createModuleCache() {
|
|
@@ -186,14 +199,18 @@ class DependencyGraph extends EventEmitter {
|
|
|
186
199
|
const containerName =
|
|
187
200
|
splitIndex !== -1 ? filename.slice(0, splitIndex + 4) : filename;
|
|
188
201
|
|
|
189
|
-
//
|
|
202
|
+
// Prior to unstable_enableSymlinks:
|
|
203
|
+
// Calling realpath allows us to get a hash for a given path even when
|
|
190
204
|
// it's a symlink to a file, which prevents Metro from crashing in such a
|
|
191
205
|
// case. However, it doesn't allow Metro to track changes to the target file
|
|
192
206
|
// of the symlink. We should fix this by implementing a symlink map into
|
|
193
207
|
// Metro (or maybe by implementing those "extra transformation sources" we've
|
|
194
208
|
// been talking about for stuff like CSS or WASM).
|
|
195
|
-
|
|
196
|
-
|
|
209
|
+
//
|
|
210
|
+
// This is unnecessary with a symlink-aware fileSystem implementation.
|
|
211
|
+
const resolvedPath = this._config.resolver.unstable_enableSymlinks
|
|
212
|
+
? containerName
|
|
213
|
+
: fs.realpathSync(containerName);
|
|
197
214
|
const sha1 = this._fileSystem.getSha1(resolvedPath);
|
|
198
215
|
if (!sha1) {
|
|
199
216
|
throw new ReferenceError(`SHA-1 for file ${filename} (${resolvedPath}) is not computed.
|
|
@@ -197,14 +197,26 @@ class DependencyGraph extends EventEmitter {
|
|
|
197
197
|
nodeModulesPaths: this._config.resolver.nodeModulesPaths,
|
|
198
198
|
preferNativePlatform: true,
|
|
199
199
|
projectRoot: this._config.projectRoot,
|
|
200
|
+
reporter: this._config.reporter,
|
|
200
201
|
resolveAsset: (dirPath: string, assetName: string, extension: string) => {
|
|
201
202
|
const basePath = dirPath + path.sep + assetName;
|
|
202
|
-
|
|
203
|
+
let assets = [
|
|
203
204
|
basePath + extension,
|
|
204
205
|
...this._config.resolver.assetResolutions.map(
|
|
205
206
|
resolution => basePath + '@' + resolution + 'x' + extension,
|
|
206
207
|
),
|
|
207
|
-
]
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
if (this._config.resolver.unstable_enableSymlinks) {
|
|
211
|
+
assets = assets
|
|
212
|
+
.map(candidate => this._fileSystem.getRealPath(candidate))
|
|
213
|
+
.filter(Boolean);
|
|
214
|
+
} else {
|
|
215
|
+
assets = assets.filter(candidate =>
|
|
216
|
+
this._fileSystem.exists(candidate),
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
208
220
|
return assets.length ? assets : null;
|
|
209
221
|
},
|
|
210
222
|
resolveRequest: this._config.resolver.resolveRequest,
|
|
@@ -214,6 +226,9 @@ class DependencyGraph extends EventEmitter {
|
|
|
214
226
|
this._config.resolver.unstable_conditionsByPlatform,
|
|
215
227
|
unstable_enablePackageExports:
|
|
216
228
|
this._config.resolver.unstable_enablePackageExports,
|
|
229
|
+
unstable_getRealPath: this._config.resolver.unstable_enableSymlinks
|
|
230
|
+
? path => this._fileSystem.getRealPath(path)
|
|
231
|
+
: null,
|
|
217
232
|
});
|
|
218
233
|
}
|
|
219
234
|
|
|
@@ -236,14 +251,19 @@ class DependencyGraph extends EventEmitter {
|
|
|
236
251
|
const containerName =
|
|
237
252
|
splitIndex !== -1 ? filename.slice(0, splitIndex + 4) : filename;
|
|
238
253
|
|
|
239
|
-
//
|
|
254
|
+
// Prior to unstable_enableSymlinks:
|
|
255
|
+
// Calling realpath allows us to get a hash for a given path even when
|
|
240
256
|
// it's a symlink to a file, which prevents Metro from crashing in such a
|
|
241
257
|
// case. However, it doesn't allow Metro to track changes to the target file
|
|
242
258
|
// of the symlink. We should fix this by implementing a symlink map into
|
|
243
259
|
// Metro (or maybe by implementing those "extra transformation sources" we've
|
|
244
260
|
// been talking about for stuff like CSS or WASM).
|
|
261
|
+
//
|
|
262
|
+
// This is unnecessary with a symlink-aware fileSystem implementation.
|
|
263
|
+
const resolvedPath = this._config.resolver.unstable_enableSymlinks
|
|
264
|
+
? containerName
|
|
265
|
+
: fs.realpathSync(containerName);
|
|
245
266
|
|
|
246
|
-
const resolvedPath = fs.realpathSync(containerName);
|
|
247
267
|
const sha1 = this._fileSystem.getSha1(resolvedPath);
|
|
248
268
|
|
|
249
269
|
if (!sha1) {
|
|
@@ -19,85 +19,9 @@ class Package {
|
|
|
19
19
|
this._root = path.dirname(this.path);
|
|
20
20
|
this._content = null;
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* The `browser` field and replacement behavior is specified in
|
|
25
|
-
* https://github.com/defunctzombie/package-browser-field-spec.
|
|
26
|
-
*/
|
|
27
|
-
getMain(mainFields) {
|
|
28
|
-
const json = this.read();
|
|
29
|
-
let main;
|
|
30
|
-
for (const name of mainFields) {
|
|
31
|
-
if (typeof json[name] === "string") {
|
|
32
|
-
main = json[name];
|
|
33
|
-
break;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// flowlint-next-line sketchy-null-string:off
|
|
38
|
-
if (!main) {
|
|
39
|
-
main = "index";
|
|
40
|
-
}
|
|
41
|
-
const replacements = getReplacements(json, mainFields);
|
|
42
|
-
if (replacements) {
|
|
43
|
-
const variants = [main];
|
|
44
|
-
if (main.slice(0, 2) === "./") {
|
|
45
|
-
variants.push(main.slice(2));
|
|
46
|
-
} else {
|
|
47
|
-
variants.push("./" + main);
|
|
48
|
-
}
|
|
49
|
-
for (const variant of variants) {
|
|
50
|
-
const winner =
|
|
51
|
-
replacements[variant] ||
|
|
52
|
-
replacements[variant + ".js"] ||
|
|
53
|
-
replacements[variant + ".json"] ||
|
|
54
|
-
replacements[variant.replace(/(\.js|\.json)$/, "")];
|
|
55
|
-
if (winner) {
|
|
56
|
-
main = winner;
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return path.join(this._root, main);
|
|
62
|
-
}
|
|
63
22
|
invalidate() {
|
|
64
23
|
this._content = null;
|
|
65
24
|
}
|
|
66
|
-
redirectRequire(name, mainFields) {
|
|
67
|
-
const json = this.read();
|
|
68
|
-
const replacements = getReplacements(json, mainFields);
|
|
69
|
-
if (!replacements) {
|
|
70
|
-
return name;
|
|
71
|
-
}
|
|
72
|
-
if (!name.startsWith(".") && !path.isAbsolute(name)) {
|
|
73
|
-
const replacement = replacements[name];
|
|
74
|
-
// support exclude with "someDependency": false
|
|
75
|
-
return replacement === false ? false : replacement || name;
|
|
76
|
-
}
|
|
77
|
-
let relPath =
|
|
78
|
-
"./" + path.relative(this._root, path.resolve(this._root, name));
|
|
79
|
-
if (path.sep !== "/") {
|
|
80
|
-
relPath = relPath.replace(new RegExp("\\" + path.sep, "g"), "/");
|
|
81
|
-
}
|
|
82
|
-
let redirect = replacements[relPath];
|
|
83
|
-
|
|
84
|
-
// false is a valid value
|
|
85
|
-
if (redirect == null) {
|
|
86
|
-
redirect = replacements[relPath + ".js"];
|
|
87
|
-
if (redirect == null) {
|
|
88
|
-
redirect = replacements[relPath + ".json"];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// support exclude with "./someFile": false
|
|
93
|
-
if (redirect === false) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
if (redirect) {
|
|
97
|
-
return path.join(this._root, redirect);
|
|
98
|
-
}
|
|
99
|
-
return name;
|
|
100
|
-
}
|
|
101
25
|
read() {
|
|
102
26
|
if (this._content == null) {
|
|
103
27
|
this._content = JSON.parse(fs.readFileSync(this.path, "utf8"));
|
|
@@ -105,20 +29,4 @@ class Package {
|
|
|
105
29
|
return this._content;
|
|
106
30
|
}
|
|
107
31
|
}
|
|
108
|
-
function getReplacements(pkg, mainFields) {
|
|
109
|
-
const replacements = mainFields
|
|
110
|
-
.map((name) => {
|
|
111
|
-
// If the field is a string, that doesn't mean we want to redirect the
|
|
112
|
-
// `main` file itself to anything else. See the spec.
|
|
113
|
-
if (!pkg[name] || typeof pkg[name] === "string") {
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
return pkg[name];
|
|
117
|
-
})
|
|
118
|
-
.filter(Boolean);
|
|
119
|
-
if (!replacements.length) {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
return Object.assign({}, ...replacements.reverse());
|
|
123
|
-
}
|
|
124
32
|
module.exports = Package;
|
|
@@ -11,22 +11,16 @@
|
|
|
11
11
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
|
+
import type {PackageJson} from 'metro-resolver/src/types';
|
|
15
|
+
|
|
14
16
|
const fs = require('fs');
|
|
15
17
|
const path = require('path');
|
|
16
18
|
|
|
17
|
-
type PackageContent = {
|
|
18
|
-
name: string,
|
|
19
|
-
'react-native': mixed,
|
|
20
|
-
browser: mixed,
|
|
21
|
-
main: ?string,
|
|
22
|
-
...
|
|
23
|
-
};
|
|
24
|
-
|
|
25
19
|
class Package {
|
|
26
20
|
path: string;
|
|
27
21
|
|
|
28
22
|
_root: string;
|
|
29
|
-
_content: ?
|
|
23
|
+
_content: ?PackageJson;
|
|
30
24
|
|
|
31
25
|
constructor({file}: {file: string, ...}) {
|
|
32
26
|
this.path = path.resolve(file);
|
|
@@ -34,104 +28,11 @@ class Package {
|
|
|
34
28
|
this._content = null;
|
|
35
29
|
}
|
|
36
30
|
|
|
37
|
-
/**
|
|
38
|
-
* The `browser` field and replacement behavior is specified in
|
|
39
|
-
* https://github.com/defunctzombie/package-browser-field-spec.
|
|
40
|
-
*/
|
|
41
|
-
getMain(mainFields: $ReadOnlyArray<string>): string {
|
|
42
|
-
const json = this.read();
|
|
43
|
-
|
|
44
|
-
let main;
|
|
45
|
-
|
|
46
|
-
for (const name of mainFields) {
|
|
47
|
-
if (typeof json[name] === 'string') {
|
|
48
|
-
main = json[name];
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// flowlint-next-line sketchy-null-string:off
|
|
54
|
-
if (!main) {
|
|
55
|
-
main = 'index';
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const replacements = getReplacements(json, mainFields);
|
|
59
|
-
if (replacements) {
|
|
60
|
-
const variants = [main];
|
|
61
|
-
if (main.slice(0, 2) === './') {
|
|
62
|
-
variants.push(main.slice(2));
|
|
63
|
-
} else {
|
|
64
|
-
variants.push('./' + main);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
for (const variant of variants) {
|
|
68
|
-
const winner =
|
|
69
|
-
replacements[variant] ||
|
|
70
|
-
replacements[variant + '.js'] ||
|
|
71
|
-
replacements[variant + '.json'] ||
|
|
72
|
-
replacements[variant.replace(/(\.js|\.json)$/, '')];
|
|
73
|
-
|
|
74
|
-
if (winner) {
|
|
75
|
-
main = winner;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return path.join(this._root, main);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
31
|
invalidate() {
|
|
85
32
|
this._content = null;
|
|
86
33
|
}
|
|
87
34
|
|
|
88
|
-
|
|
89
|
-
name: string,
|
|
90
|
-
mainFields: $ReadOnlyArray<string>,
|
|
91
|
-
): string | false {
|
|
92
|
-
const json = this.read();
|
|
93
|
-
const replacements = getReplacements(json, mainFields);
|
|
94
|
-
|
|
95
|
-
if (!replacements) {
|
|
96
|
-
return name;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!name.startsWith('.') && !path.isAbsolute(name)) {
|
|
100
|
-
const replacement = replacements[name];
|
|
101
|
-
// support exclude with "someDependency": false
|
|
102
|
-
return replacement === false ? false : replacement || name;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let relPath =
|
|
106
|
-
'./' + path.relative(this._root, path.resolve(this._root, name));
|
|
107
|
-
|
|
108
|
-
if (path.sep !== '/') {
|
|
109
|
-
relPath = relPath.replace(new RegExp('\\' + path.sep, 'g'), '/');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
let redirect = replacements[relPath];
|
|
113
|
-
|
|
114
|
-
// false is a valid value
|
|
115
|
-
if (redirect == null) {
|
|
116
|
-
redirect = replacements[relPath + '.js'];
|
|
117
|
-
if (redirect == null) {
|
|
118
|
-
redirect = replacements[relPath + '.json'];
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// support exclude with "./someFile": false
|
|
123
|
-
if (redirect === false) {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (redirect) {
|
|
128
|
-
return path.join(this._root, redirect);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return name;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
read(): PackageContent {
|
|
35
|
+
read(): PackageJson {
|
|
135
36
|
if (this._content == null) {
|
|
136
37
|
this._content = JSON.parse(fs.readFileSync(this.path, 'utf8'));
|
|
137
38
|
}
|
|
@@ -139,27 +40,4 @@ class Package {
|
|
|
139
40
|
}
|
|
140
41
|
}
|
|
141
42
|
|
|
142
|
-
function getReplacements(
|
|
143
|
-
pkg: PackageContent,
|
|
144
|
-
mainFields: $ReadOnlyArray<string>,
|
|
145
|
-
): ?{[string]: string | false, ...} {
|
|
146
|
-
const replacements = mainFields
|
|
147
|
-
.map((name: string) => {
|
|
148
|
-
// If the field is a string, that doesn't mean we want to redirect the
|
|
149
|
-
// `main` file itself to anything else. See the spec.
|
|
150
|
-
if (!pkg[name] || typeof pkg[name] === 'string') {
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return pkg[name];
|
|
155
|
-
})
|
|
156
|
-
.filter(Boolean);
|
|
157
|
-
|
|
158
|
-
if (!replacements.length) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return Object.assign({}, ...replacements.reverse());
|
|
163
|
-
}
|
|
164
|
-
|
|
165
43
|
module.exports = Package;
|