diff --git a/packager/src/Bundler/util.js b/packager/src/Bundler/util.js index e1b7488e7..f64aba707 100644 --- a/packager/src/Bundler/util.js +++ b/packager/src/Bundler/util.js @@ -11,6 +11,10 @@ 'use strict'; +const babel = require('babel-core'); +const babelGenerate = require('babel-generator').default; +const babylon = require('babylon'); + import type {AssetDescriptor} from '.'; const assetPropertyBlacklist = new Set([ @@ -19,18 +23,33 @@ const assetPropertyBlacklist = new Set([ 'path', ]); +const ASSET_REGISTRY_PATH = 'react-native/Libraries/Image/AssetRegistry'; + +function generateAssetCodeFileAst(assetDescriptor: AssetDescriptor): Object { + const properDescriptor = filterObject(assetDescriptor, assetPropertyBlacklist); + const descriptorAst = babylon.parseExpression(JSON.stringify(properDescriptor)); + const t = babel.types; + const moduleExports = t.memberExpression(t.identifier('module'), t.identifier('exports')); + const requireCall = + t.callExpression(t.identifier('require'), [t.stringLiteral(ASSET_REGISTRY_PATH)]); + const registerAssetFunction = t.memberExpression(requireCall, t.identifier('registerAsset')); + const registerAssetCall = t.callExpression(registerAssetFunction, [descriptorAst]); + return t.file(t.program([ + t.expressionStatement(t.assignmentExpression('=', moduleExports, registerAssetCall)), + ])); +} + function generateAssetTransformResult(assetDescriptor: AssetDescriptor): {| code: string, dependencies: Array, dependencyOffsets: Array, |} { - const properDescriptor = filterObject(assetDescriptor, assetPropertyBlacklist); - const json = JSON.stringify(properDescriptor); - const assetRegistryPath = 'react-native/Libraries/Image/AssetRegistry'; - const code = - `module.exports = require(${JSON.stringify(assetRegistryPath)}).registerAsset(${json});`; - const dependencies = [assetRegistryPath]; - const dependencyOffsets = [code.indexOf(assetRegistryPath) - 1]; + const {code} = babelGenerate( + generateAssetCodeFileAst(assetDescriptor), + {comments: false, compact: true}, + ); + const dependencies = [ASSET_REGISTRY_PATH]; + const dependencyOffsets = [code.indexOf(ASSET_REGISTRY_PATH) - 1]; return {code, dependencies, dependencyOffsets}; } @@ -50,5 +69,8 @@ function filterObject(object, blacklist) { return copied; } -exports.generateAssetTransformResult = generateAssetTransformResult; -exports.isAssetTypeAnImage = isAssetTypeAnImage; +module.exports = { + generateAssetCodeFileAst, + generateAssetTransformResult, + isAssetTypeAnImage +}; diff --git a/packager/src/ModuleGraph/worker/JsFileWrapping.js b/packager/src/ModuleGraph/worker/JsFileWrapping.js new file mode 100644 index 000000000..37021a31e --- /dev/null +++ b/packager/src/ModuleGraph/worker/JsFileWrapping.js @@ -0,0 +1,52 @@ +/** + * 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 babel = require('babel-core'); + +const MODULE_FACTORY_PARAMETERS = ['global', 'require', 'module', 'exports']; +const POLYFILL_FACTORY_PARAMETERS = ['global']; + +function wrapModule(fileAst: Object, dependencyMapName: string): Object { + const t = babel.types; + const params = MODULE_FACTORY_PARAMETERS.concat(dependencyMapName); + const factory = functionFromProgram(fileAst.program, params); + const def = t.callExpression(t.identifier('__d'), [factory]); + return t.file(t.program([t.expressionStatement(def)])); +} + +function wrapPolyfill(fileAst: Object): Object { + const t = babel.types; + const factory = functionFromProgram(fileAst.program, POLYFILL_FACTORY_PARAMETERS); + const iife = t.callExpression(factory, [t.identifier('this')]); + return t.file(t.program([t.expressionStatement(iife)])); +} + +function functionFromProgram(program: Object, parameters: Array): Object { + const t = babel.types; + return t.functionExpression( + t.identifier(''), + parameters.map(makeIdentifier), + t.blockStatement(program.body, program.directives), + ); +} + +function makeIdentifier(name: string): Object { + return babel.types.identifier(name); +} + +module.exports = { + MODULE_FACTORY_PARAMETERS, + POLYFILL_FACTORY_PARAMETERS, + wrapModule, + wrapPolyfill, +}; diff --git a/packager/src/ModuleGraph/worker/transform-module.js b/packager/src/ModuleGraph/worker/transform-module.js index e15a3993d..9e8b1010b 100644 --- a/packager/src/ModuleGraph/worker/transform-module.js +++ b/packager/src/ModuleGraph/worker/transform-module.js @@ -10,7 +10,8 @@ */ 'use strict'; -const babel = require('babel-core'); +const JsFileWrapping = require('./JsFileWrapping'); + const collectDependencies = require('./collect-dependencies'); const defaults = require('../../../defaults'); const docblock = require('../../node-haste/DependencyGraph/docblock'); @@ -38,8 +39,6 @@ export type TransformOptions = {| |}; const defaultVariants = {default: {}}; -const moduleFactoryParameters = ['global', 'require', 'module', 'exports']; -const polyfillFactoryParameters = ['global']; const ASSET_EXTENSIONS = new Set(defaults.assetExts); @@ -109,7 +108,7 @@ function transformJSON(json, options, callback) { const value = JSON.parse(json); const {filename} = options; const code = - `__d(function(${moduleFactoryParameters.join(', ')}) { module.exports = \n${ + `__d(function(${JsFileWrapping.MODULE_FACTORY_PARAMETERS.join(', ')}) { module.exports = \n${ json }\n});`; @@ -162,42 +161,14 @@ function makeResult(ast, filename, sourceCode, isPolyfill = false) { let dependencies, dependencyMapName, file; if (isPolyfill) { dependencies = []; - file = wrapPolyfill(ast); + file = JsFileWrapping.wrapPolyfill(ast); } else { ({dependencies, dependencyMapName} = collectDependencies(ast)); - file = wrapModule(ast, dependencyMapName); + file = JsFileWrapping.wrapModule(ast, dependencyMapName); } const gen = generate(file, filename, sourceCode); return {code: gen.code, map: gen.map, dependencies, dependencyMapName}; } -function wrapModule(file, dependencyMapName) { - const t = babel.types; - const params = moduleFactoryParameters.concat(dependencyMapName); - const factory = functionFromProgram(file.program, params); - const def = t.callExpression(t.identifier('__d'), [factory]); - return t.file(t.program([t.expressionStatement(def)])); -} - -function wrapPolyfill(file) { - const t = babel.types; - const factory = functionFromProgram(file.program, polyfillFactoryParameters); - const iife = t.callExpression(factory, [t.identifier('this')]); - return t.file(t.program([t.expressionStatement(iife)])); -} - -function functionFromProgram(program, parameters) { - const t = babel.types; - return t.functionExpression( - t.identifier(''), - parameters.map(makeIdentifier), - t.blockStatement(program.body, program.directives), - ); -} - -function makeIdentifier(name) { - return babel.types.identifier(name); -} - module.exports = transformModule;