From 77d1ca470dcc000b0f36fd000ec5395011803f40 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Tue, 15 Nov 2016 04:27:20 -0800 Subject: [PATCH] packager: JSTransformer/index.js: @flow Reviewed By: cpojer Differential Revision: D4167006 fbshipit-source-id: db0deb2262fe2c53735cb46d9de6e6da1b375180 --- react-packager/src/JSTransformer/index.js | 47 +++++++++++++++++-- .../src/JSTransformer/worker/worker.js | 16 ++++--- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/react-packager/src/JSTransformer/index.js b/react-packager/src/JSTransformer/index.js index 92c26056..ad4b7df2 100644 --- a/react-packager/src/JSTransformer/index.js +++ b/react-packager/src/JSTransformer/index.js @@ -5,7 +5,10 @@ * 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 Logger = require('../Logger'); @@ -17,6 +20,8 @@ const util = require('util'); const workerFarm = require('worker-farm'); const debug = require('debug')('ReactNativePackager:JStransformer'); +import type {Data as TransformData, Options as TransformOptions} from './worker/worker'; + // Avoid memory leaks caused in workers. This number seems to be a good enough number // to avoid any memory leak while not slowing down initial builds. // TODO(amasad): Once we get bundle splitting, we can drive this down a bit more. @@ -46,6 +51,13 @@ const validateOpts = declareOpts({ }, }); +type Options = { + transformModulePath?: ?string, + transformTimeoutInterval?: ?number, + worker?: ?string, + methods?: ?Array, +}; + const maxConcurrentWorkers = ((cores, override) => { if (override) { return Math.min(cores, override); @@ -61,7 +73,7 @@ const maxConcurrentWorkers = ((cores, override) => { return Math.floor(3 / 8 * cores + 3); // between cores *.75 and cores / 2 } return cores / 2; -})(os.cpus().length, process.env.REACT_NATIVE_MAX_WORKERS); +})(os.cpus().length, parseInt(process.env.REACT_NATIVE_MAX_WORKERS, 10)); function makeFarm(worker, methods, timeout) { return workerFarm( @@ -79,7 +91,28 @@ function makeFarm(worker, methods, timeout) { } class Transformer { - constructor(options) { + + _opts: { + transformModulePath?: ?string, + transformTimeoutInterval: number, + worker: ?string, + methods: Array, + }; + _workers: {[name: string]: mixed}; + _transformModulePath: ?string; + _transform: ( + transform: string, + filename: string, + sourceCode: string, + options: ?TransformOptions, + ) => Promise; + minify: ( + filename: string, + code: string, + sourceMap: string, + ) => Promise; + + constructor(options: Options) { const opts = this._opts = validateOpts(options); const {transformModulePath} = opts; @@ -88,6 +121,8 @@ class Transformer { this._workers = makeFarm(opts.worker, opts.methods, opts.transformTimeoutInterval); opts.methods.forEach(name => { + /* $FlowFixMe: assigning the class object fields directly is + * questionable, because it's prone to conflicts. */ this[name] = this._workers[name]; }); } @@ -108,12 +143,13 @@ class Transformer { this._workers && workerFarm.end(this._workers); } - transformFile(fileName, code, options) { + transformFile(fileName: string, code: string, options: TransformOptions) { if (!this._transform) { return Promise.reject(new Error('No transform module')); } debug('transforming file', fileName); return this + /* $FlowFixMe: _transformModulePath may be empty, see constructor */ ._transform(this._transformModulePath, fileName, code, options) .then(data => { Logger.log(data.transformFileStartLogEntry); @@ -128,13 +164,16 @@ class Transformer { `${this._opts.transformTimeoutInterval / 1000} seconds.\n` + 'You can adjust timeout via the \'transformTimeoutInterval\' option' ); + /* $FlowFixMe: monkey-patch Error */ timeoutErr.type = 'TimeoutError'; throw timeoutErr; } else if (error.type === 'ProcessTerminatedError') { const uncaughtError = new Error( 'Uncaught error in the transformer worker: ' + + /* $FlowFixMe: _transformModulePath may be empty, see constructor */ this._opts.transformModulePath ); + /* $FlowFixMe: monkey-patch Error */ uncaughtError.type = 'ProcessTerminatedError'; throw uncaughtError; } @@ -142,6 +181,8 @@ class Transformer { throw formatError(error, fileName); }); } + + static TransformError; } module.exports = Transformer; diff --git a/react-packager/src/JSTransformer/worker/worker.js b/react-packager/src/JSTransformer/worker/worker.js index 856d0ca3..52ea4b0a 100644 --- a/react-packager/src/JSTransformer/worker/worker.js +++ b/react-packager/src/JSTransformer/worker/worker.js @@ -16,6 +16,8 @@ const extractDependencies = require('./extract-dependencies'); const inline = require('./inline'); const minify = require('./minify'); +import type {LogEntry} from '../../Logger/Types'; + function makeTransformParams(filename, sourceCode, options) { if (filename.endsWith('.json')) { sourceCode = 'module.exports=' + sourceCode; @@ -36,15 +38,17 @@ type Transform = (params: { options: ?{}, }) => mixed; -type Options = {transform?: {}}; +export type Options = {transform?: {}}; + +export type Data = { + result: TransformedCode, + transformFileStartLogEntry: LogEntry, + transformFileEndLogEntry: LogEntry, +}; type Callback = ( error: ?Error, - data: ?{ - result: TransformedCode, - transformFileStartLogEntry: {}, - transformFileEndLogEntry: {}, - }, + data: ?Data, ) => mixed; function transformCode(