metro 0.74.1 → 0.75.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +26 -23
- package/src/DeltaBundler/DeltaCalculator.js +24 -0
- package/src/DeltaBundler/DeltaCalculator.js.flow +22 -0
- package/src/DeltaBundler/WorkerFarm.js +1 -0
- package/src/DeltaBundler/WorkerFarm.js.flow +1 -0
- package/src/Server.js +1 -1
- package/src/Server.js.flow +1 -1
- package/src/lib/formatBundlingError.js +3 -0
- package/src/lib/formatBundlingError.js.flow +3 -0
- package/src/node-haste/DependencyGraph/ModuleResolution.js +58 -60
- package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +69 -72
- package/src/node-haste/DependencyGraph/createHasteMap.js +1 -1
- package/src/node-haste/DependencyGraph/createHasteMap.js.flow +1 -1
- 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.0",
|
|
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.0",
|
|
39
|
+
"metro-cache": "0.75.0",
|
|
40
|
+
"metro-cache-key": "0.75.0",
|
|
41
|
+
"metro-config": "0.75.0",
|
|
42
|
+
"metro-core": "0.75.0",
|
|
43
|
+
"metro-file-map": "0.75.0",
|
|
44
|
+
"metro-hermes-compiler": "0.75.0",
|
|
45
|
+
"metro-inspector-proxy": "0.75.0",
|
|
46
|
+
"metro-minify-terser": "0.75.0",
|
|
47
|
+
"metro-minify-uglify": "0.75.0",
|
|
48
|
+
"metro-react-native-babel-preset": "0.75.0",
|
|
49
|
+
"metro-resolver": "0.75.0",
|
|
50
|
+
"metro-runtime": "0.75.0",
|
|
51
|
+
"metro-source-map": "0.75.0",
|
|
52
|
+
"metro-symbolicate": "0.75.0",
|
|
53
|
+
"metro-transform-plugins": "0.75.0",
|
|
54
|
+
"metro-transform-worker": "0.75.0",
|
|
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.0",
|
|
74
|
+
"metro-memory-fs": "0.75.0",
|
|
75
|
+
"metro-react-native-babel-preset": "0.75.0",
|
|
76
|
+
"metro-react-native-babel-transformer": "0.75.0",
|
|
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
|
}
|
|
@@ -25,6 +25,7 @@ class DeltaCalculator extends EventEmitter {
|
|
|
25
25
|
_deletedFiles = new Set();
|
|
26
26
|
_modifiedFiles = new Set();
|
|
27
27
|
_addedFiles = new Set();
|
|
28
|
+
_hasSymlinkChanges = false;
|
|
28
29
|
constructor(entryPoints, changeEventSource, options) {
|
|
29
30
|
super();
|
|
30
31
|
this._options = options;
|
|
@@ -61,6 +62,7 @@ class DeltaCalculator extends EventEmitter {
|
|
|
61
62
|
* which contain the modified/added modules and the removed modules.
|
|
62
63
|
*/
|
|
63
64
|
async getDelta({ reset, shallow }) {
|
|
65
|
+
debug("Calculating delta (reset: %s, shallow: %s)", reset, shallow);
|
|
64
66
|
// If there is already a build in progress, wait until it finish to start
|
|
65
67
|
// processing a new one (delta server doesn't support concurrent builds).
|
|
66
68
|
if (this._currentBuildPromise) {
|
|
@@ -76,6 +78,21 @@ class DeltaCalculator extends EventEmitter {
|
|
|
76
78
|
this._deletedFiles = new Set();
|
|
77
79
|
const addedFiles = this._addedFiles;
|
|
78
80
|
this._addedFiles = new Set();
|
|
81
|
+
const hasSymlinkChanges = this._hasSymlinkChanges;
|
|
82
|
+
this._hasSymlinkChanges = false;
|
|
83
|
+
|
|
84
|
+
// Revisit all files if changes include symlinks - resolutions may be
|
|
85
|
+
// invalidated but we don't yet know which. This should be optimized in the
|
|
86
|
+
// future.
|
|
87
|
+
if (hasSymlinkChanges) {
|
|
88
|
+
const markModified = (file) => {
|
|
89
|
+
if (!addedFiles.has(file) && !deletedFiles.has(file)) {
|
|
90
|
+
modifiedFiles.add(file);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
this._graph.dependencies.forEach((_, key) => markModified(key));
|
|
94
|
+
this._graph.entryPoints.forEach(markModified);
|
|
95
|
+
}
|
|
79
96
|
|
|
80
97
|
// Concurrent requests should reuse the same bundling process. To do so,
|
|
81
98
|
// this method stores the promise as an instance variable, and then it's
|
|
@@ -148,6 +165,13 @@ class DeltaCalculator extends EventEmitter {
|
|
|
148
165
|
*/
|
|
149
166
|
_handleFileChange = ({ type, filePath, metadata }, logger) => {
|
|
150
167
|
debug("Handling %s: %s (type: %s)", type, filePath, metadata.type);
|
|
168
|
+
if (metadata.type === "l") {
|
|
169
|
+
this._hasSymlinkChanges = true;
|
|
170
|
+
this.emit("change", {
|
|
171
|
+
logger,
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
151
175
|
let state;
|
|
152
176
|
if (this._deletedFiles.has(filePath)) {
|
|
153
177
|
state = "deleted";
|
|
@@ -33,6 +33,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
33
33
|
_deletedFiles: Set<string> = new Set();
|
|
34
34
|
_modifiedFiles: Set<string> = new Set();
|
|
35
35
|
_addedFiles: Set<string> = new Set();
|
|
36
|
+
_hasSymlinkChanges = false;
|
|
36
37
|
|
|
37
38
|
_graph: Graph<T>;
|
|
38
39
|
|
|
@@ -87,6 +88,7 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
87
88
|
shallow: boolean,
|
|
88
89
|
...
|
|
89
90
|
}): Promise<DeltaResult<T>> {
|
|
91
|
+
debug('Calculating delta (reset: %s, shallow: %s)', reset, shallow);
|
|
90
92
|
// If there is already a build in progress, wait until it finish to start
|
|
91
93
|
// processing a new one (delta server doesn't support concurrent builds).
|
|
92
94
|
if (this._currentBuildPromise) {
|
|
@@ -102,6 +104,21 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
102
104
|
this._deletedFiles = new Set();
|
|
103
105
|
const addedFiles = this._addedFiles;
|
|
104
106
|
this._addedFiles = new Set();
|
|
107
|
+
const hasSymlinkChanges = this._hasSymlinkChanges;
|
|
108
|
+
this._hasSymlinkChanges = false;
|
|
109
|
+
|
|
110
|
+
// Revisit all files if changes include symlinks - resolutions may be
|
|
111
|
+
// invalidated but we don't yet know which. This should be optimized in the
|
|
112
|
+
// future.
|
|
113
|
+
if (hasSymlinkChanges) {
|
|
114
|
+
const markModified = (file: string) => {
|
|
115
|
+
if (!addedFiles.has(file) && !deletedFiles.has(file)) {
|
|
116
|
+
modifiedFiles.add(file);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
this._graph.dependencies.forEach((_, key) => markModified(key));
|
|
120
|
+
this._graph.entryPoints.forEach(markModified);
|
|
121
|
+
}
|
|
105
122
|
|
|
106
123
|
// Concurrent requests should reuse the same bundling process. To do so,
|
|
107
124
|
// this method stores the promise as an instance variable, and then it's
|
|
@@ -190,6 +207,11 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
190
207
|
logger: ?RootPerfLogger,
|
|
191
208
|
): mixed => {
|
|
192
209
|
debug('Handling %s: %s (type: %s)', type, filePath, metadata.type);
|
|
210
|
+
if (metadata.type === 'l') {
|
|
211
|
+
this._hasSymlinkChanges = true;
|
|
212
|
+
this.emit('change', {logger});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
193
215
|
let state: void | 'deleted' | 'modified' | 'added';
|
|
194
216
|
if (this._deletedFiles.has(filePath)) {
|
|
195
217
|
state = 'deleted';
|
|
@@ -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,
|
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(
|
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
|
});
|
|
@@ -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
|
};
|
|
@@ -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,53 @@ 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
|
+
} = this._options;
|
|
109
78
|
try {
|
|
110
79
|
var _resolverOptions$cust;
|
|
111
80
|
const result = Resolver.resolve(
|
|
112
|
-
{
|
|
113
|
-
|
|
81
|
+
createDefaultContext({
|
|
82
|
+
allowHaste,
|
|
83
|
+
disableHierarchicalLookup,
|
|
84
|
+
doesFileExist,
|
|
85
|
+
extraNodeModules,
|
|
86
|
+
isAssetFile,
|
|
87
|
+
mainFields,
|
|
88
|
+
nodeModulesPaths,
|
|
89
|
+
preferNativePlatform,
|
|
90
|
+
resolveAsset,
|
|
91
|
+
resolveRequest,
|
|
92
|
+
sourceExts,
|
|
93
|
+
unstable_conditionNames,
|
|
94
|
+
unstable_conditionsByPlatform,
|
|
95
|
+
unstable_enablePackageExports,
|
|
114
96
|
customResolverOptions:
|
|
115
97
|
(_resolverOptions$cust = resolverOptions.customResolverOptions) !==
|
|
116
98
|
null && _resolverOptions$cust !== void 0
|
|
117
99
|
? _resolverOptions$cust
|
|
118
100
|
: {},
|
|
119
101
|
originModulePath: fromModule.path,
|
|
120
|
-
redirectModulePath: (modulePath) =>
|
|
121
|
-
this._redirectRequire(fromModule, modulePath),
|
|
122
|
-
allowHaste,
|
|
123
|
-
platform,
|
|
124
102
|
resolveHasteModule: (name) =>
|
|
125
103
|
this._options.getHasteModulePath(name, platform),
|
|
126
104
|
resolveHastePackage: (name) =>
|
|
127
105
|
this._options.getHastePackagePath(name, platform),
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.
|
|
131
|
-
},
|
|
106
|
+
getPackage: this._getPackage,
|
|
107
|
+
getPackageForModule: (modulePath) =>
|
|
108
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
109
|
+
}),
|
|
132
110
|
moduleName,
|
|
133
111
|
platform
|
|
134
112
|
);
|
|
@@ -176,9 +154,29 @@ class ModuleResolver {
|
|
|
176
154
|
throw error;
|
|
177
155
|
}
|
|
178
156
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
157
|
+
_getPackage = (packageJsonPath) => {
|
|
158
|
+
try {
|
|
159
|
+
return this._options.moduleCache.getPackage(packageJsonPath).read();
|
|
160
|
+
} catch (e) {
|
|
161
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
162
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
};
|
|
166
|
+
_getPackageForModule = (fromModule, modulePath) => {
|
|
167
|
+
let pkg;
|
|
168
|
+
try {
|
|
169
|
+
pkg = this._options.moduleCache.getPackageOf(modulePath);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
172
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
173
|
+
}
|
|
174
|
+
return pkg != null
|
|
175
|
+
? {
|
|
176
|
+
rootPath: path.dirname(pkg.path),
|
|
177
|
+
packageJson: pkg.read(),
|
|
178
|
+
}
|
|
179
|
+
: null;
|
|
182
180
|
};
|
|
183
181
|
|
|
184
182
|
/**
|
|
@@ -19,25 +19,23 @@ import type {
|
|
|
19
19
|
Resolution,
|
|
20
20
|
ResolveAsset,
|
|
21
21
|
} from 'metro-resolver';
|
|
22
|
+
import type {ResolverInputOptions} from '../../shared/types.flow';
|
|
23
|
+
import type {PackageInfo, PackageJson} from 'metro-resolver/src/types';
|
|
22
24
|
|
|
23
25
|
const {codeFrameColumns} = require('@babel/code-frame');
|
|
24
26
|
const fs = require('fs');
|
|
25
27
|
const invariant = require('invariant');
|
|
26
28
|
const Resolver = require('metro-resolver');
|
|
29
|
+
const createDefaultContext = require('metro-resolver/src/createDefaultContext');
|
|
27
30
|
const path = require('path');
|
|
28
31
|
const util = require('util');
|
|
29
|
-
import type {ResolverInputOptions} from '../../shared/types.flow';
|
|
30
32
|
import type {BundlerResolution} from '../../DeltaBundler/types.flow';
|
|
31
33
|
|
|
32
34
|
export type DirExistsFn = (filePath: string) => boolean;
|
|
33
35
|
|
|
34
36
|
export type Packageish = interface {
|
|
35
37
|
path: string,
|
|
36
|
-
|
|
37
|
-
toModuleName: string,
|
|
38
|
-
mainFields: $ReadOnlyArray<string>,
|
|
39
|
-
): string | false,
|
|
40
|
-
getMain(mainFields: $ReadOnlyArray<string>): string,
|
|
38
|
+
read(): PackageJson,
|
|
41
39
|
};
|
|
42
40
|
|
|
43
41
|
export type Moduleish = interface {
|
|
@@ -117,59 +115,6 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
117
115
|
return emptyModule;
|
|
118
116
|
}
|
|
119
117
|
|
|
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
118
|
resolveDependency(
|
|
174
119
|
fromModule: Moduleish,
|
|
175
120
|
moduleName: string,
|
|
@@ -177,24 +122,49 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
177
122
|
platform: string | null,
|
|
178
123
|
resolverOptions: ResolverInputOptions,
|
|
179
124
|
): BundlerResolution {
|
|
125
|
+
const {
|
|
126
|
+
disableHierarchicalLookup,
|
|
127
|
+
doesFileExist,
|
|
128
|
+
extraNodeModules,
|
|
129
|
+
isAssetFile,
|
|
130
|
+
mainFields,
|
|
131
|
+
nodeModulesPaths,
|
|
132
|
+
preferNativePlatform,
|
|
133
|
+
resolveAsset,
|
|
134
|
+
resolveRequest,
|
|
135
|
+
sourceExts,
|
|
136
|
+
unstable_conditionNames,
|
|
137
|
+
unstable_conditionsByPlatform,
|
|
138
|
+
unstable_enablePackageExports,
|
|
139
|
+
} = this._options;
|
|
140
|
+
|
|
180
141
|
try {
|
|
181
142
|
const result = Resolver.resolve(
|
|
182
|
-
{
|
|
183
|
-
|
|
143
|
+
createDefaultContext({
|
|
144
|
+
allowHaste,
|
|
145
|
+
disableHierarchicalLookup,
|
|
146
|
+
doesFileExist,
|
|
147
|
+
extraNodeModules,
|
|
148
|
+
isAssetFile,
|
|
149
|
+
mainFields,
|
|
150
|
+
nodeModulesPaths,
|
|
151
|
+
preferNativePlatform,
|
|
152
|
+
resolveAsset,
|
|
153
|
+
resolveRequest,
|
|
154
|
+
sourceExts,
|
|
155
|
+
unstable_conditionNames,
|
|
156
|
+
unstable_conditionsByPlatform,
|
|
157
|
+
unstable_enablePackageExports,
|
|
184
158
|
customResolverOptions: resolverOptions.customResolverOptions ?? {},
|
|
185
159
|
originModulePath: fromModule.path,
|
|
186
|
-
redirectModulePath: (modulePath: string) =>
|
|
187
|
-
this._redirectRequire(fromModule, modulePath),
|
|
188
|
-
allowHaste,
|
|
189
|
-
platform,
|
|
190
160
|
resolveHasteModule: (name: string) =>
|
|
191
161
|
this._options.getHasteModulePath(name, platform),
|
|
192
162
|
resolveHastePackage: (name: string) =>
|
|
193
163
|
this._options.getHastePackagePath(name, platform),
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
this.
|
|
197
|
-
},
|
|
164
|
+
getPackage: this._getPackage,
|
|
165
|
+
getPackageForModule: (modulePath: string) =>
|
|
166
|
+
this._getPackageForModule(fromModule, modulePath),
|
|
167
|
+
}),
|
|
198
168
|
moduleName,
|
|
199
169
|
platform,
|
|
200
170
|
);
|
|
@@ -245,9 +215,36 @@ class ModuleResolver<TPackage: Packageish> {
|
|
|
245
215
|
}
|
|
246
216
|
}
|
|
247
217
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
218
|
+
_getPackage = (packageJsonPath: string): ?PackageJson => {
|
|
219
|
+
try {
|
|
220
|
+
return this._options.moduleCache.getPackage(packageJsonPath).read();
|
|
221
|
+
} catch (e) {
|
|
222
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
223
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return null;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
_getPackageForModule = (
|
|
230
|
+
fromModule: Moduleish,
|
|
231
|
+
modulePath: string,
|
|
232
|
+
): ?PackageInfo => {
|
|
233
|
+
let pkg;
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
pkg = this._options.moduleCache.getPackageOf(modulePath);
|
|
237
|
+
} catch (e) {
|
|
238
|
+
// Do nothing. The standard module cache does not trigger any error, but
|
|
239
|
+
// the ModuleGraph one does, if the module does not exist.
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return pkg != null
|
|
243
|
+
? {
|
|
244
|
+
rootPath: path.dirname(pkg.path),
|
|
245
|
+
packageJson: pkg.read(),
|
|
246
|
+
}
|
|
247
|
+
: null;
|
|
251
248
|
};
|
|
252
249
|
|
|
253
250
|
/**
|
|
@@ -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,
|
|
@@ -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;
|