support react-native field with fallback to browser field
Summary: React Native is a lot more powerful an environment than the browser, so we need an alternate mapping, as specified [here](https://github.com/defunctzombie/node-browser-resolve#browser-field) An example: ```js { "browser": { "./lib/server": false }, "react-native": { "dgram": "react-native-udp", "fs": "react-native-level-fs" }, "chromeapp": { "dgram": "chrome-dgram", "fs": "level-filesystem" } } ``` on the other hand, if "react-native" is not present in package.json, you should fall back to "browser" other than the one (nesting) test added, the tests are unchanged, just done for both "react-native" and "browser" (I've implemented [react-native-udp](https://npmjs.org/package/react-native-udp) and [react-native-level-fs](https://npmjs.org/package/react-native-level-fs), but they obviously don't belong in the traditional "browser" field as they won't run anywhere except in React Native.) Closes https://github.com/facebook/react-native/pull/2208 Reviewed By: svcscm Differential Revision: D2691236 Pulled By: vjeux fb-gh-sync-id: 34041ed50bda4ec07f31d1dc50dcdfa428af2512
This commit is contained in:
parent
2b22d22a83
commit
b86f14738e
|
@ -1362,7 +1362,20 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should support simple browser field in packages', function() {
|
testBrowserField('browser')
|
||||||
|
testBrowserField('react-native')
|
||||||
|
|
||||||
|
function replaceBrowserField (json, fieldName) {
|
||||||
|
if (fieldName !== 'browser') {
|
||||||
|
json[fieldName] = json.browser
|
||||||
|
delete json.browser
|
||||||
|
}
|
||||||
|
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
function testBrowserField (fieldName) {
|
||||||
|
pit('should support simple browser field in packages ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1373,15 +1386,15 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
main: 'main.js',
|
main: 'main.js',
|
||||||
browser: 'client.js',
|
browser: 'client.js',
|
||||||
}),
|
}, fieldName)),
|
||||||
'main.js': 'some other code',
|
'main.js': 'some other code',
|
||||||
'client.js': 'some code',
|
'client.js': 'some code',
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
|
@ -1417,7 +1430,7 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should support browser field in packages w/o .js ext', function() {
|
pit('should support browser field in packages w/o .js ext ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1428,15 +1441,15 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
main: 'main.js',
|
main: 'main.js',
|
||||||
browser: 'client',
|
browser: 'client',
|
||||||
}),
|
}, fieldName)),
|
||||||
'main.js': 'some other code',
|
'main.js': 'some other code',
|
||||||
'client.js': 'some code',
|
'client.js': 'some code',
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
|
@ -1470,7 +1483,7 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should support mapping main in browser field json', function() {
|
pit('should support mapping main in browser field json ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1481,22 +1494,23 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
main: './main.js',
|
main: './main.js',
|
||||||
browser: {
|
browser: {
|
||||||
'./main.js': './client.js',
|
'./main.js': './client.js',
|
||||||
},
|
},
|
||||||
}),
|
}, fieldName)),
|
||||||
'main.js': 'some other code',
|
'main.js': 'some other code',
|
||||||
'client.js': 'some code',
|
'client.js': 'some code',
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
...defaults,
|
...defaults,
|
||||||
roots: [root],
|
roots: [root],
|
||||||
|
assetExts: ['png', 'jpg'],
|
||||||
});
|
});
|
||||||
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
||||||
expect(deps)
|
expect(deps)
|
||||||
|
@ -1525,7 +1539,7 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should work do correct browser mapping w/o js ext', function() {
|
pit('should work do correct browser mapping w/o js ext ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1536,22 +1550,23 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
main: './main.js',
|
main: './main.js',
|
||||||
browser: {
|
browser: {
|
||||||
'./main': './client.js',
|
'./main': './client.js',
|
||||||
},
|
},
|
||||||
}),
|
}, fieldName)),
|
||||||
'main.js': 'some other code',
|
'main.js': 'some other code',
|
||||||
'client.js': 'some code',
|
'client.js': 'some code',
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
...defaults,
|
...defaults,
|
||||||
roots: [root],
|
roots: [root],
|
||||||
|
assetExts: ['png', 'jpg'],
|
||||||
});
|
});
|
||||||
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
||||||
expect(deps)
|
expect(deps)
|
||||||
|
@ -1582,7 +1597,7 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should support browser mapping of files', function() {
|
pit('should support browser mapping of files ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1593,7 +1608,7 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
main: './main.js',
|
main: './main.js',
|
||||||
browser: {
|
browser: {
|
||||||
|
@ -1603,7 +1618,7 @@ describe('DependencyGraph', function() {
|
||||||
'./dir/server.js': './dir/client',
|
'./dir/server.js': './dir/client',
|
||||||
'./hello.js': './bye.js',
|
'./hello.js': './bye.js',
|
||||||
},
|
},
|
||||||
}),
|
}, fieldName)),
|
||||||
'main.js': 'some other code',
|
'main.js': 'some other code',
|
||||||
'client.js': 'require("./node")\nrequire("./dir/server.js")',
|
'client.js': 'require("./node")\nrequire("./dir/server.js")',
|
||||||
'not-node.js': 'require("./not-browser")',
|
'not-node.js': 'require("./not-browser")',
|
||||||
|
@ -1615,8 +1630,8 @@ describe('DependencyGraph', function() {
|
||||||
},
|
},
|
||||||
'hello.js': 'hello',
|
'hello.js': 'hello',
|
||||||
'bye.js': 'bye',
|
'bye.js': 'bye',
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
|
@ -1686,7 +1701,7 @@ describe('DependencyGraph', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
pit('should support browser mapping for packages', function() {
|
pit('should support browser mapping for packages ("' + fieldName + '")', function() {
|
||||||
var root = '/root';
|
var root = '/root';
|
||||||
fs.__setMockFilesystem({
|
fs.__setMockFilesystem({
|
||||||
'root': {
|
'root': {
|
||||||
|
@ -1697,12 +1712,12 @@ describe('DependencyGraph', function() {
|
||||||
'require("aPackage")',
|
'require("aPackage")',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
'aPackage': {
|
'aPackage': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
name: 'aPackage',
|
name: 'aPackage',
|
||||||
browser: {
|
browser: {
|
||||||
'node-package': 'browser-package',
|
'node-package': 'browser-package',
|
||||||
},
|
}
|
||||||
}),
|
}, fieldName)),
|
||||||
'index.js': 'require("node-package")',
|
'index.js': 'require("node-package")',
|
||||||
'node-package': {
|
'node-package': {
|
||||||
'package.json': JSON.stringify({
|
'package.json': JSON.stringify({
|
||||||
|
@ -1716,8 +1731,8 @@ describe('DependencyGraph', function() {
|
||||||
}),
|
}),
|
||||||
'index.js': 'some browser code',
|
'index.js': 'some browser code',
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var dgraph = new DependencyGraph({
|
var dgraph = new DependencyGraph({
|
||||||
|
@ -1757,6 +1772,171 @@ describe('DependencyGraph', function() {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('should support browser mapping for packages ("' + fieldName + '")', function() {
|
||||||
|
var root = '/root';
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
'index.js': [
|
||||||
|
'/**',
|
||||||
|
' * @providesModule index',
|
||||||
|
' */',
|
||||||
|
'require("aPackage")',
|
||||||
|
].join('\n'),
|
||||||
|
'aPackage': {
|
||||||
|
'package.json': JSON.stringify(replaceBrowserField({
|
||||||
|
name: 'aPackage',
|
||||||
|
browser: {
|
||||||
|
'node-package': 'browser-package',
|
||||||
|
}
|
||||||
|
}, fieldName)),
|
||||||
|
'index.js': 'require("node-package")',
|
||||||
|
'node-package': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
'name': 'node-package',
|
||||||
|
}),
|
||||||
|
'index.js': 'some node code',
|
||||||
|
},
|
||||||
|
'browser-package': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
'name': 'browser-package',
|
||||||
|
}),
|
||||||
|
'index.js': 'some browser code',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var dgraph = new DependencyGraph({
|
||||||
|
...defaults,
|
||||||
|
roots: [root],
|
||||||
|
});
|
||||||
|
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
||||||
|
expect(deps)
|
||||||
|
.toEqual([
|
||||||
|
{ id: 'index',
|
||||||
|
path: '/root/index.js',
|
||||||
|
dependencies: ['aPackage'],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{ id: 'aPackage/index.js',
|
||||||
|
path: '/root/aPackage/index.js',
|
||||||
|
dependencies: ['node-package'],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{ id: 'browser-package/index.js',
|
||||||
|
path: '/root/aPackage/browser-package/index.js',
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pit('should fall back to browser mapping from react-native mapping', function() {
|
||||||
|
var root = '/root';
|
||||||
|
fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
'index.js': [
|
||||||
|
'/**',
|
||||||
|
' * @providesModule index',
|
||||||
|
' */',
|
||||||
|
'require("aPackage")',
|
||||||
|
].join('\n'),
|
||||||
|
'aPackage': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
name: 'aPackage',
|
||||||
|
'react-native': {
|
||||||
|
'node-package': 'rn-package',
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
'index.js': 'require("node-package")',
|
||||||
|
'node_modules': {
|
||||||
|
'node-package': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
'name': 'node-package'
|
||||||
|
}),
|
||||||
|
'index.js': 'some node code',
|
||||||
|
},
|
||||||
|
'rn-package': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
'name': 'rn-package',
|
||||||
|
browser: {
|
||||||
|
'nested-package': 'nested-browser-package'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
'index.js': 'require("nested-package")',
|
||||||
|
},
|
||||||
|
'nested-browser-package': {
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
'name': 'nested-browser-package',
|
||||||
|
}),
|
||||||
|
'index.js': 'some code'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var dgraph = new DependencyGraph({
|
||||||
|
...defaults,
|
||||||
|
roots: [root],
|
||||||
|
});
|
||||||
|
return getOrderedDependenciesAsJSON(dgraph, '/root/index.js').then(function(deps) {
|
||||||
|
expect(deps)
|
||||||
|
.toEqual([
|
||||||
|
{ id: 'index',
|
||||||
|
path: '/root/index.js',
|
||||||
|
dependencies: ['aPackage'],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{ id: 'aPackage/index.js',
|
||||||
|
path: '/root/aPackage/index.js',
|
||||||
|
dependencies: ['node-package'],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{ id: 'rn-package/index.js',
|
||||||
|
path: '/root/aPackage/node_modules/rn-package/index.js',
|
||||||
|
dependencies: ['nested-package'],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
{ id: 'nested-browser-package/index.js',
|
||||||
|
path: '/root/aPackage/node_modules/nested-browser-package/index.js',
|
||||||
|
dependencies: [],
|
||||||
|
isAsset: false,
|
||||||
|
isAsset_DEPRECATED: false,
|
||||||
|
isJSON: false,
|
||||||
|
isPolyfill: false,
|
||||||
|
resolution: undefined,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('node_modules', function() {
|
describe('node_modules', function() {
|
||||||
|
|
|
@ -15,17 +15,18 @@ class Package {
|
||||||
|
|
||||||
getMain() {
|
getMain() {
|
||||||
return this._read().then(json => {
|
return this._read().then(json => {
|
||||||
if (typeof json.browser === 'string') {
|
var replacements = getReplacements(json)
|
||||||
return path.join(this.root, json.browser);
|
if (typeof replacements === 'string') {
|
||||||
|
return path.join(this.root, replacements);
|
||||||
}
|
}
|
||||||
|
|
||||||
let main = json.main || 'index';
|
let main = json.main || 'index';
|
||||||
|
|
||||||
if (json.browser && typeof json.browser === 'object') {
|
if (replacements && typeof replacements === 'object') {
|
||||||
main = json.browser[main] ||
|
main = replacements[main] ||
|
||||||
json.browser[main + '.js'] ||
|
replacements[main + '.js'] ||
|
||||||
json.browser[main + '.json'] ||
|
replacements[main + '.json'] ||
|
||||||
json.browser[main.replace(/(\.js|\.json)$/, '')] ||
|
replacements[main.replace(/(\.js|\.json)$/, '')] ||
|
||||||
main;
|
main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +52,14 @@ class Package {
|
||||||
|
|
||||||
redirectRequire(name) {
|
redirectRequire(name) {
|
||||||
return this._read().then(json => {
|
return this._read().then(json => {
|
||||||
const {browser} = json;
|
var replacements = getReplacements(json);
|
||||||
|
|
||||||
if (!browser || typeof browser !== 'object') {
|
if (!replacements || typeof replacements !== 'object') {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name[0] !== '/') {
|
if (name[0] !== '/') {
|
||||||
return browser[name] || name;
|
return replacements[name] || name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAbsolutePath(name)) {
|
if (!isAbsolutePath(name)) {
|
||||||
|
@ -66,9 +67,9 @@ class Package {
|
||||||
}
|
}
|
||||||
|
|
||||||
const relPath = './' + path.relative(this.root, name);
|
const relPath = './' + path.relative(this.root, name);
|
||||||
const redirect = browser[relPath] ||
|
const redirect = replacements[relPath] ||
|
||||||
browser[relPath + '.js'] ||
|
replacements[relPath + '.js'] ||
|
||||||
browser[relPath + '.json'];
|
replacements[relPath + '.json'];
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
return path.join(
|
return path.join(
|
||||||
this.root,
|
this.root,
|
||||||
|
@ -90,4 +91,10 @@ class Package {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getReplacements(pkg) {
|
||||||
|
return pkg['react-native'] == null
|
||||||
|
? pkg.browser
|
||||||
|
: pkg['react-native'];
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = Package;
|
module.exports = Package;
|
||||||
|
|
Loading…
Reference in New Issue