Fix @providesModule not being ignored properly

Summary:
There's quite a bit of code scattered around the packager regarding ignoring the `providesModule` Haste pragma in any file that isn't in `react-native`, `react-tools` or `parse`. There is even a (passing) test case.

However, there's an edge case.

Take, for example, `fbjs`. It has a module inside of it called `ErrorUtils`. `react-relay` requires this file normally, in Common.JS style, by doing `require('fbjs/libs/ErrorUtils')`. But when `react-native` attempts to require `ErrorUtils` using the HasteModule format (in it's JavaScript initialization), it resolves the `fbjs` `ErrorUtils` module, instead of RN's `ErrorUtils`.

This happens, it turns out, because when a module is read (in `Module._read`), it's not caring about whether or not it should pay attention to `providesModule`, and is just assigning the `providesModule` value as the id of the module no matter what. Then when `Module.getName` is called, it will always use that `data.id` that was set, thus creating the wrong dependency tree.

This
Closes https://github.com/facebook/react-native/pull/3625

Reviewed By: svcscm

Differential Revision: D2632317

Pulled By: vjeux

fb-gh-sync-id: efd8066eaf6f18fcf79698beab36cab90bf5cd6d
This commit is contained in:
Adam Miskiewicz
2015-12-24 08:31:17 -08:00
committed by facebook-github-bot-5
parent 59885911e3
commit 6cec263ca3
11 changed files with 140 additions and 54 deletions

View File

@@ -15,7 +15,7 @@ const extractRequires = require('./lib/extractRequires');
class Module {
constructor(file, fastfs, moduleCache, cache, extractor) {
constructor({ file, fastfs, moduleCache, cache, extractor, depGraphHelpers }) {
if (!isAbsolutePath(file)) {
throw new Error('Expected file to be absolute path but got ' + file);
}
@@ -27,17 +27,18 @@ class Module {
this._moduleCache = moduleCache;
this._cache = cache;
this._extractor = extractor;
this._depGraphHelpers = depGraphHelpers;
}
isHaste() {
return this._read().then(data => !!data.id);
return this.read().then(data => !!data.id);
}
getName() {
return this._cache.get(
this.path,
'name',
() => this._read().then(data => {
() => this.read().then(data => {
if (data.id) {
return data.id;
}
@@ -66,23 +67,31 @@ class Module {
}
getDependencies() {
return this._read().then(data => data.dependencies);
return this.read().then(data => data.dependencies);
}
getAsyncDependencies() {
return this._read().then(data => data.asyncDependencies);
return this.read().then(data => data.asyncDependencies);
}
invalidate() {
this._cache.invalidate(this.path);
}
_read() {
read() {
if (!this._reading) {
this._reading = this._fastfs.readFile(this.path).then(content => {
const data = {};
// Set an id on the module if it's using @providesModule syntax
// and if it's NOT in node_modules (and not a whitelisted node_module).
// This handles the case where a project may have a dep that has @providesModule
// docblock comments, but doesn't want it to conflict with whitelisted @providesModule
// modules, such as react-haste, fbjs-haste, or react-native or with non-dependency,
// project-specific code that is using @providesModule.
const moduleDocBlock = docblock.parseAsObject(content);
if (moduleDocBlock.providesModule || moduleDocBlock.provides) {
if (!this._depGraphHelpers.isNodeModulesDir(this.path) &&
(moduleDocBlock.providesModule || moduleDocBlock.provides)) {
data.id = /^(\S*)/.exec(
moduleDocBlock.providesModule || moduleDocBlock.provides
)[1];