Use Graph traversal logic for building polyfills

Reviewed By: mjesun

Differential Revision: D7240946

fbshipit-source-id: 5af729878cdf31831b15867c296cf89025ab6f58
This commit is contained in:
Rafael Oleza 2018-03-19 10:04:57 -07:00 committed by Facebook Github Bot
parent 6be6b0805d
commit d8eed45c37
10 changed files with 94 additions and 94 deletions

View File

@ -42,6 +42,7 @@ export type Options = {
+minify: boolean,
+onProgress: ?(doneCont: number, totalCount: number) => mixed,
+platform: ?string,
+type: 'module' | 'script',
};
/**
@ -199,6 +200,17 @@ class DeltaCalculator extends EventEmitter {
projectRoot,
};
// When we're processing scripts, we don't need to calculate any
// inlineRequires information, since scripts by definition don't have
// requires().
if (this._options.type === 'script') {
// $FlowIssue #23854098 - Object.assign() loses the strictness of an object in flow
return {
...transformOptionsForBlacklist,
inlineRequires: false,
};
}
const {
inlineRequires,
} = await this._bundler.getTransformOptionsForEntryFiles(
@ -211,14 +223,14 @@ class DeltaCalculator extends EventEmitter {
entryPoints: [path],
},
this._dependencyGraph,
transformOptionsForBlacklist,
{...transformOptionsForBlacklist, type: this._options.type},
);
return Array.from(added.keys());
},
);
// $FlowFixMe flow does not recognize well Object.assign() return types.
// $FlowIssue #23854098 - Object.assign() loses the strictness of an object in flow
return {
...transformOptionsForBlacklist,
inlineRequires: inlineRequires || false,
@ -267,7 +279,10 @@ class DeltaCalculator extends EventEmitter {
modifiedFiles: Set<string>,
deletedFiles: Set<string>,
): Promise<DeltaResult> {
const transformerOptions = await this.getTransformerOptions();
const transformerOptions = {
...(await this.getTransformerOptions()),
type: this._options.type,
};
if (!this._graph.dependencies.size) {
const {added} = await initialTraverseDependencies(

View File

@ -126,6 +126,7 @@ class DeltaTransformer extends EventEmitter {
const deltaCalculator = new DeltaCalculator(bundler, dependencyGraph, {
...bundleOptions,
entryPoints: [bundleOptions.entryFile],
type: 'module',
});
return new DeltaTransformer(

View File

@ -52,6 +52,11 @@ type Delta = {
deleted: Set<string>,
};
export type TransformOptions = {|
...JSTransformerOptions,
type: 'module' | 'script',
|};
/**
* Dependency Traversal logic for the Delta Bundler. This method calculates
* the modules that should be included in the bundle by traversing the
@ -69,7 +74,7 @@ type Delta = {
async function traverseDependencies(
paths: $ReadOnlyArray<string>,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
graph: Graph,
onProgress?: (numProcessed: number, total: number) => mixed = () => {},
): Promise<Result> {
@ -136,11 +141,17 @@ async function traverseDependencies(
async function initialTraverseDependencies(
graph: Graph,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
onProgress?: (numProcessed: number, total: number) => mixed = () => {},
): Promise<Result> {
graph.entryPoints.forEach(entryPoint =>
createEdge(dependencyGraph.getModuleForPath(entryPoint), graph),
createEdge(
dependencyGraph.getModuleForPath(
entryPoint,
transformOptions.type === 'script',
),
graph,
),
);
await traverseDependencies(
@ -162,7 +173,7 @@ async function initialTraverseDependencies(
async function traverseDependenciesForSingleFile(
edge: DependencyEdge,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
graph: Graph,
delta: Delta,
onProgress?: (numProcessed: number, total: number) => mixed = () => {},
@ -194,7 +205,7 @@ async function traverseDependenciesForSingleFile(
async function processEdge(
edge: DependencyEdge,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
graph: Graph,
delta: Delta,
onDependencyAdd: () => mixed,
@ -202,10 +213,11 @@ async function processEdge(
): Promise<void> {
const previousDependencies = edge.dependencies;
const result = await dependencyGraph
.getModuleForPath(edge.path)
.read(
removeInlineRequiresBlacklistFromOptions(edge.path, transformOptions),
const {type, ...workerTransformOptions} = transformOptions;
const module = dependencyGraph.getModuleForPath(edge.path, type === 'script');
const result = await module.read(
removeInlineRequiresBlacklistFromOptions(edge.path, workerTransformOptions),
);
// Get the absolute path of all sub-dependencies (some of them could have been
@ -262,7 +274,7 @@ async function addDependency(
parentEdge: DependencyEdge,
path: string,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
graph: Graph,
delta: Delta,
onDependencyAdd: () => mixed,
@ -277,7 +289,10 @@ async function addDependency(
return;
}
const edge = createEdge(dependencyGraph.getModuleForPath(path), graph);
const edge = createEdge(
dependencyGraph.getModuleForPath(path, transformOptions.type === 'script'),
graph,
);
edge.inverseDependencies.add(parentEdge.path);
delta.added.set(edge.path, edge);
@ -365,11 +380,14 @@ function destroyEdge(edge: DependencyEdge, graph: Graph) {
function resolveDependencies(
parentPath,
dependencies: Array<string>,
dependencies: $ReadOnlyArray<string>,
dependencyGraph: DependencyGraph,
transformOptions: JSTransformerOptions,
transformOptions: TransformOptions,
): Map<string, string> {
const parentModule = dependencyGraph.getModuleForPath(parentPath);
const parentModule = dependencyGraph.getModuleForPath(
parentPath,
transformOptions.type === 'string',
);
return new Map(
dependencies.map(relativePath => [

View File

@ -466,6 +466,7 @@ describe('processRequest', () => {
minify: false,
onProgress: null,
platform: undefined,
type: 'module',
}),
);
});

View File

@ -245,7 +245,7 @@ class Server {
this._opts.projectRoots,
);
let graph = await this._deltaBundler.buildGraph({
const crawlingOptions = {
assetPlugins: options.assetPlugins,
customTransformOptions: options.customTransformOptions,
dev: options.dev,
@ -254,11 +254,14 @@ class Server {
minify: options.minify,
onProgress: options.onProgress,
platform: options.platform,
});
type: 'module',
};
let graph = await this._deltaBundler.buildGraph(crawlingOptions);
let prependScripts = await getPrependedScripts(
this._opts,
options,
this._bundler,
crawlingOptions,
this._deltaBundler,
);
if (options.minify) {
@ -973,6 +976,7 @@ class Server {
runBeforeMainModule: [],
runModule: true,
sourceMapUrl: null,
type: 'script',
unbundle: false,
};
}

View File

@ -43,6 +43,7 @@ async function getTransformOptions(): Promise<JSTransformerOptions> {
hot: true,
minify: false,
platform: 'ios',
type: 'module',
};
const deltaCalculator = new DeltaCalculator(

View File

@ -13,27 +13,27 @@
const defaults = require('../defaults');
const getPreludeCode = require('./getPreludeCode');
import type Bundler from '../Bundler';
import type {DependencyEdge} from '../DeltaBundler/traverseDependencies';
import type Module from '../node-haste/Module';
import type DeltaBundler from '../DeltaBundler';
import type {CustomTransformOptions} from '../JSTransformer/worker';
type Options = {
enableBabelRCLookup: boolean,
getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,
polyfillModuleNames: Array<string>,
projectRoots: $ReadOnlyArray<string>,
};
type BundleOptions = {
customTransformOptions: CustomTransformOptions,
+dev: boolean,
+hot: boolean,
+minify: boolean,
+platform: ?string,
};
async function getPrependedScripts(
options: Options,
bundleOptions: BundleOptions,
bundler: Bundler,
deltaBundler: DeltaBundler,
): Promise<Array<DependencyEdge>> {
// Get all the polyfills from the relevant option params (the
// `getPolyfills()` method and the `polyfillModuleNames` variable).
@ -43,32 +43,22 @@ async function getPrependedScripts(
})
.concat(options.polyfillModuleNames);
const dependencyGraph = await bundler.getDependencyGraph();
// Build the module system dependencies (scripts that need to
// be included at the very beginning of the bundle) + any polifyll.
const modules = [defaults.moduleSystem]
.concat(polyfillModuleNames)
.map(polyfillModuleName =>
dependencyGraph.createPolyfill({
file: polyfillModuleName,
}),
);
const transformOptions = {
const graph = await deltaBundler.buildGraph({
assetPlugins: [],
customTransformOptions: bundleOptions.customTransformOptions,
dev: bundleOptions.dev,
enableBabelRCLookup: options.enableBabelRCLookup,
entryPoints: [defaults.moduleSystem, ...polyfillModuleNames],
hot: bundleOptions.hot,
projectRoot: options.projectRoots[0],
};
minify: bundleOptions.minify,
onProgress: null,
platform: bundleOptions.platform,
type: 'script',
});
const out = await Promise.all(
modules.map(module => _createEdgeFromScript(module, transformOptions)),
);
out.unshift(_getPrelude({dev: bundleOptions.dev}));
return out;
return [
_getPrelude({dev: bundleOptions.dev}),
...graph.dependencies.values(),
];
}
function _getPrelude({dev}: {dev: boolean}): DependencyEdge {
@ -88,38 +78,4 @@ function _getPrelude({dev}: {dev: boolean}): DependencyEdge {
};
}
async function _createEdgeFromScript(
module: Module,
options: {
dev: boolean,
enableBabelRCLookup: boolean,
hot: boolean,
projectRoot: string,
},
): Promise<DependencyEdge> {
const result = await module.read({
assetDataPlugins: [],
customTransformOptions: {},
dev: options.dev,
enableBabelRCLookup: options.enableBabelRCLookup,
hot: options.hot,
inlineRequires: false,
minify: false,
platform: undefined,
projectRoot: options.projectRoot,
});
return {
dependencies: new Map(),
inverseDependencies: new Set(),
path: module.path,
output: {
code: result.code,
map: result.map,
source: result.source,
type: 'script',
},
};
}
module.exports = getPrependedScripts;

View File

@ -238,7 +238,11 @@ class DependencyGraph extends EventEmitter {
this._haste.end();
}
getModuleForPath(entryFile: string) {
getModuleForPath(entryFile: string, isPolyfill: boolean): Module {
if (isPolyfill) {
return this._moduleCache.getPolyfillModule(entryFile);
}
if (this._helpers.isAssetFile(entryFile)) {
return this._moduleCache.getAssetModule(entryFile);
}

View File

@ -87,7 +87,7 @@ class ModuleCache {
this._roots = roots;
}
getModule(filePath: string): Module {
getModule(filePath: string) {
if (!this._moduleCache[filePath]) {
this._moduleCache[filePath] = new Module({
depGraphHelpers: this._depGraphHelpers,
@ -129,6 +129,14 @@ class ModuleCache {
return this._moduleCache[filePath];
}
getPolyfillModule(filePath: string) {
if (!this._moduleCache[filePath]) {
this._moduleCache[filePath] = this.createPolyfill({file: filePath});
}
return this._moduleCache[filePath];
}
getPackage(filePath: string): Package {
if (!this._packageCache[filePath]) {
this._packageCache[filePath] = new Package({

View File

@ -119,14 +119,6 @@ type Params = {
};
function transform({filename, options, src, plugins}: Params) {
options = options || {
assetDataPlugins: [],
platform: '',
projectRoot: '',
inlineRequires: false,
minify: false,
};
const OLD_BABEL_ENV = process.env.BABEL_ENV;
process.env.BABEL_ENV = options.dev ? 'development' : 'production';