packager: Resolver&co: @flow

Reviewed By: davidaurelio

Differential Revision: D4285448

fbshipit-source-id: ec9bc6fd3c6d6eae89347762bff8b5b24662394b
This commit is contained in:
Jean Lauliac 2016-12-08 05:10:37 -08:00 committed by Martin Konicek
parent 85478b56c5
commit b6478a3458
9 changed files with 122 additions and 55 deletions

View File

@ -52,7 +52,7 @@ type GeneratorOptions = {
type InlinePlugin = [string | {} | () => {}, any];
// based on https://babeljs.io/docs/usage/options/ -- 2016-11-11
type _TransformOptions = {
type __TransformOptions = {
filename?: string,
filenameRelative?: string,
presets?: Array<string | Object>,
@ -85,8 +85,8 @@ type _TransformOptions = {
extends?: string,
};
type TransformOptions =
_TransformOptions & {env?: {[key: string]: TransformOptions}};
type _TransformOptions =
__TransformOptions & {env?: {[key: string]: __TransformOptions}};
declare class _Ast {};
type TransformResult = {
ast: _Ast,
@ -98,9 +98,10 @@ type VisitFn = <State>(path: Object, state: State) => any;
declare module 'babel-core' {
declare type SourceMap = _SourceMap;
declare type Ast = _Ast;
declare type TransformOptions = _TransformOptions;
declare function transform(
code: string,
options?: TransformOptions,
options?: _TransformOptions,
): TransformResult;
declare function traverse<State>(
ast: _Ast,
@ -114,7 +115,7 @@ declare module 'babel-core' {
declare function transformFromAst(
ast: _Ast,
code?: ?string,
babelOptions?: TransformOptions,
babelOptions?: _TransformOptions,
): TransformResult;
}

View File

@ -35,9 +35,10 @@ const {
extname,
} = require('path');
import AssetServer from '../AssetServer';
import Module from '../node-haste/Module';
import ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
import type AssetServer from '../AssetServer';
import type Module from '../node-haste/Module';
import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
export type GetTransformOptions<T> = (
string,
@ -353,8 +354,6 @@ class Bundler {
? runBeforeMainModule
.map(name => modulesByName[name])
.filter(Boolean)
/* $FlowFixMe: looks like ResolutionResponse is monkey-patched
* with `getModuleId`. */
.map(response.getModuleId)
: undefined;
@ -450,7 +449,8 @@ class Bundler {
entryFilePath,
assetPlugins,
transformOptions: response.transformOptions,
getModuleId: response.getModuleId,
/* $FlowFixMe: `getModuleId` is monkey-patched */
getModuleId: (response.getModuleId: () => number),
dependencyPairs: response.getResolvedDependencyPairs(module),
}).then(transformed => {
modulesByName[transformed.name] = module;
@ -485,7 +485,7 @@ class Bundler {
generateSourceMaps = false,
}: {
entryFile: string,
platform: ?string,
platform: string,
dev?: boolean,
minify?: boolean,
hot?: boolean,
@ -528,14 +528,14 @@ class Bundler {
onProgress,
}: {
entryFile: string,
platform: ?string,
platform: string,
dev?: boolean,
minify?: boolean,
hot?: boolean,
recursive?: boolean,
generateSourceMaps?: boolean,
isolateModuleIDs?: boolean,
onProgress?: () => mixed,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
}) {
return this.getTransformOptions(
entryFile,
@ -567,7 +567,7 @@ class Bundler {
getOrderedDependencyPaths({ entryFile, dev, platform }: {
entryFile: string,
dev: boolean,
platform: ?string,
platform: string,
}) {
return this.getDependencies({entryFile, dev, platform}).then(
({ dependencies }) => {
@ -608,7 +608,15 @@ class Bundler {
getModuleId,
dependencyPairs,
assetPlugins,
}) {
}: {
module: Module,
bundle: Bundle,
entryFilePath: string,
transformOptions: TransformOptions,
getModuleId: () => number,
dependencyPairs: Array<[mixed, {path: string}]>,
assetPlugins: Array<string>,
}): Promise<ModuleTransport> {
let moduleTransport;
const moduleId = getModuleId(module);
@ -670,7 +678,9 @@ class Bundler {
__packager_asset: true,
fileSystemLocation: pathDirname(module.path),
httpServerLocation: assetUrlPath,
/* $FlowFixMe: `resolution` is assets-only */
width: dimensions ? dimensions.width / module.resolution : undefined,
/* $FlowFixMe: `resolution` is assets-only */
height: dimensions ? dimensions.height / module.resolution : undefined,
scales: assetData.scales,
files: assetData.files,
@ -718,9 +728,9 @@ class Bundler {
}
_generateAssetModule(
bundle,
module,
moduleId,
bundle: Bundle,
module: Module,
moduleId: number,
assetPlugins: Array<string> = [],
platform: ?string = null,
) {
@ -745,7 +755,7 @@ class Bundler {
mainModuleName: string,
options: {
dev?: boolean,
platform: ?string,
platform: string,
hot?: boolean,
generateSourceMaps?: boolean,
},

View File

@ -18,7 +18,7 @@ const invariant = require('invariant');
const minify = require('./minify');
import type {LogEntry} from '../../Logger/Types';
import type {Ast, SourceMap} from 'babel-core';
import type {Ast, SourceMap, TransformOptions} from 'babel-core';
function makeTransformParams(filename, sourceCode, options) {
if (filename.endsWith('.json')) {
@ -31,7 +31,7 @@ export type TransformedCode = {
code: string,
dependencies: Array<string>,
dependencyOffsets: Array<number>,
map?: ?{},
map?: ?SourceMap,
};
type Transform = (
@ -47,7 +47,13 @@ type Transform = (
) => void;
export type Options = {
transform?: {projectRoots: Array<string>},
transform: {
projectRoots: Array<string>,
ramGroups: Array<string>,
platform: string,
preloadedModules: Array<string>,
} & TransformOptions,
platform: string,
};
export type Data = {
@ -132,7 +138,7 @@ exports.transformAndExtractDependencies = (
transform: string,
filename: string,
sourceCode: string,
options: ?Options,
options: Options,
callback: Callback,
) => {
/* $FlowFixMe: impossible to type a dynamic require */

View File

@ -5,9 +5,11 @@
* 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';
'use strict';
const DependencyGraph = require('../node-haste');
@ -15,6 +17,11 @@ const declareOpts = require('../lib/declareOpts');
const defaults = require('../../../defaults');
const pathJoin = require('path').join;
import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
import type Module from '../node-haste/Module';
import type {SourceMap} from '../lib/SourceMap';
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
const validateOpts = declareOpts({
projectRoots: {
type: 'array',
@ -87,7 +94,12 @@ const getDependenciesValidateOpts = declareOpts({
class Resolver {
constructor(options) {
_depGraph: DependencyGraph;
_minifyCode: (filePath: string, code: string, map: SourceMap) =>
Promise<{code: string, map: SourceMap}>;
_polyfillModuleNames: Array<string>;
constructor(options: {resetCache: boolean}) {
const opts = validateOpts(options);
this._depGraph = new DependencyGraph({
@ -122,15 +134,24 @@ class Resolver {
});
}
getShallowDependencies(entryFile, transformOptions) {
getShallowDependencies(
entryFile: string,
transformOptions: TransformOptions,
): Array<string> {
return this._depGraph.getShallowDependencies(entryFile, transformOptions);
}
getModuleForPath(entryFile) {
getModuleForPath(entryFile: string): Module {
return this._depGraph.getModuleForPath(entryFile);
}
getDependencies(entryPath, options, transformOptions, onProgress, getModuleId) {
getDependencies(
entryPath: string,
options: {},
transformOptions: TransformOptions,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
getModuleId: mixed,
): Promise<ResolutionResponse> {
const {platform, recursive} = getDependenciesValidateOpts(options);
return this._depGraph.getDependencies({
entryPath,
@ -148,7 +169,7 @@ class Resolver {
});
}
getModuleSystemDependencies(options) {
getModuleSystemDependencies(options: {}): Array<Module> {
const opts = getDependenciesValidateOpts(options);
const prelude = opts.dev
@ -167,7 +188,7 @@ class Resolver {
}));
}
_getPolyfillDependencies() {
_getPolyfillDependencies(): Array<Module> {
const polyfillModuleNames = defaults.polyfills.concat(this._polyfillModuleNames);
return polyfillModuleNames.map(
@ -179,7 +200,12 @@ class Resolver {
);
}
resolveRequires(resolutionResponse, module, code, dependencyOffsets = []) {
resolveRequires(
resolutionResponse: ResolutionResponse,
module: Module,
code: string,
dependencyOffsets: Array<number> = [],
): string {
const resolvedDeps = Object.create(null);
// here, we build a map of all require strings (relative and absolute)
@ -187,6 +213,7 @@ class Resolver {
resolutionResponse.getResolvedDependencyPairs(module)
.forEach(([depName, depModule]) => {
if (depModule) {
/* $FlowFixMe: `getModuleId` is monkey-patched so may not exist */
resolvedDeps[depName] = resolutionResponse.getModuleId(depModule);
}
});
@ -204,7 +231,7 @@ class Resolver {
? `${JSON.stringify(resolvedDeps[depName])} /* ${depName} */`
: codeMatch;
code = dependencyOffsets.reduceRight((codeBits, offset) => {
const codeParts = dependencyOffsets.reduceRight((codeBits, offset) => {
const first = codeBits.shift();
codeBits.unshift(
first.slice(0, offset),
@ -213,7 +240,7 @@ class Resolver {
return codeBits;
}, [code]);
return code.join('');
return codeParts.join('');
}
wrapModule({
@ -225,6 +252,17 @@ class Resolver {
meta = {},
dev = true,
minify = false,
}: {
resolutionResponse: ResolutionResponse,
module: Module,
name: string,
map: SourceMap,
code: string,
meta?: {
dependencyOffsets?: Array<number>,
},
dev?: boolean,
minify?: boolean,
}) {
if (module.isJSON()) {
code = `module.exports = ${code}`;
@ -233,6 +271,7 @@ class Resolver {
if (module.isPolyfill()) {
code = definePolyfillCode(code);
} else {
/* $FlowFixMe: `getModuleId` is monkey-patched so may not exist */
const moduleId = resolutionResponse.getModuleId(module);
code = this.resolveRequires(
resolutionResponse,
@ -243,17 +282,18 @@ class Resolver {
code = defineModuleCode(moduleId, code, name, dev);
}
return minify
? this._minifyCode(module.path, code, map)
: Promise.resolve({code, map});
}
minifyModule({path, code, map}) {
minifyModule(
{path, code, map}: {path: string, code: string, map: SourceMap},
): Promise<{code: string, map: SourceMap}> {
return this._minifyCode(path, code, map);
}
getDependencyGraph() {
getDependencyGraph(): DependencyGraph {
return this._depGraph;
}
}

View File

@ -29,6 +29,7 @@ const CACHE_NAME = 'react-native-packager-cache';
type CacheFilePaths = {transformedCode: string, metadata: string};
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
import type {SourceMap} from './SourceMap';
/**
* If packager is running for two different directories, we don't want the
@ -79,7 +80,7 @@ export type CachedResult = {
code: string,
dependencies: Array<string>,
dependencyOffsets: Array<number>,
map?: ?{},
map?: ?SourceMap,
};
/**
@ -227,7 +228,7 @@ function readMetadataFileSync(
cachedSourceHash: number,
dependencies: Array<string>,
dependencyOffsets: Array<number>,
sourceMap: ?{},
sourceMap: ?SourceMap,
} {
const metadataStr = fs.readFileSync(metadataFilePath, 'utf8');
let metadata;

View File

@ -124,7 +124,7 @@ class ResolutionRequest {
}: {
response: ResolutionResponse,
transformOptions: Object,
onProgress: () => void,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
recursive: boolean,
}) {
const entry = this._moduleCache.getModule(this._entryPath);

View File

@ -13,21 +13,26 @@
import Module from '../Module';
import type {Options as TransformOptions} from '../../JSTransformer/worker/worker';
const NO_OPTIONS = {};
class ResolutionResponse {
transformOptions: {};
transformOptions: TransformOptions;
dependencies: Array<Module>;
mainModuleId: ?(number | string);
mocks: mixed;
numPrependedDependencies: number;
// This is monkey-patched from Resolver.
getModuleId: ?() => number;
_mappings: {};
_finalized: boolean;
_mainModule: ?Module;
constructor({transformOptions}: {transformOptions: {}}) {
constructor({transformOptions}: {transformOptions: TransformOptions}) {
this.transformOptions = transformOptions;
this.dependencies = [];
this.mainModuleId = null;
@ -76,7 +81,7 @@ class ResolutionResponse {
}
}
finalize() {
finalize(): ResolutionResponse {
/* $FlowFixMe: _mainModule is not initialized in the constructor. */
return this._mainModule.getName().then(id => {
this.mainModuleId = id;

View File

@ -25,16 +25,18 @@ const jsonStableStringify = require('json-stable-stringify');
const {join: joinPath, relative: relativePath, extname} = require('path');
import type {TransformedCode, Options as TransformOptions} from '../JSTransformer/worker/worker';
import type {SourceMap} from '../lib/SourceMap';
import type {ReadTransformProps} from '../lib/TransformCache';
import type Cache from './Cache';
import type DependencyGraphHelpers from './DependencyGraph/DependencyGraphHelpers';
import type ModuleCache from './ModuleCache';
type ReadResult = {
code?: string,
code: string,
dependencies?: ?Array<string>,
dependencyOffsets?: ?Array<number>,
map?: ?{},
map?: ?SourceMap,
source: string,
};
export type TransformCode = (
@ -122,7 +124,7 @@ class Module {
return this.read(transformOptions).then(({map}) => map);
}
getName(): Promise<string | number> {
getName(): Promise<string> {
return this._cache.get(
this.path,
'name',
@ -209,9 +211,10 @@ class Module {
id?: string,
extern: boolean,
result: TransformedCode,
) {
): ReadResult {
if (this._options.cacheTransformResults === false) {
const {dependencies} = result;
/* $FlowFixMe: this code path is dead, remove. */
return {dependencies};
}
return {...result, id, source};

View File

@ -38,6 +38,7 @@ const {
print,
} = require('../Logger');
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
import type {
Options as ModuleOptions,
TransformCode,
@ -53,7 +54,7 @@ class DependencyGraph {
extraNodeModules: Object,
forceNodeFilesystemAPI: boolean,
ignoreFilePath: (filePath: string) => boolean,
maxWorkers: number,
maxWorkers: ?number,
mocksPattern: mixed,
moduleOptions: ModuleOptions,
platforms: Set<string>,
@ -103,22 +104,22 @@ class DependencyGraph {
assetDependencies: mixed,
assetExts: Array<string>,
cache: Cache,
extensions: Array<string>,
extensions?: ?Array<string>,
extraNodeModules: Object,
forceNodeFilesystemAPI?: boolean,
ignoreFilePath: (filePath: string) => boolean,
maxWorkers: number,
mocksPattern: mixed,
maxWorkers?: ?number,
mocksPattern?: mixed,
moduleOptions: ?ModuleOptions,
platforms: mixed,
preferNativePlatform: boolean,
providesModuleNodeModules: Array<string>,
resetCache: boolean,
roots: Array<string>,
shouldThrowOnUnresolvedErrors: () => boolean,
shouldThrowOnUnresolvedErrors?: () => boolean,
transformCacheKey: string,
transformCode: TransformCode,
useWatchman: boolean,
useWatchman?: ?boolean,
watch: boolean,
}) {
this._opts = {
@ -272,8 +273,8 @@ class DependencyGraph {
}: {
entryPath: string,
platform: string,
transformOptions: {},
onProgress: () => void,
transformOptions: TransformOptions,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
recursive: boolean,
}) {
return this.load().then(() => {