Prepare `__d` fn for Buck integration

Summary:
The new Packager/Buck integration passes module factory functions as first argument, so that the complete call can be amended at the end safely at a later point in time.
The call expression as a whole is covered perfectly by the created source map. Appending to that code later won’t break mappings.

`__d` now also accepts an additional `dependencyMap` parameter, which so far is only used by the new Packager/Buck integration. It enables module-local dependency IDs, thus eliminating the need to insert `correct` module IDs when building a bundle. Advantages are that source maps are no longer affected, and that builds can be quicker.

Reviewed By: cpojer

Differential Revision: D4124333

fbshipit-source-id: 12eba15d0b9d8c6624280a2ba1e7e4bc654bc83d
This commit is contained in:
David Aurelio 2016-11-04 05:07:34 -07:00 committed by Facebook Github Bot
parent c296a3ee25
commit dee58678c6
3 changed files with 35 additions and 27 deletions

View File

@ -366,19 +366,19 @@ describe('Resolver', function() {
dev: false,
}).then(({code: processedCode}) => {
expect(processedCode).toEqual([
`__d(${resolutionResponse.getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
'__d(/* test module */function(global, require, module, exports) {' +
// require
`require(${moduleIds.get('x')} /* x */)`,
`require(${moduleIds.get('y')} /* y */)`,
'require( \'z\' )',
'require( "a")',
'require("b" )',
'});',
`}, ${resolutionResponse.getModuleId(module)});`,
].join('\n'));
});
});
pit('should add module transport names as third argument to `__d`', () => {
pit('should add module transport names as fourth argument to `__d`', () => {
const module = createModule('test module');
const code = 'arbitrary(code)'
const resolutionResponse = new ResolutionResponseMock({
@ -393,9 +393,9 @@ describe('Resolver', function() {
dev: true,
}).then(({code: processedCode}) =>
expect(processedCode).toEqual([
`__d(${resolutionResponse.getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
'__d(/* test module */function(global, require, module, exports) {' +
code,
'}, "test module");'
`}, ${resolutionResponse.getModuleId(module)}, null, "test module");`
].join('\n'))
);
});
@ -455,8 +455,8 @@ describe('Resolver', function() {
.wrapModule({resolutionResponse, module, name: id, code, dev: false})
.then(({code: processedCode}) =>
expect(processedCode).toEqual([
`__d(${resolutionResponse.getModuleId(module)} /* ${id} */, function(global, require, module, exports) {`,
`module.exports = ${code}\n});`,
`__d(/* ${id} */function(global, require, module, exports) {`,
`module.exports = ${code}\n}, ${resolutionResponse.getModuleId(module)});`,
].join('')));
});
});
@ -483,7 +483,9 @@ describe('Resolver', function() {
});
pit('should invoke the minifier with the wrapped code', () => {
const wrappedCode = `__d(${resolutionResponse.getModuleId(module)} /* ${id} */, function(global, require, module, exports) {${code}\n});`
const wrappedCode =
`__d(/* ${id} */function(global, require, module, exports) {${
code}\n}, ${resolutionResponse.getModuleId(module)});`
return depResolver
.wrapModule({
resolutionResponse,

View File

@ -259,12 +259,12 @@ class Resolver {
function defineModuleCode(moduleName, code, verboseName = '', dev = true) {
return [
'__d(',
`${JSON.stringify(moduleName)} /* ${verboseName} */, `,
'function(global, require, module, exports) {',
`__d(/* ${verboseName} */`,
'function(global, require, module, exports) {', // module factory
code,
'\n}',
dev ? `, ${JSON.stringify(verboseName)}` : '',
'\n}, ',
`${JSON.stringify(moduleName)}`, // module id, null = id map. used in ModuleGraph
dev ? `, null, ${JSON.stringify(verboseName)}` : '',
');',
].join('');
}

View File

@ -11,12 +11,14 @@
'use strict';
type DependencyMap = Array<ModuleID>;
type Exports = any;
type FactoryFn = (
global: Object,
require: RequireFn,
moduleObject: {exports: {}},
exports: {},
dependencyMap: ?DependencyMap,
) => void;
type HotModuleReloadingAcceptFn = Function;
type HotModuleReloadingData = {|
@ -29,12 +31,13 @@ type Module = {
};
type ModuleID = number;
type ModuleDefinition = {|
dependencyMap: ?DependencyMap,
exports: Exports,
factory: FactoryFn,
hasError: boolean,
isInitialized: boolean,
exports: Exports,
verboseName?: string,
hot?: HotModuleReloadingData,
isInitialized: boolean,
verboseName?: string,
|};
type ModuleMap =
{[key: ModuleID]: (ModuleDefinition)};
@ -50,8 +53,9 @@ if (__DEV__) {
}
function define(
moduleId: number,
factory: FactoryFn,
moduleId: number,
dependencyMap?: DependencyMap,
) {
if (moduleId in modules) {
// prevent repeated calls to `global.nativeRequire` to overwrite modules
@ -59,18 +63,20 @@ function define(
return;
}
modules[moduleId] = {
dependencyMap,
exports: undefined,
factory,
hasError: false,
isInitialized: false,
exports: undefined,
};
if (__DEV__) {
// HMR
modules[moduleId].hot = createHotReloadingObject();
// DEBUGGABLE MODULES NAMES
// avoid unnecessary parameter in prod
const verboseName: string | void = arguments[2];
// we take `verboseName` from `arguments` to avoid an unused named parameter
// in `define` in production.
const verboseName: string | void = arguments[3];
if (verboseName) {
modules[moduleId].verboseName = verboseName;
verboseNamesToModuleIds[verboseName] = moduleId;
@ -90,14 +96,14 @@ function require(moduleId: ModuleID | VerboseModuleNameForDev) {
'debugging purposes and will BREAK IN PRODUCTION!'
);
}
} else {
moduleId = +moduleId;
}
const module = modules[moduleId];
//$FlowFixMe: at this point we know that moduleId is a number
const moduleIdReallyIsNumber: number = moduleId;
const module = modules[moduleIdReallyIsNumber];
return module && module.isInitialized
? module.exports
: guardedLoadModule(moduleId, module);
: guardedLoadModule(moduleIdReallyIsNumber, module);
}
let inGuard = false;
@ -146,7 +152,7 @@ function loadModuleImplementation(moduleId, module) {
// infinite require loop.
module.isInitialized = true;
const exports = module.exports = {};
const {factory} = module;
const {factory, dependencyMap} = module;
try {
if (__DEV__) {
// $FlowFixMe: we know that __DEV__ is const and `Systrace` exists
@ -161,7 +167,7 @@ function loadModuleImplementation(moduleId, module) {
// keep args in sync with with defineModuleCode in
// packager/react-packager/src/Resolver/index.js
// and packager/react-packager/src/ModuleGraph/worker.js
factory(global, require, moduleObject, exports);
factory(global, require, moduleObject, exports, dependencyMap);
// avoid removing factory in DEV mode as it breaks HMR
if (!__DEV__) {
@ -239,7 +245,7 @@ if (__DEV__) {
const mod = modules[id];
if (!mod && factory) { // new modules need a factory
define(id, factory);
define(factory, id);
return true; // new modules don't need to be accepted
}