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

View File

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

View File

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