Add `bundle` command
Summary: This adds the machinery necessary to create a bundling function, and adds different reusable parts around generating code and maps for bundles. Used for the new integration with Buck Reviewed By: cpojer Differential Revision: D4299272 fbshipit-source-id: 59ebe39a454ebf56c2159717c2881088d6d3308a
This commit is contained in:
parent
a76547f7ac
commit
f3a9decebc
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Copyright (c) 2016-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.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const defaults = require('../../../defaults');
|
||||
const nullthrows = require('fbjs/lib/nullthrows');
|
||||
const parallel = require('async/parallel');
|
||||
const seq = require('async/seq');
|
||||
|
||||
const {virtualModule} = require('./output/util');
|
||||
|
||||
import type {
|
||||
Callback,
|
||||
GraphFn,
|
||||
GraphResult,
|
||||
Module,
|
||||
} from './types.flow';
|
||||
|
||||
type BuildFn = (
|
||||
entryPoints: Iterable<string>,
|
||||
options: BuildOptions,
|
||||
callback: Callback<{modules: Iterable<Module>, entryModules: Iterable<Module>}>,
|
||||
) => void;
|
||||
|
||||
type BuildOptions = {|
|
||||
optimize?: boolean,
|
||||
platform?: string,
|
||||
|};
|
||||
|
||||
exports.createBuildSetup = (
|
||||
graph: GraphFn,
|
||||
translateDefaultsPath: string => string = x => x,
|
||||
): BuildFn =>
|
||||
(entryPoints, options, callback) => {
|
||||
const {
|
||||
optimize = false,
|
||||
platform = defaults.platforms[0],
|
||||
} = options;
|
||||
const graphOptions = {optimize};
|
||||
|
||||
const graphWithOptions =
|
||||
(entry, cb) => graph(entry, platform, graphOptions, cb);
|
||||
const graphOnlyModules = seq(graphWithOptions, getModules);
|
||||
|
||||
parallel({
|
||||
graph: cb => graphWithOptions(
|
||||
concat(defaults.runBeforeMainModule, entryPoints),
|
||||
cb,
|
||||
),
|
||||
moduleSystem: cb => graphOnlyModules(
|
||||
[translateDefaultsPath(defaults.moduleSystem)],
|
||||
cb,
|
||||
),
|
||||
polyfills: cb => graphOnlyModules(
|
||||
defaults.polyfills.map(translateDefaultsPath),
|
||||
cb,
|
||||
),
|
||||
}, (
|
||||
error: ?Error,
|
||||
result?: {graph: GraphResult, moduleSystem: Array<Module>, polyfills: Array<Module>},
|
||||
) => {
|
||||
if (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const {
|
||||
graph: {modules, entryModules},
|
||||
moduleSystem,
|
||||
polyfills,
|
||||
} = nullthrows(result);
|
||||
|
||||
callback(null, {
|
||||
entryModules,
|
||||
modules: concat([prelude(optimize)], moduleSystem, polyfills, modules),
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getModules = (x, cb) => cb(null, x.modules);
|
||||
|
||||
function* concat<T>(...iterables: Array<Iterable<T>>): Iterable<T> {
|
||||
for (const it of iterables) {
|
||||
yield* it;
|
||||
}
|
||||
}
|
||||
|
||||
function prelude(optimize) {
|
||||
return virtualModule(
|
||||
`var __DEV__= ${String(!optimize)
|
||||
}, __BUNDLE_START_TIME__ = Date.now();`
|
||||
);
|
||||
}
|
|
@ -13,36 +13,32 @@
|
|||
const {createIndexMap} = require('./source-map');
|
||||
const {addModuleIdsToModuleWrapper} = require('./util');
|
||||
|
||||
import type {Module} from '../types.flow';
|
||||
import type {SourceMap} from './source-map';
|
||||
import type {OutputFn} from '../types.flow';
|
||||
|
||||
module.exports = (
|
||||
modules: Iterable<Module>,
|
||||
filename?: string,
|
||||
idForPath: {path: string} => number,
|
||||
): {code: string, map: SourceMap} => {
|
||||
let code = '';
|
||||
let line = 0;
|
||||
const sections = [];
|
||||
(modules, filename, idForPath) => {
|
||||
let code = '';
|
||||
let line = 0;
|
||||
const sections = [];
|
||||
|
||||
for (const module of modules) {
|
||||
const {file} = module;
|
||||
const moduleCode = file.type === 'module'
|
||||
? addModuleIdsToModuleWrapper(module, idForPath)
|
||||
: file.code;
|
||||
for (const module of modules) {
|
||||
const {file} = module;
|
||||
const moduleCode = file.type === 'module'
|
||||
? addModuleIdsToModuleWrapper(module, idForPath)
|
||||
: file.code;
|
||||
|
||||
code += moduleCode + '\n';
|
||||
if (file.map) {
|
||||
sections.push({
|
||||
map: file.map,
|
||||
offset: {column: 0, line}
|
||||
});
|
||||
code += moduleCode + '\n';
|
||||
if (file.map) {
|
||||
sections.push({
|
||||
map: file.map,
|
||||
offset: {column: 0, line}
|
||||
});
|
||||
}
|
||||
line += countLines(moduleCode);
|
||||
}
|
||||
line += countLines(moduleCode);
|
||||
}
|
||||
|
||||
return {code, map: createIndexMap({file: filename, sections})};
|
||||
};
|
||||
return {code, map: createIndexMap({file: filename, sections})};
|
||||
}: OutputFn);
|
||||
|
||||
const reLine = /^/gm;
|
||||
function countLines(string: string): number {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
import type {Module} from '../types.flow';
|
||||
import type {IdForPathFn, Module} from '../types.flow';
|
||||
|
||||
// Transformed modules have the form
|
||||
// __d(function(require, module, global, exports, dependencyMap) {
|
||||
|
@ -59,11 +59,27 @@ exports.createIdForPathFn = (): ({path: string} => number) => {
|
|||
};
|
||||
};
|
||||
|
||||
exports.virtualModule = (code: string): Module => ({
|
||||
dependencies: [],
|
||||
file: {
|
||||
code,
|
||||
path: '',
|
||||
type: 'script',
|
||||
// creates a series of virtual modules with require calls to the passed-in
|
||||
// modules.
|
||||
exports.requireCallsTo = function* (
|
||||
modules: Iterable<Module>,
|
||||
idForPath: IdForPathFn,
|
||||
): Iterable<Module> {
|
||||
for (const module of modules) {
|
||||
yield virtualModule(`require(${idForPath(module.file)});`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// creates a virtual module (i.e. not corresponding to a file on disk)
|
||||
// with the given source code.
|
||||
exports.virtualModule = virtualModule;
|
||||
function virtualModule(code: string) {
|
||||
return {
|
||||
dependencies: [],
|
||||
file: {
|
||||
code,
|
||||
path: '',
|
||||
type: 'script',
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{"main": "ModuleGraph.js"}
|
|
@ -10,29 +10,13 @@
|
|||
*/
|
||||
'use strict';
|
||||
|
||||
import type {SourceMap} from './output/source-map';
|
||||
import type {Console} from 'console';
|
||||
|
||||
export type Callback<A = void, B = void>
|
||||
= (Error => mixed)
|
||||
& ((null | void, A, B) => mixed);
|
||||
|
||||
type ResolveOptions = {
|
||||
log?: Console,
|
||||
};
|
||||
|
||||
type LoadOptions = {|
|
||||
log?: Console,
|
||||
optimize?: boolean,
|
||||
platform?: string,
|
||||
|};
|
||||
|
||||
type GraphOptions = {|
|
||||
cwd?: string,
|
||||
log?: Console,
|
||||
optimize?: boolean,
|
||||
skip?: Set<string>,
|
||||
|};
|
||||
|
||||
type Dependency = {|
|
||||
id: string,
|
||||
path: string,
|
||||
|
@ -47,11 +31,6 @@ export type File = {|
|
|||
|
||||
type FileTypes = 'module' | 'script';
|
||||
|
||||
export type Module = {|
|
||||
dependencies: Array<Dependency>,
|
||||
file: File,
|
||||
|};
|
||||
|
||||
export type GraphFn = (
|
||||
entryPoints: Iterable<string>,
|
||||
platform: string,
|
||||
|
@ -59,11 +38,55 @@ export type GraphFn = (
|
|||
callback?: Callback<GraphResult>,
|
||||
) => void;
|
||||
|
||||
type GraphOptions = {|
|
||||
cwd?: string,
|
||||
log?: Console,
|
||||
optimize?: boolean,
|
||||
skip?: Set<string>,
|
||||
|};
|
||||
|
||||
export type GraphResult = {
|
||||
entryModules: Array<Module>,
|
||||
modules: Array<Module>,
|
||||
};
|
||||
|
||||
export type IdForPathFn = {path: string} => number;
|
||||
|
||||
export type LoadFn = (
|
||||
file: string,
|
||||
options: LoadOptions,
|
||||
callback: Callback<File, Array<string>>,
|
||||
) => void;
|
||||
|
||||
type LoadOptions = {|
|
||||
log?: Console,
|
||||
optimize?: boolean,
|
||||
platform?: string,
|
||||
|};
|
||||
|
||||
export type Module = {|
|
||||
dependencies: Array<Dependency>,
|
||||
file: File,
|
||||
|};
|
||||
|
||||
export type OutputFn = (
|
||||
modules: Iterable<Module>,
|
||||
filename?: string,
|
||||
idForPath: IdForPathFn,
|
||||
) => OutputResult;
|
||||
|
||||
type OutputResult = {
|
||||
code: string,
|
||||
map: SourceMap,
|
||||
};
|
||||
|
||||
export type PackageData = {|
|
||||
browser?: Object | string,
|
||||
main?: string,
|
||||
name?: string,
|
||||
'react-native'?: Object | string,
|
||||
|};
|
||||
|
||||
export type ResolveFn = (
|
||||
id: string,
|
||||
source: string,
|
||||
|
@ -72,12 +95,25 @@ export type ResolveFn = (
|
|||
callback: Callback<string>,
|
||||
) => void;
|
||||
|
||||
export type LoadFn = (
|
||||
file: string,
|
||||
options: LoadOptions,
|
||||
callback: Callback<File, Array<string>>,
|
||||
type ResolveOptions = {
|
||||
log?: Console,
|
||||
};
|
||||
|
||||
export type TransformFn = (
|
||||
data: {|
|
||||
filename: string,
|
||||
options?: Object,
|
||||
plugins?: Array<string | Object | [string | Object, any]>,
|
||||
sourceCode: string,
|
||||
|},
|
||||
callback: Callback<TransformFnResult>
|
||||
) => void;
|
||||
|
||||
|
||||
export type TransformFnResult = {
|
||||
ast: Object,
|
||||
};
|
||||
|
||||
export type TransformResult = {|
|
||||
code: string,
|
||||
dependencies: Array<string>,
|
||||
|
@ -93,24 +129,3 @@ export type TransformedFile = {
|
|||
transformed: {[variant: string]: TransformResult},
|
||||
type: FileTypes,
|
||||
};
|
||||
|
||||
export type PackageData = {|
|
||||
browser?: Object | string,
|
||||
main?: string,
|
||||
name?: string,
|
||||
'react-native'?: Object | string,
|
||||
|};
|
||||
|
||||
export type TransformFnResult = {
|
||||
ast: Object,
|
||||
};
|
||||
|
||||
export type TransformFn = (
|
||||
data: {|
|
||||
filename: string,
|
||||
options?: Object,
|
||||
plugins?: Array<string | Object | [string | Object, any]>,
|
||||
sourceCode: string,
|
||||
|},
|
||||
callback: Callback<TransformFnResult>
|
||||
) => void;
|
||||
|
|
Loading…
Reference in New Issue