Simplify HMR codepath

Reviewed By: davidaurelio

Differential Revision: D2839590

fb-gh-sync-id: 9bb14cafc69eec7d7a8712b60435e29f2ba48d3c
This commit is contained in:
Martín Bigio 2016-01-20 07:13:26 -08:00 committed by facebook-github-bot-7
parent b324dc6ae5
commit 95b69d548b
6 changed files with 537 additions and 447 deletions

View File

@ -10,6 +10,7 @@
const _ = require('underscore');
const base64VLQ = require('./base64-vlq');
const BundleBase = require('./BundleBase');
const UglifyJS = require('uglify-js');
const ModuleTransport = require('../lib/ModuleTransport');
const Activity = require('../Activity');
@ -24,11 +25,9 @@ const getNameAndCode = ({name, code}) => ({name, code});
const getNameAndMinifiedCode =
({name, code}) => ({name, code: minifyCode(code)});
class Bundle {
class Bundle extends BundleBase {
constructor(sourceMapUrl) {
this._finalized = false;
this._modules = [];
this._assets = [];
super();
this._sourceMap = false;
this._sourceMapUrl = sourceMapUrl;
this._shouldCombineSourceMaps = false;
@ -36,58 +35,49 @@ class Bundle {
this._numRequireCalls = 0;
}
setMainModuleId(moduleId) {
this._mainModuleId = moduleId;
}
addModule(resolver, response, module, transformed) {
return resolver.wrapModule(
response,
module,
transformed.code
).then(({code, name}) => {
const moduleTransport = new ModuleTransport({
code,
name,
map: transformed.map,
sourceCode: transformed.sourceCode,
sourcePath: transformed.sourcePath,
virtual: transformed.virtual,
});
addModule(module) {
if (!(module instanceof ModuleTransport)) {
throw new Error('Expeceted a ModuleTransport object');
}
// If we get a map from the transformer we'll switch to a mode
// were we're combining the source maps as opposed to
if (!this._shouldCombineSourceMaps && moduleTransport.map != null) {
this._shouldCombineSourceMaps = true;
}
// If we get a map from the transformer we'll switch to a mode
// were we're combining the source maps as opposed to
if (!this._shouldCombineSourceMaps && module.map != null) {
this._shouldCombineSourceMaps = true;
}
this._modules.push(module);
}
getModules() {
return this._modules;
}
getMainModuleId() {
return this._mainModuleId;
super.addModule(moduleTransport);
});
}
setNumPrependedModules(n) {
this._numPrependedModules = n;
}
addAsset(asset) {
this._assets.push(asset);
}
finalize(options) {
options = options || {};
if (options.runMainModule) {
options.runBeforeMainModule.forEach(this._addRequireCall, this);
this._addRequireCall(this._mainModuleId);
this._addRequireCall(super.getMainModuleId());
}
Object.freeze(this._modules);
Object.seal(this._modules);
Object.freeze(this._assets);
Object.seal(this._assets);
this._finalized = true;
super.finalize();
}
_addRequireCall(moduleId) {
const code = ';require("' + moduleId + '");';
const name = 'require-' + moduleId;
this.addModule(new ModuleTransport({
super.addModule(new ModuleTransport({
name,
code,
virtual: true,
@ -97,21 +87,6 @@ class Bundle {
this._numRequireCalls += 1;
}
_assertFinalized() {
if (!this._finalized) {
throw new Error('Bundle needs to be finalized before getting any source');
}
}
_getSource(dev) {
if (this._source) {
return this._source;
}
this._source = _.pluck(this._modules, 'code').join('\n');
return this._source;
}
_getInlineSourceMap(dev) {
if (this._inlineSourceMap == null) {
const sourceMap = this.getSourceMap({excludeSource: true, dev});
@ -123,7 +98,7 @@ class Bundle {
}
getSource(options) {
this._assertFinalized();
super.assertFinalized();
options = options || {};
@ -131,7 +106,7 @@ class Bundle {
return this.getMinifiedSourceAndMap(options.dev).code;
}
let source = this._getSource(options.dev);
let source = super.getSource();
if (options.inlineSourceMap) {
source += SOURCEMAPPING_URL + this._getInlineSourceMap(options.dev);
@ -143,7 +118,7 @@ class Bundle {
}
getUnbundle({minify}) {
const allModules = this._modules.slice();
const allModules = super.getModules().slice();
const prependedModules = this._numPrependedModules;
const requireCalls = this._numRequireCalls;
@ -163,13 +138,13 @@ class Bundle {
}
getMinifiedSourceAndMap(dev) {
this._assertFinalized();
super.assertFinalized();
if (this._minifiedSourceAndMap) {
return this._minifiedSourceAndMap;
}
let source = this._getSource(dev);
let source = this.getSource();
let map = this.getSourceMap();
if (!dev) {
@ -235,7 +210,7 @@ class Bundle {
};
let line = 0;
this._modules.forEach(function(module) {
super.getModules().forEach(function(module) {
let map = module.map;
if (module.virtual) {
map = generateSourceMapForVirtualModule(module);
@ -256,7 +231,7 @@ class Bundle {
}
getSourceMap(options) {
this._assertFinalized();
super.assertFinalized();
options = options || {};
@ -271,22 +246,18 @@ class Bundle {
const mappings = this._getMappings();
const map = {
file: 'bundle.js',
sources: _.pluck(this._modules, 'sourcePath'),
sources: _.pluck(super.getModules(), 'sourcePath'),
version: 3,
names: [],
mappings: mappings,
sourcesContent: options.excludeSource
? [] : _.pluck(this._modules, 'sourceCode')
? [] : _.pluck(super.getModules(), 'sourceCode')
};
return map;
}
getAssets() {
return this._assets;
}
_getMappings() {
const modules = this._modules;
const modules = super.getModules();
// The first line mapping in our package is basically the base64vlq code for
// zeros (A).
@ -333,7 +304,7 @@ class Bundle {
}
getJSModulePaths() {
return this._modules.filter(function(module) {
return super.getModules().filter(function(module) {
// Filter out non-js files. Like images etc.
return !module.virtual;
}).map(function(module) {
@ -343,7 +314,7 @@ class Bundle {
getDebugInfo() {
return [
'<div><h3>Main Module:</h3> ' + this._mainModuleId + '</div>',
'<div><h3>Main Module:</h3> ' + super.getMainModuleId() + '</div>',
'<style>',
'pre.collapsed {',
' height: 10px;',
@ -355,7 +326,7 @@ class Bundle {
'}',
'</style>',
'<h3> Module paths and transformed code: </h3>',
this._modules.map(function(m) {
super.getModules().map(function(m) {
return '<div> <h4> Path: </h4>' + m.sourcePath + '<br/> <h4> Source: </h4>' +
'<code><pre class="collapsed" onclick="this.classList.remove(\'collapsed\')">' +
_.escape(m.code) + '</pre></code></div>';
@ -369,10 +340,9 @@ class Bundle {
}
return {
modules: this._modules,
assets: this._assets,
...super.toJSON(),
sourceMapUrl: this._sourceMapUrl,
mainModuleId: this._mainModuleId,
mainModuleId: super.getMainModuleId(),
numPrependedModules: this._numPrependedModules,
numRequireCalls: this._numRequireCalls,
};
@ -380,18 +350,12 @@ class Bundle {
static fromJSON(json) {
const bundle = new Bundle(json.sourceMapUrl);
bundle._mainModuleId = json.mainModuleId;
bundle._assets = json.assets;
bundle._modules = json.modules;
bundle._sourceMapUrl = json.sourceMapUrl;
bundle._numPrependedModules = json.numPrependedModules;
bundle._numRequireCalls = json.numRequireCalls;
Object.freeze(bundle._modules);
Object.seal(bundle._modules);
Object.freeze(bundle._assets);
Object.seal(bundle._assets);
bundle._finalized = true;
BundleBase.fromJSON(bundle, json);
return bundle;
}

View File

@ -0,0 +1,94 @@
/**
* 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 _ = require('underscore');
const ModuleTransport = require('../lib/ModuleTransport');
class BundleBase {
constructor() {
this._finalized = false;
this._modules = [];
this._assets = [];
}
getMainModuleId() {
return this._mainModuleId;
}
setMainModuleId(moduleId) {
this._mainModuleId = moduleId;
}
addModule(module) {
if (!module instanceof ModuleTransport) {
throw new Error('Expeceted a ModuleTransport object');
}
this._modules.push(module);
}
getModules() {
return this._modules;
}
getAssets() {
return this._assets;
}
addAsset(asset) {
this._assets.push(asset);
}
finalize(options) {
Object.freeze(this._modules);
Object.seal(this._modules);
Object.freeze(this._assets);
Object.seal(this._assets);
this._finalized = true;
}
getSource(options) {
this.assertFinalized();
if (this._source) {
return this._source;
}
this._source = _.pluck(this._modules, 'code').join('\n');
return this._source;
}
assertFinalized() {
if (!this._finalized) {
throw new Error('Bundle needs to be finalized before getting any source');
}
}
toJSON() {
return {
modules: this._modules,
assets: this._assets,
};
}
static fromJSON(bundle, json) {
bundle._assets = json.assets;
bundle._modules = json.modules;
bundle._mainModuleId = json.mainModuleId;
Object.freeze(bundle._modules);
Object.seal(bundle._modules);
Object.freeze(bundle._assets);
Object.seal(bundle._assets);
bundle._finalized = true;
}
}
module.exports = BundleBase;

47
react-packager/src/Bundler/HMRBundle.js vendored Normal file
View File

@ -0,0 +1,47 @@
/**
* 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 BundleBase = require('./BundleBase');
const ModuleTransport = require('../lib/ModuleTransport');
class HMRBundle extends BundleBase {
constructor() {
super();
}
addModule(resolver, response, module, transformed) {
return resolver.resolveRequires(response,
module,
transformed.code,
).then(({name, code}) => {
code = `
__accept(
'${name}',
function(global, require, module, exports) {
${code}
}
);
`;
const moduleTransport = new ModuleTransport({
code,
name,
map: transformed.map,
sourceCode: transformed.sourceCode,
sourcePath: transformed.sourcePath,
virtual: transformed.virtual,
});
super.addModule(moduleTransport);
});
}
}
module.exports = HMRBundle;

View File

@ -10,92 +10,106 @@
jest.autoMockOff();
var SourceMapGenerator = require('source-map').SourceMapGenerator;
const Bundle = require('../Bundle');
const ModuleTransport = require('../../lib/ModuleTransport');
const Promise = require('Promise');
const SourceMapGenerator = require('source-map').SourceMapGenerator;
const UglifyJS = require('uglify-js');
var Bundle = require('../Bundle');
var ModuleTransport = require('../../lib/ModuleTransport');
var UglifyJS = require('uglify-js');
describe('Bundle', function() {
describe('Bundle', () => {
var bundle;
beforeEach(function() {
beforeEach(() => {
bundle = new Bundle('test_url');
bundle.getSourceMap = jest.genMockFn().mockImpl(function() {
bundle.getSourceMap = jest.genMockFn().mockImpl(() => {
return 'test-source-map';
});
});
describe('source bundle', function() {
it('should create a bundle and get the source', function() {
bundle.addModule(new ModuleTransport({
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
}));
bundle.addModule(new ModuleTransport({
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path',
}));
bundle.finalize({});
expect(bundle.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
'\/\/# sourceMappingURL=test_url'
].join('\n'));
});
it('should be ok to leave out the source map url', function() {
var p = new Bundle();
p.addModule(new ModuleTransport({
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
}));
p.addModule(new ModuleTransport({
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path',
}));
p.finalize({});
expect(p.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
].join('\n'));
});
it('should create a bundle and add run module code', function() {
bundle.addModule(new ModuleTransport({
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path'
}));
bundle.addModule(new ModuleTransport({
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path'
}));
bundle.setMainModuleId('foo');
bundle.finalize({
runBeforeMainModule: ['bar'],
runMainModule: true,
describe('source bundle', () => {
pit('should create a bundle and get the source', () => {
return Promise.resolve().then(() => {
return addModule({
bundle,
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle,
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path',
});
}).then(() => {
bundle.finalize({});
expect(bundle.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
'\/\/# sourceMappingURL=test_url'
].join('\n'));
});
expect(bundle.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
';require("bar");',
';require("foo");',
'\/\/# sourceMappingURL=test_url',
].join('\n'));
});
it('should get minified source', function() {
var minified = {
pit('should be ok to leave out the source map url', () => {
const otherBundle = new Bundle();
return Promise.resolve().then(() => {
return addModule({
bundle: otherBundle,
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle: otherBundle,
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path',
});
}).then(() => {
otherBundle.finalize({});
expect(otherBundle.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
].join('\n'));
});
});
pit('should create a bundle and add run module code', () => {
return Promise.resolve().then(() => {
return addModule({
bundle,
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle,
code: 'transformed bar;',
sourceCode: 'source bar',
sourcePath: 'bar path',
});
}).then(() => {
bundle.setMainModuleId('foo');
bundle.finalize({
runBeforeMainModule: ['bar'],
runMainModule: true,
});
expect(bundle.getSource({dev: true})).toBe([
'transformed foo;',
'transformed bar;',
';require("bar");',
';require("foo");',
'\/\/# sourceMappingURL=test_url',
].join('\n'));
});
});
pit('should get minified source', () => {
const minified = {
code: 'minified',
map: 'map',
};
@ -104,141 +118,156 @@ describe('Bundle', function() {
return minified;
};
bundle.addModule(new ModuleTransport({
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path'
}));
bundle.finalize();
expect(bundle.getMinifiedSourceAndMap({dev: true})).toBe(minified);
});
});
describe('sourcemap bundle', function() {
it('should create sourcemap', function() {
var p = new Bundle('test_url');
p.addModule(new ModuleTransport({
code: [
'transformed foo',
'transformed foo',
'transformed foo',
].join('\n'),
sourceCode: [
'source foo',
'source foo',
'source foo',
].join('\n'),
sourcePath: 'foo path',
}));
p.addModule(new ModuleTransport({
code: [
'transformed bar',
'transformed bar',
'transformed bar',
].join('\n'),
sourceCode: [
'source bar',
'source bar',
'source bar',
].join('\n'),
sourcePath: 'bar path',
}));
p.setMainModuleId('foo');
p.finalize({
runBeforeMainModule: [],
runMainModule: true,
});
var s = p.getSourceMap({dev: true});
expect(s).toEqual(genSourceMap(p.getModules()));
});
it('should combine sourcemaps', function() {
var p = new Bundle('test_url');
p.addModule(new ModuleTransport({
code: 'transformed foo;\n',
map: {name: 'sourcemap foo'},
sourceCode: 'source foo',
sourcePath: 'foo path'
}));
p.addModule(new ModuleTransport({
code: 'transformed foo;\n',
map: {name: 'sourcemap bar'},
sourceCode: 'source foo',
sourcePath: 'foo path'
}));
p.addModule(new ModuleTransport({
code: 'image module;\nimage module;',
virtual: true,
sourceCode: 'image module;\nimage module;',
sourcePath: 'image.png',
}));
p.setMainModuleId('foo');
p.finalize({
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
runMainModule: true,
});
var s = p.getSourceMap({dev: true});
expect(s).toEqual({
file: 'bundle.js',
version: 3,
sections: [
{ offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } },
{ offset: { line: 2, column: 0 }, map: { name: 'sourcemap bar' } },
{
offset: {
column: 0,
line: 4
},
map: {
file: 'image.png',
mappings: 'AAAA;AACA;',
names: [],
sources: [ 'image.png' ],
sourcesContent: ['image module;\nimage module;'],
version: 3,
}
},
{
offset: {
column: 0,
line: 6
},
map: {
file: 'require-InitializeJavaScriptAppEngine.js',
mappings: 'AAAA;',
names: [],
sources: [ 'require-InitializeJavaScriptAppEngine.js' ],
sourcesContent: [';require("InitializeJavaScriptAppEngine");'],
version: 3,
}
},
{
offset: {
column: 0,
line: 7
},
map: {
file: 'require-foo.js',
mappings: 'AAAA;',
names: [],
sources: [ 'require-foo.js' ],
sourcesContent: [';require("foo");'],
version: 3,
}
},
],
return Promise.resolve().then(() => {
return addModule({
bundle,
code: 'transformed foo;',
sourceCode: 'source foo',
sourcePath: 'foo path',
});
}).then(() => {
bundle.finalize();
expect(bundle.getMinifiedSourceAndMap({dev: true})).toBe(minified);
});
});
});
describe('getAssets()', function() {
it('should save and return asset objects', function() {
describe('sourcemap bundle', () => {
pit('should create sourcemap', () => {
const otherBundle = new Bundle('test_url');
return Promise.resolve().then(() => {
return addModule({
bundle: otherBundle,
code: [
'transformed foo',
'transformed foo',
'transformed foo',
].join('\n'),
sourceCode: [
'source foo',
'source foo',
'source foo',
].join('\n'),
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle: otherBundle,
code: [
'transformed bar',
'transformed bar',
'transformed bar',
].join('\n'),
sourceCode: [
'source bar',
'source bar',
'source bar',
].join('\n'),
sourcePath: 'bar path',
});
}).then(() => {
otherBundle.setMainModuleId('foo');
otherBundle.finalize({
runBeforeMainModule: [],
runMainModule: true,
});
const sourceMap = otherBundle.getSourceMap({dev: true});
expect(sourceMap).toEqual(genSourceMap(otherBundle.getModules()));
});
});
pit('should combine sourcemaps', () => {
const otherBundle = new Bundle('test_url');
return Promise.resolve().then(() => {
return addModule({
bundle: otherBundle,
code: 'transformed foo;\n',
sourceCode: 'source foo',
map: {name: 'sourcemap foo'},
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle: otherBundle,
code: 'transformed bar;\n',
sourceCode: 'source bar',
map: {name: 'sourcemap bar'},
sourcePath: 'bar path',
});
}).then(() => {
return addModule({
bundle: otherBundle,
code: 'image module;\nimage module;',
virtual: true,
sourceCode: 'image module;\nimage module;',
sourcePath: 'image.png',
});
}).then(() => {
otherBundle.setMainModuleId('foo');
otherBundle.finalize({
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
runMainModule: true,
});
const sourceMap = otherBundle.getSourceMap({dev: true});
expect(sourceMap).toEqual({
file: 'bundle.js',
version: 3,
sections: [
{ offset: { line: 0, column: 0 }, map: { name: 'sourcemap foo' } },
{ offset: { line: 2, column: 0 }, map: { name: 'sourcemap bar' } },
{
offset: {
column: 0,
line: 4
},
map: {
file: 'image.png',
mappings: 'AAAA;AACA;',
names: [],
sources: [ 'image.png' ],
sourcesContent: ['image module;\nimage module;'],
version: 3,
}
},
{
offset: {
column: 0,
line: 6
},
map: {
file: 'require-InitializeJavaScriptAppEngine.js',
mappings: 'AAAA;',
names: [],
sources: [ 'require-InitializeJavaScriptAppEngine.js' ],
sourcesContent: [';require("InitializeJavaScriptAppEngine");'],
version: 3,
}
},
{
offset: {
column: 0,
line: 7
},
map: {
file: 'require-foo.js',
mappings: 'AAAA;',
names: [],
sources: [ 'require-foo.js' ],
sourcesContent: [';require("foo");'],
version: 3,
}
},
],
});
});
});
});
describe('getAssets()', () => {
it('should save and return asset objects', () => {
var p = new Bundle('test_url');
var asset1 = {};
var asset2 = {};
@ -249,22 +278,27 @@ describe('Bundle', function() {
});
});
describe('getJSModulePaths()', function() {
it('should return module paths', function() {
var p = new Bundle('test_url');
p.addModule(new ModuleTransport({
code: 'transformed foo;\n',
sourceCode: 'source foo',
sourcePath: 'foo path'
}));
p.addModule(new ModuleTransport({
code: 'image module;\nimage module;',
virtual: true,
sourceCode: 'image module;\nimage module;',
sourcePath: 'image.png',
}));
expect(p.getJSModulePaths()).toEqual(['foo path']);
describe('getJSModulePaths()', () => {
pit('should return module paths', () => {
var otherBundle = new Bundle('test_url');
return Promise.resolve().then(() => {
return addModule({
bundle: otherBundle,
code: 'transformed foo;\n',
sourceCode: 'source foo',
sourcePath: 'foo path',
});
}).then(() => {
return addModule({
bundle: otherBundle,
code: 'image module;\nimage module;',
virtual: true,
sourceCode: 'image module;\nimage module;',
sourcePath: 'image.png',
});
}).then(() => {
expect(otherBundle.getJSModulePaths()).toEqual(['foo path']);
});
});
});
});
@ -302,3 +336,20 @@ function genSourceMap(modules) {
}
return sourceMapGen.toJSON();
}
function resolverFor(code) {
return {
wrapModule: (response, module, sourceCode) => Promise.resolve(
{name: 'name', code}
),
};
}
function addModule({bundle, code, sourceCode, sourcePath, map, virtual}) {
return bundle.addModule(
resolverFor(code),
null,
null,
{sourceCode, sourcePath, map, virtual}
);
}

View File

@ -161,46 +161,29 @@ describe('Bundler', function() {
runBeforeMainModule: [],
runModule: true,
sourceMapUrl: 'source_map_url',
}).then(function(p) {
expect(p.addModule.mock.calls[0][0]).toEqual({
name: 'foo',
code: 'lol transformed /root/foo.js lol',
map: 'sourcemap /root/foo.js',
sourceCode: 'source /root/foo.js',
sourcePath: '/root/foo.js',
});
}).then(bundle => {
const ithAddedModule = (i) => bundle.addModule.mock.calls[i][2].path;
expect(p.addModule.mock.calls[1][0]).toEqual({
name: 'bar',
code: 'lol transformed /root/bar.js lol',
map: 'sourcemap /root/bar.js',
sourceCode: 'source /root/bar.js',
sourcePath: '/root/bar.js'
});
expect(ithAddedModule(0)).toEqual('/root/foo.js');
expect(ithAddedModule(1)).toEqual('/root/bar.js');
expect(ithAddedModule(2)).toEqual('/root/img/img.png');
expect(ithAddedModule(3)).toEqual('/root/img/new_image.png');
expect(ithAddedModule(4)).toEqual('/root/file.json');
var imgModule_DEPRECATED = {
expect(bundle.finalize.mock.calls[0]).toEqual([
{runMainModule: true, runBeforeMainModule: []}
]);
expect(bundle.addAsset.mock.calls).toContain([{
__packager_asset: true,
path: '/root/img/img.png',
uri: 'img',
width: 25,
height: 50,
deprecated: true,
};
}]);
expect(p.addModule.mock.calls[2][0]).toEqual({
name: 'image!img',
code: 'lol module.exports = ' +
JSON.stringify(imgModule_DEPRECATED) +
'; lol',
sourceCode: 'module.exports = ' +
JSON.stringify(imgModule_DEPRECATED) +
';',
sourcePath: '/root/img/img.png',
virtual: true,
map: undefined,
});
var imgModule = {
expect(bundle.addAsset.mock.calls).toContain([{
__packager_asset: true,
fileSystemLocation: '/root/img',
httpServerLocation: '/assets/img',
@ -215,41 +198,7 @@ describe('Bundler', function() {
hash: 'i am a hash',
name: 'img',
type: 'png',
};
expect(p.addModule.mock.calls[3][0]).toEqual({
name: 'new_image.png',
code: 'lol module.exports = require("AssetRegistry").registerAsset(' +
JSON.stringify(imgModule) +
'); lol',
sourceCode: 'module.exports = require("AssetRegistry").registerAsset(' +
JSON.stringify(imgModule) +
');',
sourcePath: '/root/img/new_image.png',
virtual: true,
map: undefined,
});
expect(p.addModule.mock.calls[4][0]).toEqual({
name: 'package/file.json',
code: 'lol module.exports = {"json":true}; lol',
sourceCode: 'module.exports = {"json":true};',
sourcePath: '/root/file.json',
map: undefined,
virtual: true,
});
expect(p.finalize.mock.calls[0]).toEqual([
{runMainModule: true, runBeforeMainModule: []}
]);
expect(p.addAsset.mock.calls).toContain([
imgModule_DEPRECATED
]);
expect(p.addAsset.mock.calls).toContain([
imgModule
]);
}]);
// TODO(amasad) This fails with 0 != 5 in OSS
//expect(ProgressBar.prototype.tick.mock.calls.length).toEqual(modules.length);

View File

@ -18,6 +18,7 @@ const Cache = require('../DependencyResolver/Cache');
const Transformer = require('../JSTransformer');
const Resolver = require('../Resolver');
const Bundle = require('./Bundle');
const HMRBundle = require('./HMRBundle');
const PrepackBundle = require('./PrepackBundle');
const Activity = require('../Activity');
const ModuleTransport = require('../lib/ModuleTransport');
@ -155,31 +156,54 @@ class Bundler {
return this._bundlesLayout.generateLayout(main, isDev);
}
bundle({
bundle(options) {
return this._bundle({
bundle: new Bundle(options.sourceMapUrl),
includeSystemDependencies: true,
...options,
});
}
bundleForHMR(options) {
return this._bundle({
bundle: new HMRBundle(),
hot: true,
...options,
});
}
_bundle({
bundle,
modules,
entryFile,
runModule: runMainModule,
runBeforeMainModule,
sourceMapUrl,
dev: isDev,
includeSystemDependencies,
platform,
unbundle: isUnbundle,
hot: hot,
}) {
// Const cannot have the same name as the method (babel/babel#2834)
const bbundle = new Bundle(sourceMapUrl);
const findEventId = Activity.startEvent('find dependencies');
let transformEventId;
const moduleSystem = this._resolver.getModuleSystemDependencies(
{ dev: isDev, platform, isUnbundle }
);
return this.getDependencies(entryFile, isDev, platform).then((response) => {
Activity.endEvent(findEventId);
bundle.setMainModuleId(response.mainModuleId);
transformEventId = Activity.startEvent('transform');
// Prepend the module system polyfill to the top of dependencies
var dependencies = moduleSystem.concat(response.dependencies);
const moduleSystemDeps = includeSystemDependencies
? this._resolver.getModuleSystemDependencies(
{ dev: isDev, platform, isUnbundle }
)
: [];
const modulesToProcess = modules || response.dependencies;
const dependencies = moduleSystemDeps.concat(modulesToProcess);
bundle.setNumPrependedModules && bundle.setNumPrependedModules(
response.numPrependedDependencies + moduleSystemDeps.length
);
let bar;
if (process.stdout.isTTY) {
@ -191,34 +215,41 @@ class Bundler {
});
}
bbundle.setMainModuleId(response.mainModuleId);
bbundle.setNumPrependedModules(
response.numPrependedDependencies + moduleSystem.length);
return Promise.all(
dependencies.map(
module => this._transformModule(
bbundle,
module => {
return this._transformModule(
bundle,
response,
module,
platform,
hot,
).then(transformed => {
if (bar) {
bar.tick();
}
return {
module,
transformed,
};
});
}
)
).then(transformedModules => Promise.all(
transformedModules.map(({module, transformed}) => {
return bundle.addModule(
this._resolver,
response,
module,
platform,
hot,
).then(transformed => {
if (bar) {
bar.tick();
}
return this._wrapTransformedModule(response, module, transformed);
})
)
);
}).then((transformedModules) => {
transformed,
);
})
));
}).then(() => {
Activity.endEvent(transformEventId);
transformedModules.forEach(function(moduleTransport) {
bbundle.addModule(moduleTransport);
});
bbundle.finalize({runBeforeMainModule, runMainModule});
return bbundle;
bundle.finalize({runBeforeMainModule, runMainModule});
return bundle;
});
}
@ -284,35 +315,6 @@ class Bundler {
});
}
bundleForHMR({entryFile, platform, modules}) {
return this.getDependencies(entryFile, /*isDev*/true, platform)
.then(response => {
return Promise.all(
modules.map(module => {
return Promise.all([
module.getName(),
this._transformModuleForHMR(module, platform),
]).then(([moduleName, transformed]) => {
return this._resolver.resolveRequires(response,
module,
transformed.code,
).then(({name, code}) => {
return (`
__accept(
'${moduleName}',
function(global, require, module, exports) {
${code}
}
);
`);
});
});
})
);
})
.then(modules => modules.join('\n'));
}
_transformModuleForHMR(module, platform) {
if (module.isAsset()) {
return this._generateAssetObjAndCode(module, platform).then(
@ -401,23 +403,6 @@ class Bundler {
}
}
_wrapTransformedModule(response, module, transformed) {
return this._resolver.wrapModule(
response,
module,
transformed.code
).then(
({code, name}) => new ModuleTransport({
code,
name,
map: transformed.map,
sourceCode: transformed.sourceCode,
sourcePath: transformed.sourcePath,
virtual: transformed.virtual,
})
);
}
getGraphDebugInfo() {
return this._resolver.getDebugInfo();
}