mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-06 17:52:57 +08:00
Summary: We don't (yet) treat these the same as any other modules because we still have special resolution rules for them in the packager allowing the use of `providesModule`, but I believe this allows people to use npm react in their RN projects and not have duplicate copies of React. Fixes facebook/react-native#2985. This relies on fbjs 0.6, which includes `.flow` files alongside the `.js` files to allow them to be typechecked without additional configuration. This also uses react 0.14.5, which shims a couple of files (as `.native.js`) to avoid DOM-specific bits. Once we fix these in React, we will use the same code on web and native. Hopefully we can also remove the packager support I'm adding here for `.native.js`. This diff is not the desired end state for us – ideally the packager would know nothing of react or fbjs, and we'll get there eventually by not relying on `providesModule` in order to load react and fbjs modules. (fbjs change posted here but not merged yet: https://github.com/facebook/fbjs/pull/84.) This should also allow relay to work seamlessly with RN, but I haven't verified this. public Reviewed By: sebmarkbage Differential Revision: D2786197 fb-gh-sync-id: ff50f28445e949edc9501f4b599df7970813870d
143 lines
3.9 KiB
JavaScript
143 lines
3.9 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
'use strict';
|
|
const path = require('path');
|
|
const getPlatformExtension = require('../lib/getPlatformExtension');
|
|
const Promise = require('promise');
|
|
|
|
const GENERIC_PLATFORM = 'generic';
|
|
const NATIVE_PLATFORM = 'native';
|
|
|
|
class HasteMap {
|
|
constructor({
|
|
extensions,
|
|
fastfs,
|
|
moduleCache,
|
|
preferNativePlatform,
|
|
helpers,
|
|
}) {
|
|
this._extensions = extensions;
|
|
this._fastfs = fastfs;
|
|
this._moduleCache = moduleCache;
|
|
this._preferNativePlatform = preferNativePlatform;
|
|
this._helpers = helpers;
|
|
}
|
|
|
|
build() {
|
|
this._map = Object.create(null);
|
|
|
|
let promises = this._fastfs.findFilesByExts(this._extensions, {
|
|
ignore: (file) => this._helpers.isNodeModulesDir(file),
|
|
}).map(file => this._processHasteModule(file));
|
|
|
|
promises = promises.concat(
|
|
this._fastfs.findFilesByName('package.json', {
|
|
ignore: (file) => this._helpers.isNodeModulesDir(file),
|
|
}).map(file => this._processHastePackage(file))
|
|
);
|
|
|
|
return Promise.all(promises);
|
|
}
|
|
|
|
processFileChange(type, absPath) {
|
|
return Promise.resolve().then(() => {
|
|
/*eslint no-labels: 0 */
|
|
if (type === 'delete' || type === 'change') {
|
|
loop: for (const name in this._map) {
|
|
const modulesMap = this._map[name];
|
|
for (const platform in modulesMap) {
|
|
const module = modulesMap[platform];
|
|
if (module.path === absPath) {
|
|
delete modulesMap[platform];
|
|
break loop;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type === 'delete') {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (this._extensions.indexOf(this._helpers.extname(absPath)) !== -1) {
|
|
if (path.basename(absPath) === 'package.json') {
|
|
return this._processHastePackage(absPath);
|
|
} else {
|
|
return this._processHasteModule(absPath);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
getModule(name, platform = null) {
|
|
const modulesMap = this._map[name];
|
|
if (modulesMap == null) {
|
|
return null;
|
|
}
|
|
|
|
// If platform is 'ios', we prefer .ios.js to .native.js which we prefer to
|
|
// a plain .js file.
|
|
let module = undefined;
|
|
if (module == null && platform != null) {
|
|
module = modulesMap[platform];
|
|
}
|
|
if (module == null && this._preferNativePlatform) {
|
|
module = modulesMap[NATIVE_PLATFORM];
|
|
}
|
|
if (module == null) {
|
|
module = modulesMap[GENERIC_PLATFORM];
|
|
}
|
|
return module;
|
|
}
|
|
|
|
_processHasteModule(file) {
|
|
const module = this._moduleCache.getModule(file);
|
|
return module.isHaste().then(
|
|
isHaste => isHaste && module.getName()
|
|
.then(name => this._updateHasteMap(name, module))
|
|
);
|
|
}
|
|
|
|
_processHastePackage(file) {
|
|
file = path.resolve(file);
|
|
const p = this._moduleCache.getPackage(file, this._fastfs);
|
|
return p.isHaste()
|
|
.then(isHaste => isHaste && p.getName()
|
|
.then(name => this._updateHasteMap(name, p)))
|
|
.catch(e => {
|
|
if (e instanceof SyntaxError) {
|
|
// Malformed package.json.
|
|
return;
|
|
}
|
|
throw e;
|
|
});
|
|
}
|
|
|
|
_updateHasteMap(name, mod) {
|
|
if (this._map[name] == null) {
|
|
this._map[name] = Object.create(null);
|
|
}
|
|
|
|
const moduleMap = this._map[name];
|
|
const modulePlatform = getPlatformExtension(mod.path) || GENERIC_PLATFORM;
|
|
const existingModule = moduleMap[modulePlatform];
|
|
|
|
if (existingModule && existingModule.path !== mod.path) {
|
|
throw new Error(
|
|
`Naming collision detected: ${mod.path} ` +
|
|
`collides with ${existingModule.path}`
|
|
);
|
|
}
|
|
|
|
moduleMap[modulePlatform] = mod;
|
|
}
|
|
}
|
|
|
|
module.exports = HasteMap;
|