Move wrapModule logic for scripts, modules and JSON files to the transformer

Reviewed By: davidaurelio

Differential Revision: D6389116

fbshipit-source-id: fa43bd54669849c22b6b9d155ab07676b2455ef7
This commit is contained in:
Rafael Oleza 2017-11-23 15:33:45 -08:00 committed by Facebook Github Bot
parent b193fc3436
commit b08ce130fd
14 changed files with 529 additions and 704 deletions

View File

@ -213,6 +213,7 @@ class Bundler {
module.path, module.path,
module.localPath, module.localPath,
code, code,
module.isPolyfill(),
transformCodeOptions, transformCodeOptions,
), ),
transformCache: opts.transformCache, transformCache: opts.transformCache,
@ -240,14 +241,11 @@ class Bundler {
} }
async generateAssetObjAndCode( async generateAssetObjAndCode(
module: Module, path: string,
assetPlugins: Array<string>, assetPlugins: Array<string>,
platform: ?string = null, platform: ?string = null,
) { ) {
const assetData = await this._assetServer.getAssetData( const assetData = await this._assetServer.getAssetData(path, platform);
module.path,
platform,
);
const asset = await this._applyAssetPlugins(assetPlugins, assetData); const asset = await this._applyAssetPlugins(assetPlugins, assetData);
const { const {

View File

@ -14,6 +14,7 @@
const DeltaCalculator = require('./DeltaCalculator'); const DeltaCalculator = require('./DeltaCalculator');
const addParamsToDefineCall = require('../lib/addParamsToDefineCall');
const createModuleIdFactory = require('../lib/createModuleIdFactory'); const createModuleIdFactory = require('../lib/createModuleIdFactory');
const {EventEmitter} = require('events'); const {EventEmitter} = require('events');
@ -425,27 +426,37 @@ class DeltaTransformer extends EventEmitter {
): Promise<[number, ?DeltaEntry]> { ): Promise<[number, ?DeltaEntry]> {
const name = module.getName(); const name = module.getName();
const metadata = await this._getMetadata(module, transformOptions); const metadata = await this._getMetadata(module, transformOptions);
const edge = dependencyEdges.get(module.path); const edge = dependencyEdges.get(module.path);
const dependencyPairs = edge ? edge.dependencies : new Map(); const dependencyPairs = edge ? edge.dependencies : new Map();
const wrapped = this._resolver.wrapModule({ let wrappedCode;
module,
getModuleId: this._getModuleId, if (module.isAsset()) {
dependencyPairs, wrappedCode = await this._wrapAsset({
dependencyOffsets: metadata.dependencyOffsets || [], code: metadata.code,
name, dependencyPairs,
code: metadata.code, name,
map: metadata.map, path: module.path,
dev: this._bundleOptions.dev, });
}); } else if (!module.isPolyfill()) {
wrappedCode = this._addDependencyMap({
code: metadata.code,
dependencyPairs,
name,
path: module.path,
});
} else {
wrappedCode = metadata.code;
}
const {code, map} = transformOptions.minify const {code, map} = transformOptions.minify
? await this._resolver.minifyModule( ? await this._resolver.minifyModule(
module.path, module.path,
wrapped.code, wrappedCode,
wrapped.map, metadata.map,
) )
: wrapped; : {code: wrappedCode, map: metadata.map};
const id = this._getModuleId(module.path); const id = this._getModuleId(module.path);
@ -463,6 +474,70 @@ class DeltaTransformer extends EventEmitter {
]; ];
} }
/**
* Function to add the mapping object between local module ids and
* actual bundle module ids for dependencies. This way, we can do the path
* replacements on require() calls on transformers (since local ids do not
* change between bundles).
*/
_addDependencyMap({
code,
dependencyPairs,
name,
path,
}: {
code: string,
dependencyPairs: Map<string, string>,
name: string,
path: string,
}): string {
const moduleId = this._getModuleId(path);
const params = [
moduleId,
Array.from(dependencyPairs.values()).map(this._getModuleId),
];
// Add the module name as the last parameter (to make it easier to do
// requires by name when debugging).
if (this._bundleOptions.dev) {
params.push(name);
}
return addParamsToDefineCall(code, ...params);
}
/**
* Temporary function to wrap an asset. This logic will go away once we
* generate the needed JS code for assets in the transformer.
*/
async _wrapAsset({
code,
dependencyPairs,
name,
path,
}: {
code: string,
dependencyPairs: Map<string, string>,
name: string,
path: string,
}): Promise<string> {
const asset = await this._bundler.generateAssetObjAndCode(
path,
this._bundleOptions.assetPlugins,
this._bundleOptions.platform,
);
return await this._resolver.wrapModule({
path,
getModuleId: this._getModuleId,
dependencyPairs,
dependencyOffsets: asset.meta.dependencyOffsets,
name,
code: asset.code,
dev: this._bundleOptions.dev,
});
}
_getModuleType(module: Module): DeltaEntryType { _getModuleType(module: Module): DeltaEntryType {
if (module.isAsset()) { if (module.isAsset()) {
return 'asset'; return 'asset';
@ -480,25 +555,10 @@ class DeltaTransformer extends EventEmitter {
transformOptions: JSTransformerOptions, transformOptions: JSTransformerOptions,
): Promise<{ ): Promise<{
+code: string, +code: string,
+dependencyOffsets: ?Array<number>, +dependencies: Array<string>,
+map: CompactRawMappings, +map: CompactRawMappings,
+source: string, +source: string,
}> { }> {
if (module.isAsset()) {
const asset = await this._bundler.generateAssetObjAndCode(
module,
this._bundleOptions.assetPlugins,
this._bundleOptions.platform,
);
return {
code: asset.code,
dependencyOffsets: asset.meta.dependencyOffsets,
map: [],
source: '',
};
}
return await module.read(transformOptions); return await module.read(transformOptions);
} }

View File

@ -59,6 +59,7 @@ describe('Transformer', function() {
fileName, fileName,
localPath, localPath,
code, code,
false,
transformOptions, transformOptions,
); );
@ -67,6 +68,7 @@ describe('Transformer', function() {
fileName, fileName,
localPath, localPath,
code, code,
false,
transformOptions, transformOptions,
); );
}); });
@ -92,7 +94,7 @@ describe('Transformer', function() {
expect.assertions(6); expect.assertions(6);
return transformer return transformer
.transformFile(fileName, localPath, '', {}) .transformFile(fileName, localPath, '', true, {})
.catch(function(error) { .catch(function(error) {
expect(error.type).toEqual('TransformError'); expect(error.type).toEqual('TransformError');
expect(error.message).toBe( expect(error.message).toBe(

View File

@ -87,6 +87,7 @@ module.exports = class Transformer {
filename: string, filename: string,
localPath: LocalPath, localPath: LocalPath,
code: string, code: string,
isScript: boolean,
options: Options, options: Options,
): Promise<TransformedCode> { ): Promise<TransformedCode> {
try { try {
@ -97,6 +98,7 @@ module.exports = class Transformer {
filename, filename,
localPath, localPath,
code, code,
isScript,
options, options,
); );

View File

@ -13,243 +13,95 @@
jest jest
.mock('../constant-folding') .mock('../constant-folding')
.mock('../extract-dependencies')
.mock('../inline') .mock('../inline')
.mock('../minify') .mock('../minify');
.mock('babel-generator');
const {objectContaining} = jasmine; const path = require('path');
const transformCode = require('..').transformAndExtractDependencies;
describe('code transformation worker:', () => { describe('code transformation worker:', () => {
let transformCode; it('transforms a simple script', async () => {
let babelGenerator; const {result} = await transformCode(
path.join(__dirname, '../../../transformer.js'),
let extractDependencies, transformer; 'arbitrary/file.js',
beforeEach(() => { `local/file.js`,
jest.resetModules(); 'someReallyArbitrary(code)',
({transformCode} = require('..')); true,
extractDependencies = require('../extract-dependencies').mockReturnValue( {
{}, dev: true,
); transform: {},
transformer = { },
transform: jest.fn(({filename, options, src}) => ({
code: src,
map: [],
})),
};
babelGenerator = require('babel-generator');
babelGenerator.default.mockReturnValue({
code: '',
map: [],
});
});
it('calls the transform with file name, source code, and transform options', function() {
const filename = 'arbitrary/file.js';
const localPath = `local/${filename}`;
const sourceCode = 'arbitrary(code)';
const transformOptions = {arbitrary: 'options'};
transformCode(transformer, filename, localPath, sourceCode, {
dev: true,
transform: transformOptions,
});
expect(transformer.transform).toBeCalledWith({
filename,
localPath,
options: transformOptions,
plugins: [],
src: sourceCode,
});
});
it('calls the transform with two plugins when not in dev mode', () => {
const filename = 'arbitrary/file.js';
const localPath = `local/${filename}`;
const sourceCode = 'arbitrary(code)';
const options = {dev: false, transform: {arbitrary: 'options'}};
transformCode(transformer, filename, localPath, sourceCode, options);
const plugins = transformer.transform.mock.calls[0][0].plugins;
expect(plugins[0]).toEqual([expect.any(Object), options]);
expect(plugins[1]).toEqual([expect.any(Object), options]);
});
it('prefixes JSON files with an assignment to module.exports to make the code valid', function() {
const filename = 'arbitrary/file.json';
const localPath = `local/${filename}`;
const sourceCode = '{"arbitrary":"property"}';
transformCode(transformer, filename, localPath, sourceCode, {dev: true});
expect(transformer.transform).toBeCalledWith({
filename,
localPath,
options: undefined,
plugins: [],
src: `module.exports=${sourceCode}`,
});
});
it('calls back with the result of the transform in the cache', async () => {
const result = {
code: 'some.other(code)',
map: [],
};
babelGenerator.default.mockReturnValue({
code: 'some.other(code)',
map: [],
});
const data = await transformCode(
transformer,
'filename',
'local/filename',
result.code,
{},
); );
expect(data.result).toEqual(objectContaining(result)); expect(result.code).toBe(
[
'(function (global) {',
' someReallyArbitrary(code);',
'})(this);',
].join('\n'),
);
expect(result.map).toHaveLength(3);
expect(result.dependencies).toEqual([]);
}); });
it('removes the leading `module.exports` before returning if the file is a JSON file, even if minified', async () => { it('transforms a simple module', async () => {
const code = '{a:1,b:2}'; const {result} = await transformCode(
const filePath = 'arbitrary/file.json'; path.join(__dirname, '../../../transformer.js'),
'arbitrary/file.js',
babelGenerator.default.mockReturnValue({ `local/file.js`,
code: '{a:1,b:2}', 'arbitrary(code)',
map: [], false,
}); {
dev: true,
const data = await transformCode(transformer, filePath, filePath, code, {}); transform: {},
},
expect(data.result.code).toEqual(code);
});
it('removes shebang when present', async () => {
const shebang = '#!/usr/bin/env node';
const result = {
code: `${shebang} \n arbitrary(code)`,
};
const filePath = 'arbitrary/file.js';
babelGenerator.default.mockReturnValue({
code: `${shebang} \n arbitrary(code)`,
map: [],
});
const data = await transformCode(
transformer,
filePath,
filePath,
result.code,
{},
); );
const {code} = data.result; expect(result.code).toBe(
expect(code).not.toContain(shebang); [
expect(code.split('\n').length).toEqual(result.code.split('\n').length); '__d(function (global, require, module, exports, _dependencyMap) {',
' arbitrary(code);',
'});',
].join('\n'),
);
expect(result.map).toHaveLength(3);
expect(result.dependencies).toEqual([]);
}); });
it('calls back with any error yielded by the transform', async () => { it('transforms a module with dependencies', async () => {
const message = 'SyntaxError: this code is broken.'; const {result} = await transformCode(
path.join(__dirname, '../../../transformer.js'),
'arbitrary/file.js',
`local/file.js`,
[
'require("./a");',
'arbitrary(code);',
'const b = require("b");',
'import c from "./c";',
].join('\n'),
false,
{
dev: true,
transform: {},
},
);
transformer.transform.mockImplementation(() => { expect(result.code).toBe(
throw new Error(message); [
}); '__d(function (global, require, module, exports, _dependencyMap) {',
' var _c = require(_dependencyMap[0], "./c");',
expect.assertions(1); '',
' var _c2 = babelHelpers.interopRequireDefault(_c);',
try { '',
await transformCode( ' require(_dependencyMap[1], "./a");',
transformer, '',
'filename', ' arbitrary(code);',
'local/filename', '',
'code', ' var b = require(_dependencyMap[2], "b");',
{}, '});',
); ].join('\n'),
} catch (error) { );
expect(error.message).toBe(message); expect(result.map).toHaveLength(13);
} expect(result.dependencies).toEqual(['./c', './a', 'b']);
});
describe('dependency extraction', () => {
it('passes the transformed code the `extractDependencies`', async () => {
const code = 'arbitrary(code)';
babelGenerator.default.mockReturnValue({
code: 'arbitrary(code)',
map: [],
});
await transformCode(transformer, 'filename', 'local/filename', code, {});
expect(extractDependencies).toBeCalledWith(code, 'filename');
});
it('uses `dependencies` and `dependencyOffsets` provided by `extractDependencies` for the result', async () => {
const dependencyData = {
dependencies: ['arbitrary', 'list', 'of', 'dependencies'],
dependencyOffsets: [12, 119, 185, 328, 471],
};
extractDependencies.mockReturnValue(dependencyData);
const data = await transformCode(
transformer,
'filename',
'local/filename',
'code',
{},
);
expect(data.result).toEqual(objectContaining(dependencyData));
});
it('does not extract requires of JSON files', async () => {
const jsonStr = '{"arbitrary":"json"}';
babelGenerator.default.mockReturnValue({
code: '{"arbitrary":"json"}',
map: [],
});
const data = await transformCode(
transformer,
'arbitrary.json',
'local/arbitrary.json',
jsonStr,
{},
);
const {dependencies, dependencyOffsets} = data.result;
expect(extractDependencies).not.toBeCalled();
expect(dependencies).toEqual([]);
expect(dependencyOffsets).toEqual([]);
});
it('calls back with every error thrown by `extractDependencies`', async () => {
const error = new Error('arbitrary');
extractDependencies.mockImplementation(() => {
throw error;
});
try {
await transformCode(
transformer,
'arbitrary.js',
'local/arbitrary.js',
'code',
{},
);
} catch (err) {
expect(err).toBe(error);
}
});
}); });
}); });

View File

@ -12,28 +12,25 @@
'use strict'; 'use strict';
const JsFileWrapping = require('../../ModuleGraph/worker/JsFileWrapping');
const collectDependencies = require('../../ModuleGraph/worker/collect-dependencies');
const constantFolding = require('./constant-folding'); const constantFolding = require('./constant-folding');
const extractDependencies = require('./extract-dependencies');
const generate = require('babel-generator').default; const generate = require('babel-generator').default;
const inline = require('./inline'); const inline = require('./inline');
const minify = require('./minify'); const minify = require('./minify');
const {compactMapping, toRawMappings} = require('../../Bundler/source-map'); const {compactMapping} = require('../../Bundler/source-map');
import type {LogEntry} from '../../Logger/Types'; import type {LogEntry} from '../../Logger/Types';
import type { import type {CompactRawMappings, MappingsMap} from '../../lib/SourceMap';
CompactRawMappings,
MappingsMap,
RawMappings,
} from '../../lib/SourceMap';
import type {LocalPath} from '../../node-haste/lib/toLocalPath'; import type {LocalPath} from '../../node-haste/lib/toLocalPath';
import type {ResultWithMap} from './minify'; import type {ResultWithMap} from './minify';
import type {Ast, Plugins as BabelPlugins} from 'babel-core'; import type {Ast, Plugins as BabelPlugins} from 'babel-core';
export type TransformedCode = { export type TransformedCode = {
code: string, code: string,
dependencies: Array<string>, dependencies: $ReadOnlyArray<string>,
dependencyOffsets: Array<number>,
map: CompactRawMappings, map: CompactRawMappings,
}; };
@ -96,6 +93,7 @@ async function transformCode(
filename: string, filename: string,
localPath: LocalPath, localPath: LocalPath,
sourceCode: string, sourceCode: string,
isScript: boolean,
options: Options, options: Options,
): Promise<Data> { ): Promise<Data> {
const isJson = filename.endsWith('.json'); const isJson = filename.endsWith('.json');
@ -116,7 +114,7 @@ async function transformCode(
? [] ? []
: [[inline.plugin, options], [constantFolding.plugin, options]]; : [[inline.plugin, options], [constantFolding.plugin, options]];
const result = await transformer.transform({ const {ast} = await transformer.transform({
filename, filename,
localPath, localPath,
options: options.transform, options: options.transform,
@ -124,9 +122,45 @@ async function transformCode(
src: sourceCode, src: sourceCode,
}); });
// Serialize the AST received from the transformer. const timeDelta = process.hrtime(transformFileStartLogEntry.start_timestamp);
const transformed = generate( const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
result.ast, const transformFileEndLogEntry = {
action_name: 'Transforming file',
action_phase: 'end',
file_name: filename,
duration_ms,
log_entry_label: 'Transforming file',
};
let dependencies, wrappedAst;
// If the module to transform is a script (meaning that is not part of the
// dependency graph and it code will just be prepended to the bundle modules),
// we need to wrap it differently than a commonJS module (also, scripts do
// not have dependencies).
if (isScript) {
dependencies = [];
wrappedAst = JsFileWrapping.wrapPolyfill(ast);
} else {
let dependencyData = collectDependencies(ast);
if (!options.dev) {
dependencyData = collectDependencies.forOptimization(
ast,
dependencyData.dependencies,
dependencyData.dependencyMapName,
);
}
dependencies = dependencyData.dependencies.map(dep => dep.name);
wrappedAst = JsFileWrapping.wrapModule(
ast,
dependencyData.dependencyMapName,
);
}
const result = generate(
wrappedAst,
{ {
code: false, code: false,
comments: false, comments: false,
@ -139,40 +173,10 @@ async function transformCode(
sourceCode, sourceCode,
); );
// If the transformer returns standard sourcemaps, we need to transform them const map = result.rawMappings ? result.rawMappings.map(compactMapping) : [];
// to rawMappings so we can process them correctly.
const rawMappings =
transformed.map && !Array.isArray(transformed.map)
? toRawMappings(transformed.map)
: transformed.map;
// Convert the sourcemaps to Compact Raw source maps.
const map = rawMappings ? rawMappings.map(compactMapping) : [];
let code = transformed.code;
if (isJson) {
code = code.replace(/^\w+\.exports=/, '');
} else {
// Remove shebang
code = code.replace(/^#!.*/, '');
}
const depsResult = isJson
? {dependencies: [], dependencyOffsets: []}
: extractDependencies(code, filename);
const timeDelta = process.hrtime(transformFileStartLogEntry.start_timestamp);
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
const transformFileEndLogEntry = {
action_name: 'Transforming file',
action_phase: 'end',
file_name: filename,
duration_ms,
log_entry_label: 'Transforming file',
};
return { return {
result: {...depsResult, code, map}, result: {dependencies, code: result.code, map},
transformFileStartLogEntry, transformFileStartLogEntry,
transformFileEndLogEntry, transformFileEndLogEntry,
}; };
@ -201,6 +205,7 @@ exports.transformAndExtractDependencies = async function(
filename: string, filename: string,
localPath: LocalPath, localPath: LocalPath,
sourceCode: string, sourceCode: string,
isScript: boolean,
options: Options, options: Options,
): Promise<Data> { ): Promise<Data> {
// $FlowFixMe: impossible to type a dynamic require. // $FlowFixMe: impossible to type a dynamic require.
@ -211,6 +216,7 @@ exports.transformAndExtractDependencies = async function(
filename, filename,
localPath, localPath,
sourceCode, sourceCode,
isScript,
options, options,
); );
}; };

View File

@ -133,7 +133,14 @@ function createMapLookup(dependencyMapIdentifier, propertyIdentifier) {
); );
} }
function collectDependencies(ast, replacement, dependencyMapIdentifier) { function collectDependencies(
ast,
replacement,
dependencyMapIdentifier,
): {
dependencies: $ReadOnlyArray<TransformResultDependency>,
dependencyMapName: string,
} {
const visited = new WeakSet(); const visited = new WeakSet();
const traversalState = {dependencyMapIdentifier}; const traversalState = {dependencyMapIdentifier};
traverse( traverse(

View File

@ -161,8 +161,8 @@ describe('Resolver', function() {
dependencyPairs.set(relativePath, dependencyModule.path); dependencyPairs.set(relativePath, dependencyModule.path);
} }
const {code: processedCode} = depResolver.wrapModule({ const processedCode = depResolver.wrapModule({
module: module, path: module.path,
getModuleId: resolutionResponse.getModuleId, getModuleId: resolutionResponse.getModuleId,
dependencyPairs, dependencyPairs,
name: 'test module', name: 'test module',
@ -201,11 +201,11 @@ describe('Resolver', function() {
mainModuleId: 'test module', mainModuleId: 'test module',
}); });
const {code: processedCode} = depResolver.wrapModule({ const processedCode = depResolver.wrapModule({
getModuleId: resolutionResponse.getModuleId, getModuleId: resolutionResponse.getModuleId,
dependencyPairs: resolutionResponse.getResolvedDependencyPairs(module), dependencyPairs: resolutionResponse.getResolvedDependencyPairs(module),
code, code,
module, path: module.path,
name: 'test module', name: 'test module',
dev: true, dev: true,
}); });
@ -220,90 +220,6 @@ describe('Resolver', function() {
); );
}); });
it('should pass through passed-in source maps', () => {
expect.assertions(1);
const module = createModule('test module');
const resolutionResponse = new ResolutionResponseMock({
dependencies: [module],
mainModuleId: 'test module',
});
const inputMap = {version: 3, mappings: 'ARBITRARY'};
const {map} = depResolver.wrapModule({
getModuleId: resolutionResponse.getModuleId,
dependencyPairs: resolutionResponse.getResolvedDependencyPairs(module),
module,
name: 'test module',
code: 'arbitrary(code)',
map: inputMap,
});
expect(map).toBe(inputMap);
});
it('should resolve polyfills', async function() {
expect.assertions(1);
return Resolver.load({
projectRoot: '/root',
}).then(depResolver => {
const polyfill = createPolyfill('test polyfill', []);
const code = ['global.fetch = () => 1;'].join('');
const {code: processedCode} = depResolver.wrapModule({
module: polyfill,
code,
});
expect(processedCode).toEqual(
[
'(function(global) {',
'global.fetch = () => 1;',
'\n})' +
"(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);",
].join(''),
);
});
});
describe('JSON files:', () => {
const code = JSON.stringify({arbitrary: 'data'});
const id = 'arbitrary.json';
let depResolver, module, resolutionResponse;
beforeEach(() => {
return Resolver.load({projectRoot: '/root'}).then(r => {
depResolver = r;
module = createJsonModule(id);
resolutionResponse = new ResolutionResponseMock({
dependencies: [module],
mainModuleId: id,
});
});
});
it('should prefix JSON files with `module.exports=`', () => {
expect.assertions(1);
const {code: processedCode} = depResolver.wrapModule({
getModuleId: resolutionResponse.getModuleId,
dependencyPairs: resolutionResponse.getResolvedDependencyPairs(
module,
),
module,
name: id,
code,
dev: false,
});
expect(processedCode).toEqual(
[
`__d(/* ${id} */function(global, require, module, exports) {`,
`module.exports = ${code}\n}, ${resolutionResponse.getModuleId(
module.path,
)});`,
].join(''),
);
});
});
describe('minification:', () => { describe('minification:', () => {
const code = 'arbitrary(code)'; const code = 'arbitrary(code)';
const id = 'arbitrary.js'; const id = 'arbitrary.js';

View File

@ -120,7 +120,6 @@ class Resolver {
} }
resolveRequires( resolveRequires(
module: Module,
getModuleId: (path: string) => number, getModuleId: (path: string) => number,
code: string, code: string,
dependencyPairs: Map<string, string>, dependencyPairs: Map<string, string>,
@ -154,44 +153,30 @@ class Resolver {
} }
wrapModule({ wrapModule({
module, path,
getModuleId, getModuleId,
dependencyPairs, dependencyPairs,
dependencyOffsets, dependencyOffsets,
name, name,
map,
code, code,
dev = true, dev = true,
}: { }: {
module: Module, path: string,
getModuleId: (path: string) => number, getModuleId: (path: string) => number,
dependencyPairs: Map<string, string>, dependencyPairs: Map<string, string>,
dependencyOffsets: Array<number>, dependencyOffsets: Array<number>,
name: string, name: string,
map: CompactRawMappings,
code: string, code: string,
dev?: boolean, dev?: boolean,
}): {code: string, map: CompactRawMappings} { }): string {
if (module.isJSON()) { code = this.resolveRequires(
code = `module.exports = ${code}`; getModuleId,
} code,
dependencyPairs,
dependencyOffsets,
);
if (module.isPolyfill()) { return defineModuleCode(getModuleId(path), code, name, dev);
code = definePolyfillCode(code);
} else {
const moduleId = getModuleId(module.path);
code = this.resolveRequires(
module,
getModuleId,
code,
dependencyPairs,
dependencyOffsets,
);
code = defineModuleCode(moduleId, code, name, dev);
}
return {code, map};
} }
async minifyModule( async minifyModule(

View File

@ -1,325 +1,337 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`basic_bundle bundles package with polyfills 1`] = ` exports[`basic_bundle bundles package with polyfills 1`] = `
"(function(global) { "(function (global) {
global.__DEV__ = false;
global.__BUNDLE_START_TIME__ = global.nativePerformanceNow ? global.nativePerformanceNow() : Date.now();
})(this);
(function (global) {
'use strict';
global.__DEV__ = false; global.require = _require;
global.__d = define;
var modules = Object.create(null);
global.__BUNDLE_START_TIME__ = global.nativePerformanceNow ? global.nativePerformanceNow() : Date.now(); function define(factory, moduleId, dependencyMap) {
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this); if (moduleId in modules) {
(function(global) { return;
}
'use strict'; modules[moduleId] = {
dependencyMap: dependencyMap,
global.require = _require; exports: undefined,
global.__d = define; factory: factory,
hasError: false,
var modules = Object.create(null); isInitialized: false
};
function define(factory, moduleId, dependencyMap) {
if (moduleId in modules) {
return;
} }
modules[moduleId] = {
dependencyMap: dependencyMap,
exports: undefined,
factory: factory,
hasError: false,
isInitialized: false
};
}
function _require(moduleId) { function _require(moduleId) {
var moduleIdReallyIsNumber = moduleId; var moduleIdReallyIsNumber = moduleId;
var module = modules[moduleIdReallyIsNumber]; var module = modules[moduleIdReallyIsNumber];
return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module); return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module);
} }
var inGuard = false;
function guardedLoadModule(moduleId, module) {
if (!inGuard && global.ErrorUtils) {
inGuard = true;
var returnValue = void 0;
try {
returnValue = loadModuleImplementation(moduleId, module);
} catch (e) {
global.ErrorUtils.reportFatalError(e);
}
inGuard = false;
return returnValue;
} else {
return loadModuleImplementation(moduleId, module);
}
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
var localId = moduleId & LOCAL_ID_MASK;
return {
segmentId: segmentId,
localId: localId
};
}
_require.unpackModuleId = unpackModuleId;
function loadModuleImplementation(moduleId, module) {
var nativeRequire = global.nativeRequire;
if (!module && nativeRequire) {
var _unpackModuleId = unpackModuleId(moduleId),
segmentId = _unpackModuleId.segmentId,
localId = _unpackModuleId.localId;
nativeRequire(localId, segmentId);
module = modules[moduleId];
}
if (!module) {
throw unknownModuleError(moduleId);
}
if (module.hasError) {
throw moduleThrewError(moduleId, module.error);
}
module.isInitialized = true;
var exports = module.exports = {};
var _module = module,
factory = _module.factory,
dependencyMap = _module.dependencyMap;
var inGuard = false;
function guardedLoadModule(moduleId, module) {
if (!inGuard && global.ErrorUtils) {
inGuard = true;
var returnValue = void 0;
try { try {
returnValue = loadModuleImplementation(moduleId, module); var _moduleObject = {
exports: exports
};
factory(global, _require, _moduleObject, exports, dependencyMap);
{
module.factory = undefined;
module.dependencyMap = undefined;
}
return module.exports = _moduleObject.exports;
} catch (e) { } catch (e) {
global.ErrorUtils.reportFatalError(e); module.hasError = true;
module.error = e;
module.isInitialized = false;
module.exports = undefined;
throw e;
} }
inGuard = false;
return returnValue;
} else {
return loadModuleImplementation(moduleId, module);
}
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
var localId = moduleId & LOCAL_ID_MASK;
return { segmentId: segmentId, localId: localId };
}
_require.unpackModuleId = unpackModuleId;
function loadModuleImplementation(moduleId, module) {
var nativeRequire = global.nativeRequire;
if (!module && nativeRequire) {
var _unpackModuleId = unpackModuleId(moduleId),
segmentId = _unpackModuleId.segmentId,
localId = _unpackModuleId.localId;
nativeRequire(localId, segmentId);
module = modules[moduleId];
} }
if (!module) { function unknownModuleError(id) {
throw unknownModuleError(moduleId); var message = 'Requiring unknown module \\"' + id + '\\".';
return Error(message);
} }
if (module.hasError) { function moduleThrewError(id, error) {
throw moduleThrewError(moduleId, module.error); var displayName = id;
return Error('Requiring module \\"' + displayName + '\\", which threw an exception: ' + error);
} }
})(this);
(function (global) {
'use strict';
module.isInitialized = true; if (!Object.keys) {
var exports = module.exports = {}; Object.keys = function () {};
var _module = module,
factory = _module.factory,
dependencyMap = _module.dependencyMap;
try {
var _moduleObject = { exports: exports };
factory(global, _require, _moduleObject, exports, dependencyMap);
{
module.factory = undefined;
module.dependencyMap = undefined;
}
return module.exports = _moduleObject.exports;
} catch (e) {
module.hasError = true;
module.error = e;
module.isInitialized = false;
module.exports = undefined;
throw e;
} }
} })(this);
(function (global) {
'use strict';
function unknownModuleError(id) { if (!String.prototype.repeat) {
var message = 'Requiring unknown module \\"' + id + '\\".'; String.prototype.repeat = function () {};
}
})(this);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
return Error(message); var Bar = require(_dependencyMap[0]);
}
function moduleThrewError(id, error) { var Foo = require(_dependencyMap[1]);
var displayName = id;
return Error('Requiring module \\"' + displayName + '\\", which threw an exception: ' + error);
}
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);
(function(global) {
'use strict'; module.exports = {
Foo: Foo,
Bar: Bar
};
},4,[5,6]);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
if (!Object.keys) { var Foo = require(_dependencyMap[0]);
Object.keys = function () {};
}
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);
(function(global) {
'use strict'; module.exports = {
type: 'bar',
foo: Foo.type
};
},5,[6]);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
if (!String.prototype.repeat) { var asset = require(_dependencyMap[0]);
String.prototype.repeat = function () {};
}
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);
__d(/* /TestBundle.js */function(global, require, module, exports) {
'use strict'; module.exports = {
type: 'foo',
var Bar = require(5); // 5 = ./Bar asset: asset
var Foo = require(6); // 6 = ./Foo };
},6,[7]);
module.exports = { Foo: Foo, Bar: Bar };
}, 4);
__d(/* /Bar.js */function(global, require, module, exports) {
'use strict';
var Foo = require(6); // 6 = ./Foo
module.exports = { type: 'bar', foo: Foo.type };
}, 5);
__d(/* /Foo.js */function(global, require, module, exports) {
'use strict';
var asset = require(7); // 7 = ./test.png
module.exports = { type: 'foo', asset: asset };
}, 6);
__d(/* /test.png */function(global, require, module, exports) {module.exports=require(8).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = /AssetRegistry __d(/* /test.png */function(global, require, module, exports) {module.exports=require(8).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = /AssetRegistry
}, 7); }, 7);
__d(/* /AssetRegistry.js */function(global, require, module, exports) { __d(function (global, require, module, exports, _dependencyMap) {
'use strict';
'use strict'; },8,[]);
}, 8);
require(4);" require(4);"
`; `;
exports[`basic_bundle bundles package without polyfills 1`] = ` exports[`basic_bundle bundles package without polyfills 1`] = `
"(function(global) { "(function (global) {
global.__DEV__ = false;
global.__BUNDLE_START_TIME__ = global.nativePerformanceNow ? global.nativePerformanceNow() : Date.now();
})(this);
(function (global) {
'use strict';
global.__DEV__ = false; global.require = _require;
global.__d = define;
var modules = Object.create(null);
global.__BUNDLE_START_TIME__ = global.nativePerformanceNow ? global.nativePerformanceNow() : Date.now(); function define(factory, moduleId, dependencyMap) {
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this); if (moduleId in modules) {
(function(global) { return;
}
'use strict'; modules[moduleId] = {
dependencyMap: dependencyMap,
global.require = _require; exports: undefined,
global.__d = define; factory: factory,
hasError: false,
var modules = Object.create(null); isInitialized: false
};
function define(factory, moduleId, dependencyMap) {
if (moduleId in modules) {
return;
} }
modules[moduleId] = {
dependencyMap: dependencyMap,
exports: undefined,
factory: factory,
hasError: false,
isInitialized: false
};
}
function _require(moduleId) { function _require(moduleId) {
var moduleIdReallyIsNumber = moduleId; var moduleIdReallyIsNumber = moduleId;
var module = modules[moduleIdReallyIsNumber]; var module = modules[moduleIdReallyIsNumber];
return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module); return module && module.isInitialized ? module.exports : guardedLoadModule(moduleIdReallyIsNumber, module);
} }
var inGuard = false;
function guardedLoadModule(moduleId, module) {
if (!inGuard && global.ErrorUtils) {
inGuard = true;
var returnValue = void 0;
try {
returnValue = loadModuleImplementation(moduleId, module);
} catch (e) {
global.ErrorUtils.reportFatalError(e);
}
inGuard = false;
return returnValue;
} else {
return loadModuleImplementation(moduleId, module);
}
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
var localId = moduleId & LOCAL_ID_MASK;
return {
segmentId: segmentId,
localId: localId
};
}
_require.unpackModuleId = unpackModuleId;
function loadModuleImplementation(moduleId, module) {
var nativeRequire = global.nativeRequire;
if (!module && nativeRequire) {
var _unpackModuleId = unpackModuleId(moduleId),
segmentId = _unpackModuleId.segmentId,
localId = _unpackModuleId.localId;
nativeRequire(localId, segmentId);
module = modules[moduleId];
}
if (!module) {
throw unknownModuleError(moduleId);
}
if (module.hasError) {
throw moduleThrewError(moduleId, module.error);
}
module.isInitialized = true;
var exports = module.exports = {};
var _module = module,
factory = _module.factory,
dependencyMap = _module.dependencyMap;
var inGuard = false;
function guardedLoadModule(moduleId, module) {
if (!inGuard && global.ErrorUtils) {
inGuard = true;
var returnValue = void 0;
try { try {
returnValue = loadModuleImplementation(moduleId, module); var _moduleObject = {
exports: exports
};
factory(global, _require, _moduleObject, exports, dependencyMap);
{
module.factory = undefined;
module.dependencyMap = undefined;
}
return module.exports = _moduleObject.exports;
} catch (e) { } catch (e) {
global.ErrorUtils.reportFatalError(e); module.hasError = true;
module.error = e;
module.isInitialized = false;
module.exports = undefined;
throw e;
} }
inGuard = false;
return returnValue;
} else {
return loadModuleImplementation(moduleId, module);
}
}
var ID_MASK_SHIFT = 16;
var LOCAL_ID_MASK = ~0 >>> ID_MASK_SHIFT;
function unpackModuleId(moduleId) {
var segmentId = moduleId >>> ID_MASK_SHIFT;
var localId = moduleId & LOCAL_ID_MASK;
return { segmentId: segmentId, localId: localId };
}
_require.unpackModuleId = unpackModuleId;
function loadModuleImplementation(moduleId, module) {
var nativeRequire = global.nativeRequire;
if (!module && nativeRequire) {
var _unpackModuleId = unpackModuleId(moduleId),
segmentId = _unpackModuleId.segmentId,
localId = _unpackModuleId.localId;
nativeRequire(localId, segmentId);
module = modules[moduleId];
} }
if (!module) { function unknownModuleError(id) {
throw unknownModuleError(moduleId); var message = 'Requiring unknown module \\"' + id + '\\".';
return Error(message);
} }
if (module.hasError) { function moduleThrewError(id, error) {
throw moduleThrewError(moduleId, module.error); var displayName = id;
return Error('Requiring module \\"' + displayName + '\\", which threw an exception: ' + error);
} }
})(this);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
module.isInitialized = true; var Bar = require(_dependencyMap[0]);
var exports = module.exports = {};
var _module = module,
factory = _module.factory,
dependencyMap = _module.dependencyMap;
try { var Foo = require(_dependencyMap[1]);
var _moduleObject = { exports: exports }; module.exports = {
Foo: Foo,
Bar: Bar
};
},2,[3,4]);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
factory(global, _require, _moduleObject, exports, dependencyMap); var Foo = require(_dependencyMap[0]);
{ module.exports = {
module.factory = undefined; type: 'bar',
module.dependencyMap = undefined; foo: Foo.type
} };
},3,[4]);
__d(function (global, require, module, exports, _dependencyMap) {
'use strict';
return module.exports = _moduleObject.exports; var asset = require(_dependencyMap[0]);
} catch (e) {
module.hasError = true;
module.error = e;
module.isInitialized = false;
module.exports = undefined;
throw e;
}
}
function unknownModuleError(id) { module.exports = {
var message = 'Requiring unknown module \\"' + id + '\\".'; type: 'foo',
asset: asset
return Error(message); };
} },4,[5]);
function moduleThrewError(id, error) {
var displayName = id;
return Error('Requiring module \\"' + displayName + '\\", which threw an exception: ' + error);
}
})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);
__d(/* /TestBundle.js */function(global, require, module, exports) {
'use strict';
var Bar = require(3); // 3 = ./Bar
var Foo = require(4); // 4 = ./Foo
module.exports = { Foo: Foo, Bar: Bar };
}, 2);
__d(/* /Bar.js */function(global, require, module, exports) {
'use strict';
var Foo = require(4); // 4 = ./Foo
module.exports = { type: 'bar', foo: Foo.type };
}, 3);
__d(/* /Foo.js */function(global, require, module, exports) {
'use strict';
var asset = require(5); // 5 = ./test.png
module.exports = { type: 'foo', asset: asset };
}, 4);
__d(/* /test.png */function(global, require, module, exports) {module.exports=require(6).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 6 = /AssetRegistry __d(/* /test.png */function(global, require, module, exports) {module.exports=require(6).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 6 = /AssetRegistry
}, 5); }, 5);
__d(/* /AssetRegistry.js */function(global, require, module, exports) { __d(function (global, require, module, exports, _dependencyMap) {
'use strict';
'use strict'; },6,[]);
}, 6);
require(2);" require(2);"
`; `;

View File

@ -212,9 +212,7 @@ function validateCachedResult(cachedResult: mixed): ?CachedResult {
typeof cachedResult === 'object' && typeof cachedResult === 'object' &&
typeof cachedResult.code === 'string' && typeof cachedResult.code === 'string' &&
Array.isArray(cachedResult.dependencies) && Array.isArray(cachedResult.dependencies) &&
cachedResult.dependencies.every(dep => typeof dep === 'string') && cachedResult.dependencies.every(dep => typeof dep === 'string')
Array.isArray(cachedResult.dependencyOffsets) &&
cachedResult.dependencyOffsets.every(offset => typeof offset === 'number')
) { ) {
return (cachedResult: any); return (cachedResult: any);
} }

View File

@ -33,8 +33,7 @@ const CACHE_SUB_DIR = 'cache';
export type CachedResult = { export type CachedResult = {
code: string, code: string,
dependencies: Array<string>, dependencies: $ReadOnlyArray<string>,
dependencyOffsets: Array<number>,
map: CompactRawMappings, map: CompactRawMappings,
}; };
@ -143,7 +142,6 @@ class FileBasedCache {
.digest('hex'), .digest('hex'),
hashSourceCode(props), hashSourceCode(props),
result.dependencies, result.dependencies,
result.dependencyOffsets,
result.map, result.map,
]), ]),
); );
@ -214,7 +212,6 @@ class FileBasedCache {
result: { result: {
code: transformedCode, code: transformedCode,
dependencies: metadata.dependencies, dependencies: metadata.dependencies,
dependencyOffsets: metadata.dependencyOffsets,
map: metadata.sourceMap, map: metadata.sourceMap,
}, },
outdatedDependencies: EMPTY_ARRAY, outdatedDependencies: EMPTY_ARRAY,
@ -335,7 +332,6 @@ function readMetadataFileSync(
cachedResultHash: string, cachedResultHash: string,
cachedSourceHash: string, cachedSourceHash: string,
dependencies: Array<string>, dependencies: Array<string>,
dependencyOffsets: Array<number>,
sourceMap: CompactRawMappings, sourceMap: CompactRawMappings,
} { } {
const metadataStr = fs.readFileSync(metadataFilePath, 'utf8'); const metadataStr = fs.readFileSync(metadataFilePath, 'utf8');
@ -347,7 +343,6 @@ function readMetadataFileSync(
cachedResultHash, cachedResultHash,
cachedSourceHash, cachedSourceHash,
dependencies, dependencies,
dependencyOffsets,
sourceMap, sourceMap,
] = metadata; ] = metadata;
if ( if (
@ -357,10 +352,6 @@ function readMetadataFileSync(
Array.isArray(dependencies) && Array.isArray(dependencies) &&
dependencies.every(dep => typeof dep === 'string') dependencies.every(dep => typeof dep === 'string')
) || ) ||
!(
Array.isArray(dependencyOffsets) &&
dependencyOffsets.every(offset => typeof offset === 'number')
) ||
!(sourceMap == null || typeof sourceMap === 'object') !(sourceMap == null || typeof sourceMap === 'object')
) { ) {
return null; return null;
@ -369,7 +360,6 @@ function readMetadataFileSync(
cachedResultHash, cachedResultHash,
cachedSourceHash, cachedSourceHash,
dependencies, dependencies,
dependencyOffsets,
sourceMap, sourceMap,
}; };
} }

View File

@ -71,7 +71,6 @@ describe('TransformCaching.FileBasedCache', () => {
result: { result: {
code: `/* result for ${key} */`, code: `/* result for ${key} */`,
dependencies: ['foo', `dep of ${key}`], dependencies: ['foo', `dep of ${key}`],
dependencyOffsets: [12, 34],
map: {desc: `source map for ${key}`}, map: {desc: `source map for ${key}`},
}, },
}; };
@ -104,7 +103,6 @@ describe('TransformCaching.FileBasedCache', () => {
result: { result: {
code: `/* result for ${key} */`, code: `/* result for ${key} */`,
dependencies: ['foo', 'bar'], dependencies: ['foo', 'bar'],
dependencyOffsets: [12, 34],
map: {desc: `source map for ${key}`}, map: {desc: `source map for ${key}`},
}, },
}; };

View File

@ -39,8 +39,7 @@ import type {LocalPath} from './lib/toLocalPath';
export type ReadResult = { export type ReadResult = {
+code: string, +code: string,
+dependencies: Array<string>, +dependencies: $ReadOnlyArray<string>,
+dependencyOffsets?: ?Array<number>,
+map: CompactRawMappings, +map: CompactRawMappings,
+source: string, +source: string,
}; };