mirror of https://github.com/status-im/metro.git
Add unbundling to packager
Reviewed By: tadeuzagallo Differential Revision: D2707409 fb-gh-sync-id: 30216c36066dae68d83622dba2d598e9dc0a29db
This commit is contained in:
parent
df687d8442
commit
b428bebf56
|
@ -16,6 +16,14 @@ const Activity = require('../Activity');
|
|||
|
||||
const SOURCEMAPPING_URL = '\n\/\/@ sourceMappingURL=';
|
||||
|
||||
const minifyCode = code =>
|
||||
UglifyJS.minify(code, {fromString: true, ascii_only: true}).code;
|
||||
const getCode = x => x.code;
|
||||
const getMinifiedCode = x => minifyCode(x.code);
|
||||
const getNameAndCode = ({name, code}) => ({name, code});
|
||||
const getNameAndMinifiedCode =
|
||||
({name, code}) => ({name, code: minifyCode(code)});
|
||||
|
||||
class Bundle {
|
||||
constructor(sourceMapUrl) {
|
||||
this._finalized = false;
|
||||
|
@ -24,6 +32,8 @@ class Bundle {
|
|||
this._sourceMap = false;
|
||||
this._sourceMapUrl = sourceMapUrl;
|
||||
this._shouldCombineSourceMaps = false;
|
||||
this._numPrependedModules = 0;
|
||||
this._numRequireCalls = 0;
|
||||
}
|
||||
|
||||
setMainModuleId(moduleId) {
|
||||
|
@ -48,6 +58,10 @@ class Bundle {
|
|||
return this._modules;
|
||||
}
|
||||
|
||||
setNumPrependedModules(n) {
|
||||
this._numPrependedModules = n;
|
||||
}
|
||||
|
||||
addAsset(asset) {
|
||||
this._assets.push(asset);
|
||||
}
|
||||
|
@ -76,6 +90,7 @@ class Bundle {
|
|||
sourceCode: code,
|
||||
sourcePath: name + '.js',
|
||||
}));
|
||||
this._numRequireCalls += 1;
|
||||
}
|
||||
|
||||
_assertFinalized() {
|
||||
|
@ -141,6 +156,26 @@ class Bundle {
|
|||
return source;
|
||||
}
|
||||
|
||||
getUnbundle({minify}) {
|
||||
const allModules = this._modules.slice();
|
||||
const prependedModules = this._numPrependedModules;
|
||||
const requireCalls = this._numRequireCalls;
|
||||
|
||||
const modules =
|
||||
allModules
|
||||
.splice(prependedModules, allModules.length - requireCalls - prependedModules);
|
||||
const startupCode =
|
||||
allModules
|
||||
.map(minify ? getMinifiedCode : getCode)
|
||||
.join('\n');
|
||||
|
||||
return {
|
||||
startupCode,
|
||||
modules:
|
||||
modules.map(minify ? getNameAndMinifiedCode : getNameAndCode)
|
||||
};
|
||||
}
|
||||
|
||||
getMinifiedSourceAndMap(dev) {
|
||||
this._assertFinalized();
|
||||
|
||||
|
@ -336,6 +371,8 @@ class Bundle {
|
|||
assets: this._assets,
|
||||
sourceMapUrl: this._sourceMapUrl,
|
||||
mainModuleId: this._mainModuleId,
|
||||
numPrependedModules: this._numPrependedModules,
|
||||
numRequireCalls: this._numRequireCalls,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -345,6 +382,8 @@ class Bundle {
|
|||
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);
|
||||
|
|
|
@ -130,7 +130,10 @@ describe('Bundler', function() {
|
|||
});
|
||||
|
||||
wrapModule.mockImpl(function(response, module, code) {
|
||||
return Promise.resolve('lol ' + code + ' lol');
|
||||
return module.getName().then(name => ({
|
||||
name,
|
||||
code: 'lol ' + code + ' lol'
|
||||
}));
|
||||
});
|
||||
|
||||
sizeOf.mockImpl(function(path, cb) {
|
||||
|
@ -160,6 +163,7 @@ describe('Bundler', function() {
|
|||
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',
|
||||
|
@ -167,6 +171,7 @@ describe('Bundler', function() {
|
|||
});
|
||||
|
||||
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',
|
||||
|
@ -183,6 +188,7 @@ describe('Bundler', function() {
|
|||
};
|
||||
|
||||
expect(p.addModule.mock.calls[2][0]).toEqual({
|
||||
name: 'image!img',
|
||||
code: 'lol module.exports = ' +
|
||||
JSON.stringify(imgModule_DEPRECATED) +
|
||||
'; lol',
|
||||
|
@ -212,6 +218,7 @@ describe('Bundler', function() {
|
|||
};
|
||||
|
||||
expect(p.addModule.mock.calls[3][0]).toEqual({
|
||||
name: 'new_image.png',
|
||||
code: 'lol module.exports = require("AssetRegistry").registerAsset(' +
|
||||
JSON.stringify(imgModule) +
|
||||
'); lol',
|
||||
|
@ -224,6 +231,7 @@ describe('Bundler', function() {
|
|||
});
|
||||
|
||||
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',
|
||||
|
|
|
@ -140,6 +140,7 @@ class Bundler {
|
|||
sourceMapUrl,
|
||||
dev: isDev,
|
||||
platform,
|
||||
unbundle: isUnbundle,
|
||||
}) {
|
||||
// Const cannot have the same name as the method (babel/babel#2834)
|
||||
const bbundle = new Bundle(sourceMapUrl);
|
||||
|
@ -147,7 +148,7 @@ class Bundler {
|
|||
let transformEventId;
|
||||
|
||||
const moduleSystem = this._resolver.getModuleSystemDependencies(
|
||||
{ dev: isDev, platform }
|
||||
{ dev: isDev, platform, isUnbundle }
|
||||
);
|
||||
|
||||
return this.getDependencies(entryFile, isDev, platform).then((response) => {
|
||||
|
@ -168,6 +169,8 @@ class Bundler {
|
|||
}
|
||||
|
||||
bbundle.setMainModuleId(response.mainModuleId);
|
||||
bbundle.setNumPrependedModules(
|
||||
response.numPrependedDependencies + moduleSystem.length);
|
||||
return Promise.all(
|
||||
dependencies.map(
|
||||
module => this._transformModule(
|
||||
|
@ -317,8 +320,9 @@ class Bundler {
|
|||
module,
|
||||
transformed.code
|
||||
).then(
|
||||
code => new ModuleTransport({
|
||||
code: code,
|
||||
({code, name}) => new ModuleTransport({
|
||||
code,
|
||||
name,
|
||||
map: transformed.map,
|
||||
sourceCode: transformed.sourceCode,
|
||||
sourcePath: transformed.sourcePath,
|
||||
|
|
|
@ -14,6 +14,7 @@ class ResolutionResponse {
|
|||
this.asyncDependencies = [];
|
||||
this.mainModuleId = null;
|
||||
this.mocks = null;
|
||||
this.numPrependedDependencies = 0;
|
||||
this._mappings = Object.create(null);
|
||||
this._finalized = false;
|
||||
}
|
||||
|
@ -50,6 +51,7 @@ class ResolutionResponse {
|
|||
prependDependency(module) {
|
||||
this._assertNotFinalized();
|
||||
this.dependencies.unshift(module);
|
||||
this.numPrependedDependencies += 1;
|
||||
}
|
||||
|
||||
pushAsyncDependency(dependency) {
|
||||
|
|
|
@ -627,7 +627,8 @@ describe('Resolver', function() {
|
|||
createModule('test module', ['x', 'y']),
|
||||
code
|
||||
).then(processedCode => {
|
||||
expect(processedCode).toEqual([
|
||||
expect(processedCode.name).toEqual('test module');
|
||||
expect(processedCode.code).toEqual([
|
||||
'__d(\'test module\',function(global, require,' +
|
||||
' module, exports) { ' +
|
||||
// single line import
|
||||
|
|
|
@ -60,6 +60,10 @@ const getDependenciesValidateOpts = declareOpts({
|
|||
type: 'string',
|
||||
required: false,
|
||||
},
|
||||
isUnbundle: {
|
||||
type: 'boolean',
|
||||
default: false
|
||||
},
|
||||
});
|
||||
|
||||
class Resolver {
|
||||
|
@ -115,7 +119,9 @@ class Resolver {
|
|||
? path.join(__dirname, 'polyfills/prelude_dev.js')
|
||||
: path.join(__dirname, 'polyfills/prelude.js');
|
||||
|
||||
const moduleSystem = path.join(__dirname, 'polyfills/require.js');
|
||||
const moduleSystem = opts.isUnbundle
|
||||
? path.join(__dirname, 'polyfills/require-unbundle.js')
|
||||
: path.join(__dirname, 'polyfills/require.js');
|
||||
|
||||
return [
|
||||
prelude,
|
||||
|
@ -152,7 +158,7 @@ class Resolver {
|
|||
wrapModule(resolutionResponse, module, code) {
|
||||
return Promise.resolve().then(() => {
|
||||
if (module.isPolyfill()) {
|
||||
return Promise.resolve(code);
|
||||
return Promise.resolve({code});
|
||||
}
|
||||
|
||||
const resolvedDeps = Object.create(null);
|
||||
|
@ -179,14 +185,13 @@ class Resolver {
|
|||
}
|
||||
};
|
||||
|
||||
return module.getName().then(
|
||||
name => defineModuleCode({
|
||||
code: code.replace(replacePatterns.IMPORT_RE, relativizeCode)
|
||||
.replace(replacePatterns.EXPORT_RE, relativizeCode)
|
||||
.replace(replacePatterns.REQUIRE_RE, relativizeCode),
|
||||
moduleName: name,
|
||||
})
|
||||
);
|
||||
code = code
|
||||
.replace(replacePatterns.IMPORT_RE, relativizeCode)
|
||||
.replace(replacePatterns.EXPORT_RE, relativizeCode)
|
||||
.replace(replacePatterns.REQUIRE_RE, relativizeCode);
|
||||
|
||||
return module.getName().then(name =>
|
||||
({name, code: defineModuleCode(name, code)}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -197,7 +202,7 @@ class Resolver {
|
|||
|
||||
}
|
||||
|
||||
function defineModuleCode({moduleName, code}) {
|
||||
function defineModuleCode(moduleName, code) {
|
||||
return [
|
||||
`__d(`,
|
||||
`'${moduleName}',`,
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
'use strict';
|
||||
|
||||
((global) => {
|
||||
const {ErrorUtils, __nativeRequire} = global;
|
||||
global.require = require;
|
||||
global.__d = define;
|
||||
|
||||
const modules = Object.create(null);
|
||||
|
||||
const loadModule = ErrorUtils ?
|
||||
guardedLoadModule : loadModuleImplementation;
|
||||
|
||||
function define(moduleId, factory) {
|
||||
modules[moduleId] = {
|
||||
factory,
|
||||
hasError: false,
|
||||
exports: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function require(moduleId) {
|
||||
const module = modules[moduleId];
|
||||
return module && module.exports || loadModule(moduleId, module);
|
||||
}
|
||||
|
||||
function guardedLoadModule(moduleId, module) {
|
||||
try {
|
||||
return loadModuleImplementation(moduleId, module);
|
||||
} catch (e) {
|
||||
ErrorUtils.reportFatalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
function loadModuleImplementation(moduleId, module) {
|
||||
if (!module) {
|
||||
__nativeRequire(moduleId);
|
||||
module = modules[moduleId];
|
||||
}
|
||||
|
||||
if (!module) {
|
||||
throw unknownModuleError(moduleId);
|
||||
}
|
||||
|
||||
if (module.hasError) {
|
||||
throw moduleThrewError(moduleId);
|
||||
}
|
||||
|
||||
const exports = module.exports = {};
|
||||
const {factory} = module;
|
||||
try {
|
||||
const moduleObject = {exports};
|
||||
factory(global, require, moduleObject, exports);
|
||||
return (module.exports = moduleObject.exports);
|
||||
} catch(e) {
|
||||
module.hasError = true;
|
||||
module.exports = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function unknownModuleError(id) {
|
||||
let message = 'Requiring unknown module "' + id + '".';
|
||||
if (__DEV__) {
|
||||
message +=
|
||||
'If you are sure the module is there, try restarting the packager.';
|
||||
}
|
||||
return Error(message);
|
||||
}
|
||||
|
||||
function moduleThrewError(id) {
|
||||
return Error('Requiring module "' + id + '", which threw an exception.');
|
||||
}
|
||||
|
||||
})(this);
|
|
@ -115,6 +115,7 @@ describe('processRequest', () => {
|
|||
dev: true,
|
||||
platform: undefined,
|
||||
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
|
||||
unbundle: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -134,6 +135,7 @@ describe('processRequest', () => {
|
|||
dev: true,
|
||||
platform: 'ios',
|
||||
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
|
||||
unbundle: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -274,6 +276,7 @@ describe('processRequest', () => {
|
|||
dev: true,
|
||||
platform: undefined,
|
||||
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
|
||||
unbundle: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -292,6 +295,7 @@ describe('processRequest', () => {
|
|||
dev: false,
|
||||
platform: undefined,
|
||||
runBeforeMainModule: ['InitializeJavaScriptAppEngine'],
|
||||
unbundle: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
|
|
@ -102,6 +102,10 @@ const bundleOpts = declareOpts({
|
|||
'InitializeJavaScriptAppEngine'
|
||||
],
|
||||
},
|
||||
unbundle: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
|
||||
const dependencyOpts = declareOpts({
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
'use strict';
|
||||
|
||||
function ModuleTransport(data) {
|
||||
this.name = data.name;
|
||||
|
||||
assertExists(data, 'code');
|
||||
this.code = data.code;
|
||||
|
||||
|
|
Loading…
Reference in New Issue