Use continuous module IDs for random access bundles

Reviewed By: bestander

Differential Revision: D3292980

fbshipit-source-id: ab5791d31add42a26cf55a0309564330c383eaa2
This commit is contained in:
David Aurelio 2016-05-12 17:13:12 -07:00 committed by Facebook Github Bot 5
parent 3f1cd5aa4e
commit b4e970f6c3
8 changed files with 93 additions and 63 deletions

View File

@ -12,7 +12,11 @@ const asIndexedFile = require('./as-indexed-file');
const asAssets = require('./as-assets');
function buildBundle(packagerClient, requestOptions) {
return packagerClient.buildBundle({...requestOptions, unbundle: true});
return packagerClient.buildBundle({
...requestOptions,
unbundle: true,
isolateModuleIDs: true,
});
}
function saveUnbundle(bundle, options, log) {

View File

@ -1,5 +1,5 @@
{
"version": "0.3.1",
"version": "0.3.2",
"name": "react-native-packager",
"description": "Build native apps with React!",
"repository": {

View File

@ -128,6 +128,7 @@ describe('Bundler', function() {
mainModuleId: 'foo',
dependencies: modules,
transformOptions,
getModuleId: () => 123,
})
);
@ -207,7 +208,8 @@ describe('Bundler', function() {
pit('gets the list of dependencies from the resolver', function() {
const entryFile = '/root/foo.js';
return bundler.getDependencies({entryFile, recursive: true}).then(() =>
expect(getDependencies).toBeCalledWith(
// jest calledWith does not support jasmine.any
expect(getDependencies.mock.calls[0].slice(0, -2)).toEqual([
'/root/foo.js',
{ dev: true, recursive: true },
{ minify: false,
@ -219,8 +221,7 @@ describe('Bundler', function() {
projectRoots,
}
},
undefined,
)
])
);
});

View File

@ -141,7 +141,6 @@ class Bundler {
fileWatcher: opts.fileWatcher,
assetExts: opts.assetExts,
cache: this._cache,
getModuleId: this._getModuleId,
transformCode:
(module, code, options) =>
this._transformer.transformFile(module.path, code, options),
@ -169,9 +168,9 @@ class Bundler {
const moduleSystemDeps =
this._resolver.getModuleSystemDependencies({dev, unbundle});
return this._bundle({
...options,
bundle: new Bundle({dev, minify, sourceMapUrl: options.sourceMapUrl}),
moduleSystemDeps,
...options,
});
}
@ -247,9 +246,10 @@ class Bundler {
unbundle,
entryModuleOnly,
resolutionResponse,
isolateModuleIDs,
}) {
const onResolutionResponse = response => {
bundle.setMainModuleId(this._getModuleId(getMainModule(response)));
bundle.setMainModuleId(response.getModuleId(getMainModule(response)));
if (bundle.setNumPrependedModules) {
bundle.setNumPrependedModules(
response.numPrependedDependencies + moduleSystemDeps.length
@ -273,7 +273,7 @@ class Bundler {
? runBeforeMainModule
.map(name => modulesByName[name])
.filter(Boolean)
.map(this._getModuleId, this)
.map(response.getModuleId)
: undefined;
bundle.finalize({
@ -294,6 +294,7 @@ class Bundler {
resolutionResponse,
onResolutionResponse,
finalizeBundle,
isolateModuleIDs,
});
}
@ -344,6 +345,7 @@ class Bundler {
hot,
unbundle,
resolutionResponse,
isolateModuleIDs,
onResolutionResponse = noop,
onModuleTransformed = noop,
finalizeBundle = noop,
@ -371,6 +373,7 @@ class Bundler {
hot,
onProgress,
minify,
isolateModuleIDs,
generateSourceMaps: unbundle,
});
}
@ -398,6 +401,7 @@ class Bundler {
bundle,
entryFilePath,
transformOptions: response.transformOptions,
getModuleId: response.getModuleId,
}).then(transformed => {
modulesByName[transformed.name] = module;
onModuleTransformed({
@ -467,6 +471,7 @@ class Bundler {
hot = false,
recursive = true,
generateSourceMaps = false,
isolateModuleIDs = false,
onProgress,
}) {
return this.getTransformOptions(
@ -491,6 +496,7 @@ class Bundler {
{dev, platform, recursive},
transformOptions,
onProgress,
isolateModuleIDs ? createModuleIdFactory() : this._getModuleId,
);
});
}
@ -527,13 +533,14 @@ class Bundler {
);
}
_toModuleTransport({module, bundle, entryFilePath, transformOptions}) {
_toModuleTransport({module, bundle, entryFilePath, transformOptions, getModuleId}) {
let moduleTransport;
if (module.isAsset_DEPRECATED()) {
moduleTransport = this._generateAssetModule_DEPRECATED(bundle, module);
moduleTransport =
this._generateAssetModule_DEPRECATED(bundle, module, getModuleId);
} else if (module.isAsset()) {
moduleTransport = this._generateAssetModule(
bundle, module, transformOptions.platform);
bundle, module, getModuleId, transformOptions.platform);
}
if (moduleTransport) {
@ -554,7 +561,7 @@ class Bundler {
return new ModuleTransport({
name,
id: this._getModuleId(module),
id: getModuleId(module),
code,
map,
meta: {dependencies, dependencyOffsets, preloaded},
@ -568,7 +575,7 @@ class Bundler {
return this._resolver.getDebugInfo();
}
_generateAssetModule_DEPRECATED(bundle, module) {
_generateAssetModule_DEPRECATED(bundle, module, getModuleId) {
return Promise.all([
sizeOf(module.path),
module.getName(),
@ -588,7 +595,7 @@ class Bundler {
return new ModuleTransport({
name: id,
id: this._getModuleId(module),
id: getModuleId(module),
code: code,
sourceCode: code,
sourcePath: module.path,
@ -647,7 +654,7 @@ class Bundler {
}
_generateAssetModule(bundle, module, platform = null) {
_generateAssetModule(bundle, module, getModuleId, platform = null) {
return Promise.all([
module.getName(),
this._generateAssetObjAndCode(module, platform),
@ -655,7 +662,7 @@ class Bundler {
bundle.addAsset(asset);
return new ModuleTransport({
name,
id: this._getModuleId(module),
id: getModuleId(module),
code,
meta: meta,
sourceCode: code,

View File

@ -50,6 +50,7 @@ describe('Resolver', function() {
constructor({dependencies, mainModuleId}) {
this.dependencies = dependencies;
this.mainModuleId = mainModuleId;
this.getModuleId = createGetModuleId();
}
prependDependency(dependency) {
@ -95,7 +96,7 @@ describe('Resolver', function() {
DependencyGraph.prototype.getDependencies.mockImplementation(
() => Promise.reject());
new Resolver({projectRoot: '/root', })
new Resolver({projectRoot: '/root'})
.getDependencies(entry, {platform}, transformOptions);
expect(DependencyGraph.prototype.getDependencies).toBeCalledWith({
entryPath: entry,
@ -110,7 +111,6 @@ describe('Resolver', function() {
var deps = [module];
var depResolver = new Resolver({
getModuleId: createGetModuleId(),
projectRoot: '/root',
});
@ -121,8 +121,14 @@ describe('Resolver', function() {
}));
});
return depResolver.getDependencies('/root/index.js', { dev: false })
.then(function(result) {
return depResolver
.getDependencies(
'/root/index.js',
{ dev: false },
undefined,
undefined,
createGetModuleId()
).then(function(result) {
expect(result.mainModuleId).toEqual('index');
expect(result.dependencies[result.dependencies.length - 1]).toBe(module);
expect(DependencyGraph.prototype.createPolyfill.mock.calls.map((call) => call[0])).toEqual([
@ -227,8 +233,14 @@ describe('Resolver', function() {
const polyfill = {};
DependencyGraph.prototype.createPolyfill.mockReturnValueOnce(polyfill);
return depResolver.getDependencies('/root/index.js', { dev: true })
.then(function(result) {
return depResolver
.getDependencies(
'/root/index.js',
{ dev: true },
undefined,
undefined,
createGetModuleId()
).then(function(result) {
expect(result.mainModuleId).toEqual('index');
expect(DependencyGraph.mock.instances[0].getDependencies)
.toBeCalledWith({entryPath: '/root/index.js', recursive: true});
@ -254,8 +266,14 @@ describe('Resolver', function() {
}));
});
return depResolver.getDependencies('/root/index.js', { dev: false })
.then((result) => {
return depResolver
.getDependencies(
'/root/index.js',
{ dev: false },
undefined,
undefined,
createGetModuleId()
).then((result) => {
expect(result.mainModuleId).toEqual('index');
expect(DependencyGraph.prototype.createPolyfill.mock.calls[result.dependencies.length - 2]).toEqual([
{ file: 'some module',
@ -278,12 +296,10 @@ describe('Resolver', function() {
});
describe('wrapModule', function() {
let depResolver, getModuleId;
let depResolver;
beforeEach(() => {
getModuleId = createGetModuleId();
depResolver = new Resolver({
depResolver,
getModuleId,
projectRoot: '/root',
});
});
@ -325,7 +341,8 @@ describe('Resolver', function() {
const moduleIds = new Map(
resolutionResponse
.getResolvedDependencyPairs()
.map(([importId, module]) => [importId, getModuleId(module)])
.map(([importId, module]) =>
[importId, resolutionResponse.getModuleId(module)])
);
return depResolver.wrapModule({
@ -337,7 +354,7 @@ describe('Resolver', function() {
dev: false,
}).then(({code: processedCode}) => {
expect(processedCode).toEqual([
`__d(${getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
`__d(${resolutionResponse.getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
// require
`require(${moduleIds.get('x')} /* x */)`,
`require(${moduleIds.get('y')} /* y */)`,
@ -364,7 +381,7 @@ describe('Resolver', function() {
dev: true,
}).then(({code: processedCode}) =>
expect(processedCode).toEqual([
`__d(${getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
`__d(${resolutionResponse.getModuleId(module)} /* test module */, function(global, require, module, exports) {` +
code,
'}, "test module");'
].join('\n'))
@ -413,7 +430,7 @@ describe('Resolver', function() {
let depResolver, module, resolutionResponse;
beforeEach(() => {
depResolver = new Resolver({getModuleId, projectRoot: '/root'});
depResolver = new Resolver({projectRoot: '/root'});
module = createJsonModule(id);
resolutionResponse = new ResolutionResponseMock({
dependencies: [module],
@ -426,7 +443,7 @@ describe('Resolver', function() {
.wrapModule({resolutionResponse, module, name: id, code, dev: false})
.then(({code: processedCode}) =>
expect(processedCode).toEqual([
`__d(${getModuleId(module)} /* ${id} */, function(global, require, module, exports) {`,
`__d(${resolutionResponse.getModuleId(module)} /* ${id} */, function(global, require, module, exports) {`,
`module.exports = ${code}\n});`,
].join('')));
});
@ -442,7 +459,6 @@ describe('Resolver', function() {
Promise.resolve({code, map}));
depResolver = new Resolver({
projectRoot: '/root',
getModuleId,
minifyCode,
});
module = createModule(id);
@ -455,7 +471,7 @@ describe('Resolver', function() {
});
pit('should invoke the minifier with the wrapped code', () => {
const wrappedCode = `__d(${getModuleId(module)} /* ${id} */, function(global, require, module, exports) {${code}\n});`
const wrappedCode = `__d(${resolutionResponse.getModuleId(module)} /* ${id} */, function(global, require, module, exports) {${code}\n});`
return depResolver
.wrapModule({
resolutionResponse,

View File

@ -47,10 +47,6 @@ const validateOpts = declareOpts({
type: 'object',
required: true,
},
getModuleId: {
type: 'function',
required: true,
},
transformCode: {
type: 'function',
},
@ -115,7 +111,6 @@ class Resolver {
assetDependencies: ['react-native/Libraries/Image/AssetRegistry'],
});
this._getModuleId = options.getModuleId;
this._minifyCode = opts.minifyCode;
this._polyfillModuleNames = opts.polyfillModuleNames || [];
@ -137,7 +132,7 @@ class Resolver {
return this._depGraph.getModuleForPath(entryFile);
}
getDependencies(entryPath, options, transformOptions, onProgress) {
getDependencies(entryPath, options, transformOptions, onProgress, getModuleId) {
const {platform, recursive} = getDependenciesValidateOpts(options);
return this._depGraph.getDependencies({
entryPath,
@ -150,8 +145,7 @@ class Resolver {
polyfill => resolutionResponse.prependDependency(polyfill)
);
// currently used by HMR
resolutionResponse.getModuleId = this._getModuleId;
resolutionResponse.getModuleId = getModuleId;
return resolutionResponse.finalize();
});
}
@ -205,7 +199,7 @@ class Resolver {
resolutionResponse.getResolvedDependencyPairs(module)
.forEach(([depName, depModule]) => {
if (depModule) {
resolvedDeps[depName] = this._getModuleId(depModule);
resolvedDeps[depName] = resolutionResponse.getModuleId(depModule);
}
});
@ -251,7 +245,7 @@ class Resolver {
if (module.isPolyfill()) {
code = definePolyfillCode(code);
} else {
const moduleId = this._getModuleId(module);
const moduleId = resolutionResponse.getModuleId(module);
code = this.resolveRequires(
resolutionResponse,
module,

View File

@ -22,14 +22,14 @@ jest.setMock('worker-farm', function() { return () => {}; })
const Promise = require('promise');
var Bundler = require('../../Bundler');
var Server = require('../');
var AssetServer = require('../../AssetServer');
const Bundler = require('../../Bundler');
const Server = require('../');
const AssetServer = require('../../AssetServer');
var FileWatcher;
let FileWatcher;
describe('processRequest', () => {
var server;
let server;
const options = {
projectRoots: ['root'],
@ -56,8 +56,8 @@ describe('processRequest', () => {
const invalidatorFunc = jest.fn();
const watcherFunc = jest.fn();
var requestHandler;
var triggerFileChange;
let requestHandler;
let triggerFileChange;
beforeEach(() => {
FileWatcher = require('node-haste').FileWatcher;
@ -135,7 +135,7 @@ describe('processRequest', () => {
requestHandler,
'index.ios.includeRequire.bundle'
).then(response => {
expect(response.body).toEqual('this is the source');
expect(response.body).toEqual('this is the source')
expect(Bundler.prototype.bundle).toBeCalledWith({
entryFile: 'index.ios.js',
inlineSourceMap: false,
@ -148,6 +148,7 @@ describe('processRequest', () => {
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
unbundle: false,
entryModuleOnly: false,
isolateModuleIDs: false,
});
});
});
@ -170,6 +171,7 @@ describe('processRequest', () => {
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
unbundle: false,
entryModuleOnly: false,
isolateModuleIDs: false,
});
});
});
@ -291,9 +293,9 @@ describe('processRequest', () => {
});
describe('/onchange endpoint', () => {
var EventEmitter;
var req;
var res;
let EventEmitter;
let req;
let res;
beforeEach(() => {
EventEmitter = require.requireActual('events').EventEmitter;
@ -363,6 +365,7 @@ describe('processRequest', () => {
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
unbundle: false,
entryModuleOnly: false,
isolateModuleIDs: false,
})
);
});
@ -384,6 +387,7 @@ describe('processRequest', () => {
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
unbundle: false,
entryModuleOnly: false,
isolateModuleIDs: false,
})
);
});

View File

@ -131,6 +131,10 @@ const bundleOpts = declareOpts({
type: 'boolean',
default: false,
},
isolateModuleIDs: {
type: 'boolean',
default: false
}
});
const dependencyOpts = declareOpts({
@ -167,7 +171,7 @@ class Server {
const assetGlobs = opts.assetExts.map(ext => '**/*.' + ext);
var watchRootConfigs = opts.projectRoots.map(dir => {
let watchRootConfigs = opts.projectRoots.map(dir => {
return {
dir: dir,
globs: [
@ -338,7 +342,7 @@ class Server {
}
_processDebugRequest(reqUrl, res) {
var ret = '<!doctype html>';
let ret = '<!doctype html>';
const pathname = url.parse(reqUrl).pathname;
const parts = pathname.split('/').filter(Boolean);
if (parts.length === 1) {
@ -406,9 +410,9 @@ class Server {
processRequest(req, res, next) {
const urlObj = url.parse(req.url, true);
var pathname = urlObj.pathname;
const pathname = urlObj.pathname;
var requestType;
let requestType;
if (pathname.match(/\.bundle$/)) {
requestType = 'bundle';
} else if (pathname.match(/\.map$/)) {
@ -438,7 +442,7 @@ class Server {
building.then(
p => {
if (requestType === 'bundle') {
var bundleSource = p.getSource({
const bundleSource = p.getSource({
inlineSourceMap: options.inlineSourceMap,
minify: options.minify,
dev: options.dev,
@ -453,7 +457,7 @@ class Server {
}
Activity.endEvent(startReqEventId);
} else if (requestType === 'map') {
var sourceMap = p.getSourceMap({
let sourceMap = p.getSourceMap({
minify: options.minify,
dev: options.dev,
});
@ -466,7 +470,7 @@ class Server {
res.end(sourceMap);
Activity.endEvent(startReqEventId);
} else if (requestType === 'assets') {
var assetsList = JSON.stringify(p.getAssets());
const assetsList = JSON.stringify(p.getAssets());
res.setHeader('Content-Type', 'application/json');
res.end(assetsList);
Activity.endEvent(startReqEventId);