2015-11-04 16:04:44 -08:00
|
|
|
/**
|
|
|
|
* 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';
|
|
|
|
|
|
|
|
|
2015-11-09 13:32:42 -08:00
|
|
|
const path = require('path');
|
|
|
|
const Activity = require('../Activity');
|
2016-07-29 11:00:08 -07:00
|
|
|
const DependencyGraph = require('../node-haste');
|
2015-11-09 13:32:42 -08:00
|
|
|
const declareOpts = require('../lib/declareOpts');
|
|
|
|
const Promise = require('promise');
|
|
|
|
|
|
|
|
const validateOpts = declareOpts({
|
2015-11-04 16:04:44 -08:00
|
|
|
projectRoots: {
|
|
|
|
type: 'array',
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
blacklistRE: {
|
|
|
|
type: 'object', // typeof regex is object
|
|
|
|
},
|
|
|
|
polyfillModuleNames: {
|
|
|
|
type: 'array',
|
|
|
|
default: [],
|
|
|
|
},
|
|
|
|
moduleFormat: {
|
|
|
|
type: 'string',
|
|
|
|
default: 'haste',
|
|
|
|
},
|
|
|
|
assetRoots: {
|
|
|
|
type: 'array',
|
|
|
|
default: [],
|
|
|
|
},
|
|
|
|
fileWatcher: {
|
|
|
|
type: 'object',
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
assetExts: {
|
|
|
|
type: 'array',
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
cache: {
|
|
|
|
type: 'object',
|
|
|
|
required: true,
|
|
|
|
},
|
2016-03-08 09:50:14 -08:00
|
|
|
transformCode: {
|
|
|
|
type: 'function',
|
|
|
|
},
|
2016-04-28 06:32:52 -07:00
|
|
|
extraNodeModules: {
|
|
|
|
type: 'object',
|
|
|
|
required: false,
|
|
|
|
},
|
2016-03-08 09:50:14 -08:00
|
|
|
minifyCode: {
|
|
|
|
type: 'function',
|
|
|
|
},
|
2015-11-04 16:04:44 -08:00
|
|
|
});
|
|
|
|
|
2015-11-09 13:32:42 -08:00
|
|
|
const getDependenciesValidateOpts = declareOpts({
|
2015-11-04 16:04:44 -08:00
|
|
|
dev: {
|
|
|
|
type: 'boolean',
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
platform: {
|
|
|
|
type: 'string',
|
|
|
|
required: false,
|
|
|
|
},
|
2016-02-12 08:27:31 -08:00
|
|
|
unbundle: {
|
2015-12-01 07:42:44 -08:00
|
|
|
type: 'boolean',
|
|
|
|
default: false
|
|
|
|
},
|
2016-01-29 10:14:37 -08:00
|
|
|
recursive: {
|
|
|
|
type: 'boolean',
|
|
|
|
default: true,
|
|
|
|
},
|
2015-11-04 16:04:44 -08:00
|
|
|
});
|
|
|
|
|
|
|
|
class Resolver {
|
|
|
|
|
|
|
|
constructor(options) {
|
2015-11-09 13:32:42 -08:00
|
|
|
const opts = validateOpts(options);
|
2015-11-04 16:04:44 -08:00
|
|
|
|
|
|
|
this._depGraph = new DependencyGraph({
|
2015-11-09 13:32:42 -08:00
|
|
|
activity: Activity,
|
2015-11-04 16:04:44 -08:00
|
|
|
roots: opts.projectRoots,
|
|
|
|
assetRoots_DEPRECATED: opts.assetRoots,
|
|
|
|
assetExts: opts.assetExts,
|
|
|
|
ignoreFilePath: function(filepath) {
|
|
|
|
return filepath.indexOf('__tests__') !== -1 ||
|
|
|
|
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
|
|
|
},
|
2015-11-09 13:32:46 -08:00
|
|
|
providesModuleNodeModules: [
|
|
|
|
'react-native',
|
2016-05-20 05:27:13 -07:00
|
|
|
'react-native-windows',
|
2015-11-09 13:32:46 -08:00
|
|
|
// Parse requires AsyncStorage. They will
|
|
|
|
// change that to require('react-native') which
|
|
|
|
// should work after this release and we can
|
|
|
|
// remove it from here.
|
|
|
|
'parse',
|
|
|
|
],
|
2016-05-24 05:09:39 -07:00
|
|
|
platforms: ['ios', 'android', 'windows', 'web'],
|
2015-12-30 11:38:44 -08:00
|
|
|
preferNativePlatform: true,
|
2015-11-04 16:04:44 -08:00
|
|
|
fileWatcher: opts.fileWatcher,
|
|
|
|
cache: opts.cache,
|
2016-01-07 06:13:14 -08:00
|
|
|
shouldThrowOnUnresolvedErrors: (_, platform) => platform === 'ios',
|
2016-03-08 09:50:14 -08:00
|
|
|
transformCode: opts.transformCode,
|
2016-04-28 06:32:52 -07:00
|
|
|
extraNodeModules: opts.extraNodeModules,
|
2016-04-06 07:58:36 -07:00
|
|
|
assetDependencies: ['react-native/Libraries/Image/AssetRegistry'],
|
2015-11-04 16:04:44 -08:00
|
|
|
});
|
|
|
|
|
2016-03-08 09:50:14 -08:00
|
|
|
this._minifyCode = opts.minifyCode;
|
2015-11-04 16:04:44 -08:00
|
|
|
this._polyfillModuleNames = opts.polyfillModuleNames || [];
|
2016-02-02 18:09:45 -08:00
|
|
|
|
|
|
|
this._depGraph.load().catch(err => {
|
|
|
|
console.error(err.message + '\n' + err.stack);
|
|
|
|
process.exit(1);
|
|
|
|
});
|
2015-11-04 16:04:44 -08:00
|
|
|
}
|
|
|
|
|
2016-04-06 11:36:57 -07:00
|
|
|
getShallowDependencies(entryFile, transformOptions) {
|
|
|
|
return this._depGraph.getShallowDependencies(entryFile, transformOptions);
|
2015-12-29 18:24:08 -08:00
|
|
|
}
|
|
|
|
|
2016-01-07 08:48:39 -08:00
|
|
|
stat(filePath) {
|
2016-02-01 16:59:28 -08:00
|
|
|
return this._depGraph.getFS().stat(filePath);
|
2016-01-07 08:48:39 -08:00
|
|
|
}
|
|
|
|
|
2016-01-04 13:01:28 -08:00
|
|
|
getModuleForPath(entryFile) {
|
|
|
|
return this._depGraph.getModuleForPath(entryFile);
|
|
|
|
}
|
|
|
|
|
2016-05-12 17:13:12 -07:00
|
|
|
getDependencies(entryPath, options, transformOptions, onProgress, getModuleId) {
|
2016-02-23 06:09:38 -08:00
|
|
|
const {platform, recursive} = getDependenciesValidateOpts(options);
|
|
|
|
return this._depGraph.getDependencies({
|
|
|
|
entryPath,
|
|
|
|
platform,
|
2016-03-08 09:50:14 -08:00
|
|
|
transformOptions,
|
2016-02-23 06:09:38 -08:00
|
|
|
recursive,
|
2016-03-08 09:50:14 -08:00
|
|
|
onProgress,
|
2016-02-23 06:09:38 -08:00
|
|
|
}).then(resolutionResponse => {
|
2016-01-29 10:14:37 -08:00
|
|
|
this._getPolyfillDependencies().reverse().forEach(
|
|
|
|
polyfill => resolutionResponse.prependDependency(polyfill)
|
|
|
|
);
|
2015-11-04 16:04:44 -08:00
|
|
|
|
2016-05-12 17:13:12 -07:00
|
|
|
resolutionResponse.getModuleId = getModuleId;
|
2016-01-29 10:14:37 -08:00
|
|
|
return resolutionResponse.finalize();
|
|
|
|
});
|
2015-11-04 16:04:44 -08:00
|
|
|
}
|
|
|
|
|
2015-11-25 17:34:55 -08:00
|
|
|
getModuleSystemDependencies(options) {
|
|
|
|
const opts = getDependenciesValidateOpts(options);
|
|
|
|
|
|
|
|
const prelude = opts.dev
|
2015-11-04 16:04:44 -08:00
|
|
|
? path.join(__dirname, 'polyfills/prelude_dev.js')
|
2015-11-25 17:34:55 -08:00
|
|
|
: path.join(__dirname, 'polyfills/prelude.js');
|
|
|
|
|
2016-05-03 15:18:10 -07:00
|
|
|
const moduleSystem = path.join(__dirname, 'polyfills/require.js');
|
2015-11-25 17:34:55 -08:00
|
|
|
|
|
|
|
return [
|
|
|
|
prelude,
|
|
|
|
moduleSystem
|
2016-02-23 06:09:38 -08:00
|
|
|
].map(moduleName => this._depGraph.createPolyfill({
|
|
|
|
file: moduleName,
|
2015-11-25 17:34:55 -08:00
|
|
|
id: moduleName,
|
|
|
|
dependencies: [],
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
_getPolyfillDependencies() {
|
|
|
|
const polyfillModuleNames = [
|
2015-11-04 16:04:44 -08:00
|
|
|
path.join(__dirname, 'polyfills/polyfills.js'),
|
|
|
|
path.join(__dirname, 'polyfills/console.js'),
|
|
|
|
path.join(__dirname, 'polyfills/error-guard.js'),
|
2016-04-25 23:14:45 -07:00
|
|
|
path.join(__dirname, 'polyfills/Number.es6.js'),
|
2015-11-04 16:04:44 -08:00
|
|
|
path.join(__dirname, 'polyfills/String.prototype.es6.js'),
|
|
|
|
path.join(__dirname, 'polyfills/Array.prototype.es6.js'),
|
2015-11-06 17:19:55 -08:00
|
|
|
path.join(__dirname, 'polyfills/Array.es6.js'),
|
2016-01-28 17:20:39 -08:00
|
|
|
path.join(__dirname, 'polyfills/Object.es7.js'),
|
2015-11-11 22:53:04 -08:00
|
|
|
path.join(__dirname, 'polyfills/babelHelpers.js'),
|
2015-11-04 16:04:44 -08:00
|
|
|
].concat(this._polyfillModuleNames);
|
|
|
|
|
|
|
|
return polyfillModuleNames.map(
|
2016-02-23 06:09:38 -08:00
|
|
|
(polyfillModuleName, idx) => this._depGraph.createPolyfill({
|
|
|
|
file: polyfillModuleName,
|
2015-11-04 16:04:44 -08:00
|
|
|
id: polyfillModuleName,
|
|
|
|
dependencies: polyfillModuleNames.slice(0, idx),
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-03-08 09:50:14 -08:00
|
|
|
resolveRequires(resolutionResponse, module, code, dependencyOffsets = []) {
|
2016-03-14 16:16:22 -07:00
|
|
|
const resolvedDeps = Object.create(null);
|
|
|
|
|
|
|
|
// here, we build a map of all require strings (relative and absolute)
|
|
|
|
// to the canonical ID of the module they reference
|
|
|
|
resolutionResponse.getResolvedDependencyPairs(module)
|
|
|
|
.forEach(([depName, depModule]) => {
|
|
|
|
if (depModule) {
|
2016-05-12 17:13:12 -07:00
|
|
|
resolvedDeps[depName] = resolutionResponse.getModuleId(depModule);
|
2016-03-14 16:16:22 -07:00
|
|
|
}
|
2015-11-04 16:04:44 -08:00
|
|
|
});
|
2016-03-14 16:16:22 -07:00
|
|
|
|
|
|
|
// if we have a canonical ID for the module imported here,
|
|
|
|
// we use it, so that require() is always called with the same
|
|
|
|
// id for every module.
|
|
|
|
// Example:
|
|
|
|
// -- in a/b.js:
|
|
|
|
// require('./c') => require(3);
|
|
|
|
// -- in b/index.js:
|
|
|
|
// require('../a/c') => require(3);
|
|
|
|
const replaceModuleId = (codeMatch, quote, depName) =>
|
|
|
|
depName in resolvedDeps
|
|
|
|
? `${JSON.stringify(resolvedDeps[depName])} /* ${depName} */`
|
|
|
|
: codeMatch;
|
|
|
|
|
|
|
|
code = dependencyOffsets.reduceRight((codeBits, offset) => {
|
|
|
|
const first = codeBits.shift();
|
|
|
|
codeBits.unshift(
|
|
|
|
first.slice(0, offset),
|
|
|
|
first.slice(offset).replace(/(['"])([^'"']*)\1/, replaceModuleId),
|
|
|
|
);
|
|
|
|
return codeBits;
|
|
|
|
}, [code]);
|
|
|
|
|
|
|
|
return code.join('');
|
2015-11-04 16:04:44 -08:00
|
|
|
}
|
|
|
|
|
2016-03-08 09:50:14 -08:00
|
|
|
wrapModule({
|
|
|
|
resolutionResponse,
|
|
|
|
module,
|
|
|
|
name,
|
|
|
|
map,
|
|
|
|
code,
|
|
|
|
meta = {},
|
2016-05-04 09:32:30 -07:00
|
|
|
dev = true,
|
2016-03-08 09:50:14 -08:00
|
|
|
minify = false
|
|
|
|
}) {
|
|
|
|
if (module.isJSON()) {
|
|
|
|
code = `module.exports = ${code}`;
|
2016-01-06 09:46:56 -08:00
|
|
|
}
|
2016-03-14 16:16:22 -07:00
|
|
|
|
|
|
|
if (module.isPolyfill()) {
|
|
|
|
code = definePolyfillCode(code);
|
|
|
|
} else {
|
2016-05-12 17:13:12 -07:00
|
|
|
const moduleId = resolutionResponse.getModuleId(module);
|
2016-03-14 16:16:22 -07:00
|
|
|
code = this.resolveRequires(
|
2016-03-08 09:50:14 -08:00
|
|
|
resolutionResponse,
|
|
|
|
module,
|
|
|
|
code,
|
|
|
|
meta.dependencyOffsets
|
2016-03-14 16:16:22 -07:00
|
|
|
);
|
2016-05-04 09:32:30 -07:00
|
|
|
code = defineModuleCode(moduleId, code, name, dev);
|
2016-03-14 16:16:22 -07:00
|
|
|
}
|
|
|
|
|
2016-03-08 09:50:14 -08:00
|
|
|
|
|
|
|
return minify
|
2016-03-14 16:16:22 -07:00
|
|
|
? this._minifyCode(module.path, code, map)
|
|
|
|
: Promise.resolve({code, map});
|
2016-01-06 09:46:56 -08:00
|
|
|
}
|
|
|
|
|
2016-03-13 11:13:40 -07:00
|
|
|
minifyModule({path, code, map}) {
|
|
|
|
return this._minifyCode(path, code, map);
|
|
|
|
}
|
2015-11-04 16:04:44 -08:00
|
|
|
}
|
|
|
|
|
2016-05-04 09:32:30 -07:00
|
|
|
function defineModuleCode(moduleName, code, verboseName = '', dev = true) {
|
2015-11-04 16:04:44 -08:00
|
|
|
return [
|
2016-05-04 09:32:30 -07:00
|
|
|
'__d(',
|
2016-03-14 16:16:22 -07:00
|
|
|
`${JSON.stringify(moduleName)} /* ${verboseName} */, `,
|
2016-05-04 09:32:30 -07:00
|
|
|
'function(global, require, module, exports) {',
|
|
|
|
code,
|
|
|
|
'\n}',
|
|
|
|
dev ? `, ${JSON.stringify(verboseName)}` : '',
|
|
|
|
');',
|
2015-11-04 16:04:44 -08:00
|
|
|
].join('');
|
|
|
|
}
|
|
|
|
|
2016-03-08 09:50:14 -08:00
|
|
|
function definePolyfillCode(code,) {
|
2016-01-21 07:22:20 -08:00
|
|
|
return [
|
2016-03-08 09:50:14 -08:00
|
|
|
`(function(global) {`,
|
2016-01-21 07:22:20 -08:00
|
|
|
code,
|
|
|
|
`\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);`,
|
|
|
|
].join('');
|
|
|
|
}
|
|
|
|
|
2015-11-04 16:04:44 -08:00
|
|
|
module.exports = Resolver;
|