mirror of https://github.com/status-im/metro.git
[react-packager] Add support for platform in the resolver
Summary: Teach the resolver about platform-based resolution. The platform extension is inferred from the entry point. It works for haste modules, as well as node-based resolution.
This commit is contained in:
parent
ab23c251c3
commit
63a96af6c6
|
@ -1809,6 +1809,77 @@ describe('DependencyGraph', function() {
|
|||
});
|
||||
});
|
||||
|
||||
pit('platform should work with node_modules', function() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
'root': {
|
||||
'index.ios.js': [
|
||||
'/**',
|
||||
' * @providesModule index',
|
||||
' */',
|
||||
'require("foo");',
|
||||
'require("bar");',
|
||||
].join('\n'),
|
||||
'node_modules': {
|
||||
'foo': {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'foo',
|
||||
}),
|
||||
'index.ios.js': '',
|
||||
},
|
||||
'bar': {
|
||||
'package.json': JSON.stringify({
|
||||
name: 'bar',
|
||||
main: 'main'
|
||||
}),
|
||||
'main.ios.js': '',
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var dgraph = new DependencyGraph({
|
||||
roots: [root],
|
||||
fileWatcher: fileWatcher,
|
||||
assetExts: ['png', 'jpg'],
|
||||
});
|
||||
return dgraph.getOrderedDependencies('/root/index.ios.js').then(function(deps) {
|
||||
expect(deps)
|
||||
.toEqual([
|
||||
{
|
||||
id: 'index',
|
||||
path: '/root/index.ios.js',
|
||||
dependencies: ['foo', 'bar'],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
{
|
||||
id: 'foo/index.ios.js',
|
||||
path: '/root/node_modules/foo/index.ios.js',
|
||||
dependencies: [],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
{
|
||||
id: 'bar/main.ios.js',
|
||||
path: '/root/node_modules/bar/main.ios.js',
|
||||
dependencies: [],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
pit('nested node_modules with specific paths', function() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
|
@ -2333,6 +2404,169 @@ describe('DependencyGraph', function() {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
pit('should work with multiple platforms (haste)', function() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
'root': {
|
||||
'index.ios.js': `
|
||||
/**
|
||||
* @providesModule index
|
||||
*/
|
||||
require('a');
|
||||
`,
|
||||
'a.ios.js': `
|
||||
/**
|
||||
* @providesModule a
|
||||
*/
|
||||
`,
|
||||
'a.android.js': `
|
||||
/**
|
||||
* @providesModule a
|
||||
*/
|
||||
`,
|
||||
'a.js': `
|
||||
/**
|
||||
* @providesModule a
|
||||
*/
|
||||
`,
|
||||
}
|
||||
});
|
||||
|
||||
var dgraph = new DependencyGraph({
|
||||
roots: [root],
|
||||
fileWatcher: fileWatcher,
|
||||
assetExts: ['png', 'jpg'],
|
||||
});
|
||||
return dgraph.getOrderedDependencies('/root/index.ios.js').then(function(deps) {
|
||||
expect(deps)
|
||||
.toEqual([
|
||||
{
|
||||
id: 'index',
|
||||
path: '/root/index.ios.js',
|
||||
dependencies: ['a'],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
{
|
||||
id: 'a',
|
||||
path: '/root/a.ios.js',
|
||||
dependencies: [],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
pit('should pick the generic file', function() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
'root': {
|
||||
'index.ios.js': `
|
||||
/**
|
||||
* @providesModule index
|
||||
*/
|
||||
require('a');
|
||||
`,
|
||||
'a.android.js': `
|
||||
/**
|
||||
* @providesModule a
|
||||
*/
|
||||
`,
|
||||
'a.js': `
|
||||
/**
|
||||
* @providesModule a
|
||||
*/
|
||||
`,
|
||||
}
|
||||
});
|
||||
|
||||
var dgraph = new DependencyGraph({
|
||||
roots: [root],
|
||||
fileWatcher: fileWatcher,
|
||||
assetExts: ['png', 'jpg'],
|
||||
});
|
||||
return dgraph.getOrderedDependencies('/root/index.ios.js').then(function(deps) {
|
||||
expect(deps)
|
||||
.toEqual([
|
||||
{
|
||||
id: 'index',
|
||||
path: '/root/index.ios.js',
|
||||
dependencies: ['a'],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
{
|
||||
id: 'a',
|
||||
path: '/root/a.js',
|
||||
dependencies: [],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
pit('should work with multiple platforms (node)', function() {
|
||||
var root = '/root';
|
||||
fs.__setMockFilesystem({
|
||||
'root': {
|
||||
'index.ios.js': `
|
||||
/**
|
||||
* @providesModule index
|
||||
*/
|
||||
require('./a');
|
||||
`,
|
||||
'a.ios.js': '',
|
||||
'a.android.js': '',
|
||||
'a.js': '',
|
||||
}
|
||||
});
|
||||
|
||||
var dgraph = new DependencyGraph({
|
||||
roots: [root],
|
||||
fileWatcher: fileWatcher,
|
||||
assetExts: ['png', 'jpg'],
|
||||
});
|
||||
return dgraph.getOrderedDependencies('/root/index.ios.js').then(function(deps) {
|
||||
expect(deps)
|
||||
.toEqual([
|
||||
{
|
||||
id: 'index',
|
||||
path: '/root/index.ios.js',
|
||||
dependencies: ['./a'],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
{
|
||||
id: '/root/a.ios.js',
|
||||
path: '/root/a.ios.js',
|
||||
dependencies: [],
|
||||
isAsset: false,
|
||||
isAsset_DEPRECATED: false,
|
||||
isJSON: false,
|
||||
isPolyfill: false,
|
||||
resolution: undefined,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('file watch updating', function() {
|
||||
|
|
|
@ -56,6 +56,10 @@ const validateOpts = declareOpts({
|
|||
'parse',
|
||||
],
|
||||
},
|
||||
platforms: {
|
||||
type: 'array',
|
||||
default: ['ios', 'android'],
|
||||
}
|
||||
});
|
||||
|
||||
class DependencyGraph {
|
||||
|
@ -169,6 +173,13 @@ class DependencyGraph {
|
|||
);
|
||||
}
|
||||
|
||||
const platformExt = getPlatformExt(entryPath);
|
||||
if (platformExt && this._opts.platforms.indexOf(platformExt) > -1) {
|
||||
this._platformExt = platformExt;
|
||||
} else {
|
||||
this._platformExt = null;
|
||||
}
|
||||
|
||||
const entry = this._moduleCache.getModule(absolutePath);
|
||||
const deps = [];
|
||||
const visited = Object.create(null);
|
||||
|
@ -237,16 +248,14 @@ class DependencyGraph {
|
|||
}
|
||||
|
||||
return p.then((realModuleName) => {
|
||||
let dep = this._hasteMap[realModuleName];
|
||||
|
||||
let dep = this._getHasteModule(realModuleName);
|
||||
if (dep && dep.type === 'Module') {
|
||||
return dep;
|
||||
}
|
||||
|
||||
let packageName = realModuleName;
|
||||
|
||||
while (packageName && packageName !== '.') {
|
||||
dep = this._hasteMap[packageName];
|
||||
dep = this._getHasteModule(packageName);
|
||||
if (dep && dep.type === 'Package') {
|
||||
break;
|
||||
}
|
||||
|
@ -349,6 +358,9 @@ class DependencyGraph {
|
|||
let file;
|
||||
if (this._fastfs.fileExists(potentialModulePath)) {
|
||||
file = potentialModulePath;
|
||||
} else if (this._platformExt != null &&
|
||||
this._fastfs.fileExists(potentialModulePath + '.' + this._platformExt + '.js')) {
|
||||
file = potentialModulePath + '.' + this._platformExt + '.js';
|
||||
} else if (this._fastfs.fileExists(potentialModulePath + '.js')) {
|
||||
file = potentialModulePath + '.js';
|
||||
} else if (this._fastfs.fileExists(potentialModulePath + '.json')) {
|
||||
|
@ -419,15 +431,32 @@ class DependencyGraph {
|
|||
}
|
||||
|
||||
_updateHasteMap(name, mod) {
|
||||
if (this._hasteMap[name]) {
|
||||
debug('WARNING: conflicting haste modules: ' + name);
|
||||
if (mod.type === 'Package' &&
|
||||
this._hasteMap[name].type === 'Module') {
|
||||
if (this._hasteMap[name] == null) {
|
||||
this._hasteMap[name] = [];
|
||||
}
|
||||
|
||||
if (mod.type === 'Module') {
|
||||
// Modules takes precendence over packages.
|
||||
return;
|
||||
this._hasteMap[name].unshift(mod);
|
||||
} else {
|
||||
this._hasteMap[name].push(mod);
|
||||
}
|
||||
}
|
||||
this._hasteMap[name] = mod;
|
||||
|
||||
_getHasteModule(name) {
|
||||
if (this._hasteMap[name]) {
|
||||
const modules = this._hasteMap[name];
|
||||
if (this._platformExt != null) {
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
if (getPlatformExt(modules[i].path) === this._platformExt) {
|
||||
return modules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modules[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
_isNodeModulesDir(file) {
|
||||
|
@ -511,12 +540,17 @@ class DependencyGraph {
|
|||
return;
|
||||
}
|
||||
|
||||
/*eslint no-labels: 0 */
|
||||
if (type === 'delete' || type === 'change') {
|
||||
_.each(this._hasteMap, (mod, name) => {
|
||||
if (mod.path === absPath) {
|
||||
delete this._hasteMap[name];
|
||||
loop: for (let name in this._hasteMap) {
|
||||
let modules = this._hasteMap[name];
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
if (modules[i].path === absPath) {
|
||||
modules.splice(i, 1);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (type === 'delete') {
|
||||
return;
|
||||
|
@ -566,6 +600,15 @@ function normalizePath(modulePath) {
|
|||
return modulePath.replace(/\/$/, '');
|
||||
}
|
||||
|
||||
// Extract platform extension: index.ios.js -> ios
|
||||
function getPlatformExt(file) {
|
||||
const parts = path.basename(file).split('.');
|
||||
if (parts.length < 3) {
|
||||
return null;
|
||||
}
|
||||
return parts[parts.length - 2];
|
||||
}
|
||||
|
||||
util.inherits(NotFoundError, Error);
|
||||
|
||||
module.exports = DependencyGraph;
|
||||
|
|
Loading…
Reference in New Issue