diff --git a/react-packager/src/Bundler/Bundle.js b/react-packager/src/Bundler/Bundle.js index 04a2e1ae..e457e203 100644 --- a/react-packager/src/Bundler/Bundle.js +++ b/react-packager/src/Bundler/Bundle.js @@ -40,10 +40,10 @@ class Bundle extends BundleBase { response, module, transformed.code - ).then(({code, name}) => { + ).then(({code, id}) => { const moduleTransport = new ModuleTransport({ code, - name, + name: id, map: transformed.map, sourceCode: transformed.sourceCode, sourcePath: transformed.sourcePath, @@ -75,7 +75,7 @@ class Bundle extends BundleBase { } _addRequireCall(moduleId) { - const code = ';require("' + moduleId + '");'; + const code = `;require(${JSON.stringify(moduleId)});`; const name = 'require-' + moduleId; super.addModule(new ModuleTransport({ name, diff --git a/react-packager/src/Bundler/__tests__/Bundler-test.js b/react-packager/src/Bundler/__tests__/Bundler-test.js index 467cf90d..a85695be 100644 --- a/react-packager/src/Bundler/__tests__/Bundler-test.js +++ b/react-packager/src/Bundler/__tests__/Bundler-test.js @@ -10,16 +10,23 @@ jest .setMock('worker-farm', () => () => undefined) + .dontMock('absolute-path') .dontMock('underscore') .dontMock('../../lib/ModuleTransport') + .dontMock('../../DependencyResolver/AssetModule') + .dontMock('../../DependencyResolver/Module') + .dontMock('../../DependencyResolver/lib/getAssetDataFromName') .setMock('uglify-js') .dontMock('../'); jest.mock('fs'); +var AssetModule = require('../../DependencyResolver/AssetModule'); var Bundler = require('../'); var JSTransformer = require('../../JSTransformer'); +var Module = require('../../DependencyResolver/Module'); var Resolver = require('../../Resolver'); + var sizeOf = require('image-size'); var fs = require('fs'); @@ -34,6 +41,14 @@ describe('Bundler', function() { isJSON, resolution, }) { + if (isAsset) { + const module = new AssetModule({ + file: path, + cache: {get: () => Promise.resolve(path)} + }); + module.getName = () => Promise.resolve(id); + return module; + } return { path, resolution, @@ -51,6 +66,8 @@ describe('Bundler', function() { var bundler; var assetServer; var modules; + const width = 50; + const height = 100; beforeEach(function() { getDependencies = jest.genMockFn(); @@ -108,10 +125,12 @@ describe('Bundler', function() { }), ]; + const mainModule = new Module({file: '/root/foo'}); getDependencies.mockImpl(function() { return Promise.resolve({ mainModuleId: 'foo', - dependencies: modules + dependencies: modules, + getMainModule: () => mainModule, }); }); @@ -132,12 +151,13 @@ describe('Bundler', function() { wrapModule.mockImpl(function(response, module, code) { return module.getName().then(name => ({ name, + id: name, code: 'lol ' + code + ' lol' })); }); sizeOf.mockImpl(function(path, cb) { - cb(null, { width: 50, height: 100 }); + cb(null, { width, height }); }); }); @@ -187,8 +207,8 @@ describe('Bundler', function() { __packager_asset: true, fileSystemLocation: '/root/img', httpServerLocation: '/assets/img', - width: 25, - height: 50, + width, + height, scales: [1, 2, 3], files: [ '/root/img/img.png', diff --git a/react-packager/src/Bundler/index.js b/react-packager/src/Bundler/index.js index 1cc28f23..9b7bb1fa 100644 --- a/react-packager/src/Bundler/index.js +++ b/react-packager/src/Bundler/index.js @@ -102,6 +102,8 @@ class Bundler { mtime = ''; } + this._getModuleId = createModuleIdGetter(); + this._cache = new Cache({ resetCache: opts.resetCache, cacheKey: [ @@ -122,6 +124,7 @@ class Bundler { fileWatcher: opts.fileWatcher, assetExts: opts.assetExts, cache: this._cache, + getModuleId: this._getModuleId, }); this._bundlesLayout = new BundlesLayout({ @@ -187,9 +190,19 @@ class Bundler { const findEventId = Activity.startEvent('find dependencies'); let transformEventId; + if (isDev) { + // `require` calls int the require polyfill itself are not analyzed and + // replaced so that they use numeric module IDs. Therefore, we include + // the Systrace module before any other module, and it will set itself + // as property on the require function. + // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686) + runBeforeMainModule = ['Systrace'].concat(runBeforeMainModule); + } + + const modulesByName = Object.create(null); return this.getDependencies(entryFile, isDev, platform).then((response) => { Activity.endEvent(findEventId); - bundle.setMainModuleId(response.mainModuleId); + bundle.setMainModuleId(this._getModuleId(response.getMainModule())); transformEventId = Activity.startEvent('transform'); const moduleSystemDeps = includeSystemDependencies @@ -225,6 +238,11 @@ class Bundler { platform, hot, ).then(transformed => { + return module.getName().then(name => { + modulesByName[name] = module; + return transformed; + }); + }).then(transformed => { if (bar) { bar.tick(); } @@ -248,7 +266,11 @@ class Bundler { )); }).then(() => { Activity.endEvent(transformEventId); - bundle.finalize({runBeforeMainModule, runMainModule}); + const runBeforeIds = runBeforeMainModule + .map(name => modulesByName[name]) + .filter(Boolean) + .map(this._getModuleId, this); + bundle.finalize({runBeforeMainModule: runBeforeIds, runMainModule}); return bundle; }); } @@ -462,8 +484,7 @@ class Bundler { type: assetData.type, }; - const ASSET_TEMPLATE = 'module.exports = require("AssetRegistry").registerAsset(%json);'; - const code = ASSET_TEMPLATE.replace('%json', JSON.stringify(asset)); + const code = module.getCode(asset); return {asset, code}; }); @@ -522,12 +543,21 @@ function verifyRootExists(root) { assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory'); } -class DummyCache { - get(filepath, field, loaderCb) { - return loaderCb(); - } - end(){} - invalidate(filepath){} +function createModuleIdGetter() { + const fileToIdMap = Object.create(null); + let nextId = 0; + return ( + ({path}) => { + if (!(path in fileToIdMap)) { + // can't be a number for now, since we also replace in import / export + // we can change that when we eventually change to analyzing dependencies + // on transformed modules + fileToIdMap[path] = String(nextId++); + } + return fileToIdMap[path]; + } + ); } + module.exports = Bundler; diff --git a/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js b/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js index fe4481a0..b18b424f 100644 --- a/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js +++ b/react-packager/src/BundlesLayout/__tests__/BundlesLayoutIntegration-test.js @@ -55,6 +55,7 @@ describe('BundlesLayout', () => { cache: new Cache(), assetExts: ['js', 'png'], assetRoots: ['/root'], + getModuleId: () => {}, }); return new BundlesLayout({ diff --git a/react-packager/src/DependencyResolver/AssetModule.js b/react-packager/src/DependencyResolver/AssetModule.js index f5555fac..68a92ee2 100644 --- a/react-packager/src/DependencyResolver/AssetModule.js +++ b/react-packager/src/DependencyResolver/AssetModule.js @@ -18,13 +18,19 @@ class AssetModule extends Module { } getDependencies() { - return Promise.resolve([]); + return Promise.resolve(['AssetRegistry']); } getAsyncDependencies() { return Promise.resolve([]); } + getCode(assetData) { + return `module.exports = require('AssetRegistry').registerAsset(${ + JSON.stringify(assetData) + });`; + } + read() { return Promise.resolve({}); } diff --git a/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js b/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js index 7fbafde8..3c1656c5 100644 --- a/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js +++ b/react-packager/src/DependencyResolver/DependencyGraph/ResolutionResponse.js @@ -39,6 +39,11 @@ class ResolutionResponse { }); } + getMainModule() { + this._assertFinalized(); + return this._mainModule; + } + pushDependency(module) { this._assertNotFinalized(); if (this.dependencies.length === 0) { diff --git a/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js b/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js index b1126a4c..a858f1d2 100644 --- a/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js +++ b/react-packager/src/DependencyResolver/DependencyGraph/__tests__/DependencyGraph-test.js @@ -374,7 +374,7 @@ describe('DependencyGraph', function() { { id: 'rootPackage/imgs/a.png', path: '/root/imgs/a.png', - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, resolution: 1, isAsset_DEPRECATED: false, @@ -434,7 +434,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/a.png', path: '/root/imgs/a@1.5x.png', resolution: 1.5, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -444,7 +444,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/b.png', path: '/root/imgs/b@.7x.png', resolution: 0.7, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -454,7 +454,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/c.png', path: '/root/imgs/c.png', resolution: 1, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -514,7 +514,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/a.png', path: '/root/imgs/a@1.5x.ios.png', resolution: 1.5, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -524,7 +524,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/b.png', path: '/root/imgs/b@.7x.ios.png', resolution: 0.7, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -534,7 +534,7 @@ describe('DependencyGraph', function() { id: 'rootPackage/imgs/c.png', path: '/root/imgs/c.ios.png', resolution: 1, - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, isAsset_DEPRECATED: false, isJSON: false, @@ -585,7 +585,7 @@ describe('DependencyGraph', function() { { id: 'rootPackage/imgs/a.png', path: '/root/imgs/a.png', - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, resolution: 1, isAsset_DEPRECATED: false, @@ -3367,7 +3367,7 @@ describe('DependencyGraph', function() { { id: 'aPackage/foo.png', path: '/root/foo.png', - dependencies: [], + dependencies: ['AssetRegistry'], isAsset: true, resolution: 1, isAsset_DEPRECATED: false, diff --git a/react-packager/src/DependencyResolver/lib/replacePatterns.js b/react-packager/src/DependencyResolver/lib/replacePatterns.js index a4e563d2..3bd6ef45 100644 --- a/react-packager/src/DependencyResolver/lib/replacePatterns.js +++ b/react-packager/src/DependencyResolver/lib/replacePatterns.js @@ -9,7 +9,7 @@ 'use strict'; -exports.IMPORT_RE = /(\bimport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g; -exports.EXPORT_RE = /(\bexport\s+(?:[^'"]+\s+from\s+)??)(['"])([^'"]+)(\2)/g; -exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g; -exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g; +exports.IMPORT_RE = /(\bimport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g; +exports.EXPORT_RE = /(\bexport\s*(?:[\s{][^'"]+[\s}]from\s*)??)(['"])([^'"]+)\2()/g; +exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g; +exports.SYSTEM_IMPORT_RE = /(\bSystem\.import\s*?\(\s*?)(['"])([^'"]+)\2(\s*?\))/g; diff --git a/react-packager/src/Resolver/__tests__/Resolver-test.js b/react-packager/src/Resolver/__tests__/Resolver-test.js index 825399b4..6093cf42 100644 --- a/react-packager/src/Resolver/__tests__/Resolver-test.js +++ b/react-packager/src/Resolver/__tests__/Resolver-test.js @@ -35,6 +35,12 @@ describe('Resolver', function() { }); }); + const modulesWithIds = []; + function getModuleId(module) { + const index = modulesWithIds.indexOf(module); + return String(index !== -1 ? index + 1 : modulesWithIds.push(module)); + } + class ResolutionResponseMock { constructor({dependencies, mainModuleId, asyncDependencies}) { this.dependencies = dependencies; @@ -73,6 +79,7 @@ describe('Resolver', function() { var depResolver = new Resolver({ projectRoot: '/root', + getModuleId, }); DependencyGraph.prototype.getDependencies.mockImpl(function() { @@ -160,6 +167,7 @@ describe('Resolver', function() { var depResolver = new Resolver({ projectRoot: '/root', + getModuleId, }); DependencyGraph.prototype.getDependencies.mockImpl(function() { @@ -187,6 +195,7 @@ describe('Resolver', function() { var depResolver = new Resolver({ projectRoot: '/root', polyfillModuleNames: ['some module'], + getModuleId, }); DependencyGraph.prototype.getDependencies.mockImpl(function() { @@ -223,12 +232,13 @@ describe('Resolver', function() { pit('should resolve modules', function() { var depResolver = new Resolver({ projectRoot: '/root', + getModuleId, }); - var dependencies = ['x', 'y', 'z', 'a', 'b']; + const magicJoiner = '\n\n\n'; /*eslint-disable */ - var code = [ + const testCases = [ // single line import "import'x';", "import 'x';", @@ -303,6 +313,7 @@ describe('Resolver', function() { 'import * as All from "x";', 'import { } from "x";', 'import { Foo } from "x";', + 'import{Foo}from"x";', 'import { Foo, } from "x";', 'import { Foo as Bar } from "x";', 'import { Foo as Bar, } from "x";', @@ -428,6 +439,7 @@ describe('Resolver', function() { "export { } from 'x';", "export {Foo} from 'x';", "export { Foo } from 'x';", + "export{Foo}from'x';", "export { Foo, } from 'x';", "export {Foo as Bar} from 'x';", "export { Foo as Bar } from 'x';", @@ -613,8 +625,9 @@ describe('Resolver', function() { 'require( \'z\' )', 'require( "a")', 'require("b" )', - ].join('\n'); + ] /*eslint-disable */ + const code = testCases.join(magicJoiner); const module = createModule('test module', ['x', 'y']); @@ -624,11 +637,21 @@ describe('Resolver', function() { asyncDependencies: [], }); - resolutionResponse.getResolvedDependencyPairs = (module) => { - return [ - ['x', createModule('changed')], - ['y', createModule('Y')], - ]; + const pairs = [ + ['x', createModule('changed')], + ['y', createModule('Y')], + ]; + resolutionResponse.getResolvedDependencyPairs = () => pairs; + + function makeExpected(code) { + return pairs + .reduce((code, [id, module]) => + code.replace( + RegExp(`(['"])${id}\\1`), + (_, quot) => `${quot}${getModuleId(module)}${quot} /* ${id} */` + ), + code + ); } return depResolver.wrapModule( @@ -637,395 +660,20 @@ describe('Resolver', function() { code ).then(processedCode => { expect(processedCode.name).toEqual('test module'); - expect(processedCode.code).toEqual([ - '__d(\'test module\',function(global, require,' + - ' module, exports) { ' + - // single line import - "import'x';", - "import 'changed';", - "import 'changed' ;", - "import Default from 'changed';", - "import * as All from 'changed';", - "import {} from 'changed';", - "import { } from 'changed';", - "import {Foo} from 'changed';", - "import { Foo } from 'changed';", - "import { Foo, } from 'changed';", - "import {Foo as Bar} from 'changed';", - "import { Foo as Bar } from 'changed';", - "import { Foo as Bar, } from 'changed';", - "import { Foo, Bar } from 'changed';", - "import { Foo, Bar, } from 'changed';", - "import { Foo as Bar, Baz } from 'changed';", - "import { Foo as Bar, Baz, } from 'changed';", - "import { Foo, Bar as Baz } from 'changed';", - "import { Foo, Bar as Baz, } from 'changed';", - "import { Foo as Bar, Baz as Qux } from 'changed';", - "import { Foo as Bar, Baz as Qux, } from 'changed';", - "import { Foo, Bar, Baz } from 'changed';", - "import { Foo, Bar, Baz, } from 'changed';", - "import { Foo as Bar, Baz, Qux } from 'changed';", - "import { Foo as Bar, Baz, Qux, } from 'changed';", - "import { Foo, Bar as Baz, Qux } from 'changed';", - "import { Foo, Bar as Baz, Qux, } from 'changed';", - "import { Foo, Bar, Baz as Qux } from 'changed';", - "import { Foo, Bar, Baz as Qux, } from 'changed';", - "import { Foo as Bar, Baz as Qux, Norf } from 'changed';", - "import { Foo as Bar, Baz as Qux, Norf, } from 'changed';", - "import { Foo as Bar, Baz, Qux as Norf } from 'changed';", - "import { Foo as Bar, Baz, Qux as Norf, } from 'changed';", - "import { Foo, Bar as Baz, Qux as Norf } from 'changed';", - "import { Foo, Bar as Baz, Qux as Norf, } from 'changed';", - "import { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';", - "import { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';", - "import Default, * as All from 'changed';", - "import Default, { } from 'changed';", - "import Default, { Foo } from 'changed';", - "import Default, { Foo, } from 'changed';", - "import Default, { Foo as Bar } from 'changed';", - "import Default, { Foo as Bar, } from 'changed';", - "import Default, { Foo, Bar } from 'changed';", - "import Default, { Foo, Bar, } from 'changed';", - "import Default, { Foo as Bar, Baz } from 'changed';", - "import Default, { Foo as Bar, Baz, } from 'changed';", - "import Default, { Foo, Bar as Baz } from 'changed';", - "import Default, { Foo, Bar as Baz, } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux, } from 'changed';", - "import Default, { Foo, Bar, Baz } from 'changed';", - "import Default, { Foo, Bar, Baz, } from 'changed';", - "import Default, { Foo as Bar, Baz, Qux } from 'changed';", - "import Default, { Foo as Bar, Baz, Qux, } from 'changed';", - "import Default, { Foo, Bar as Baz, Qux } from 'changed';", - "import Default, { Foo, Bar as Baz, Qux, } from 'changed';", - "import Default, { Foo, Bar, Baz as Qux } from 'changed';", - "import Default, { Foo, Bar, Baz as Qux, } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';", - "import Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';", - "import Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';", - "import Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';", - "import Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';", - "import Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';", - "import Default , { } from 'changed';", - 'import "changed";', - 'import Default from "changed";', - 'import * as All from "changed";', - 'import { } from "changed";', - 'import { Foo } from "changed";', - 'import { Foo, } from "changed";', - 'import { Foo as Bar } from "changed";', - 'import { Foo as Bar, } from "changed";', - 'import { Foo, Bar } from "changed";', - 'import { Foo, Bar, } from "changed";', - 'import { Foo as Bar, Baz } from "changed";', - 'import { Foo as Bar, Baz, } from "changed";', - 'import { Foo, Bar as Baz } from "changed";', - 'import { Foo, Bar as Baz, } from "changed";', - 'import { Foo as Bar, Baz as Qux } from "changed";', - 'import { Foo as Bar, Baz as Qux, } from "changed";', - 'import { Foo, Bar, Baz } from "changed";', - 'import { Foo, Bar, Baz, } from "changed";', - 'import { Foo as Bar, Baz, Qux } from "changed";', - 'import { Foo as Bar, Baz, Qux, } from "changed";', - 'import { Foo, Bar as Baz, Qux } from "changed";', - 'import { Foo, Bar as Baz, Qux, } from "changed";', - 'import { Foo, Bar, Baz as Qux } from "changed";', - 'import { Foo, Bar, Baz as Qux, } from "changed";', - 'import { Foo as Bar, Baz as Qux, Norf } from "changed";', - 'import { Foo as Bar, Baz as Qux, Norf, } from "changed";', - 'import { Foo as Bar, Baz, Qux as Norf } from "changed";', - 'import { Foo as Bar, Baz, Qux as Norf, } from "changed";', - 'import { Foo, Bar as Baz, Qux as Norf } from "changed";', - 'import { Foo, Bar as Baz, Qux as Norf, } from "changed";', - 'import { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";', - 'import { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";', - 'import Default, * as All from "changed";', - 'import Default, { } from "changed";', - 'import Default, { Foo } from "changed";', - 'import Default, { Foo, } from "changed";', - 'import Default, { Foo as Bar } from "changed";', - 'import Default, { Foo as Bar, } from "changed";', - 'import Default, { Foo, Bar } from "changed";', - 'import Default, { Foo, Bar, } from "changed";', - 'import Default, { Foo as Bar, Baz } from "changed";', - 'import Default, { Foo as Bar, Baz, } from "changed";', - 'import Default, { Foo, Bar as Baz } from "changed";', - 'import Default, { Foo, Bar as Baz, } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux, } from "changed";', - 'import Default, { Foo, Bar, Baz } from "changed";', - 'import Default, { Foo, Bar, Baz, } from "changed";', - 'import Default, { Foo as Bar, Baz, Qux } from "changed";', - 'import Default, { Foo as Bar, Baz, Qux, } from "changed";', - 'import Default, { Foo, Bar as Baz, Qux } from "changed";', - 'import Default, { Foo, Bar as Baz, Qux, } from "changed";', - 'import Default, { Foo, Bar, Baz as Qux } from "changed";', - 'import Default, { Foo, Bar, Baz as Qux, } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux, Norf } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";', - 'import Default, { Foo as Bar, Baz, Qux as Norf } from "changed";', - 'import Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";', - 'import Default, { Foo, Bar as Baz, Qux as Norf } from "changed";', - 'import Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";', - 'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";', - 'import Default from "Y";', - 'import * as All from \'z\';', - // import with support for new lines - "import { Foo,\n Bar }\n from 'changed';", - "import { \nFoo,\nBar,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz\n }\n from 'changed';", - "import { \nFoo as Bar,\n Baz\n, }\n from 'changed';", - "import { Foo,\n Bar as Baz\n }\n from 'changed';", - "import { Foo,\n Bar as Baz,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';", - "import { Foo,\n Bar,\n Baz }\n from 'changed';", - "import { Foo,\n Bar,\n Baz,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';", - "import { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';", - "import { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';", - "import { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';", - "import { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';", - "import { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';", - "import { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';", - "import { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';", - "import { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';", - "import { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';", - "import Default,\n * as All from 'changed';", - "import Default,\n { } from 'changed';", - "import Default,\n { Foo\n }\n from 'changed';", - "import Default,\n { Foo,\n }\n from 'changed';", - "import Default,\n { Foo as Bar\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar\n } from\n 'changed';", - "import Default,\n { Foo,\n Bar,\n } from\n 'changed';", - "import Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';", - "import Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';", - "import Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';", - "import Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';", - "import Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';", - "import Default\n , { } from 'changed';", - // single line export - "export'x';", - "export 'changed';", - "export 'changed' ;", - "export Default from 'changed';", - "export * as All from 'changed';", - "export {} from 'changed';", - "export { } from 'changed';", - "export {Foo} from 'changed';", - "export { Foo } from 'changed';", - "export { Foo, } from 'changed';", - "export {Foo as Bar} from 'changed';", - "export { Foo as Bar } from 'changed';", - "export { Foo as Bar, } from 'changed';", - "export { Foo, Bar } from 'changed';", - "export { Foo, Bar, } from 'changed';", - "export { Foo as Bar, Baz } from 'changed';", - "export { Foo as Bar, Baz, } from 'changed';", - "export { Foo, Bar as Baz } from 'changed';", - "export { Foo, Bar as Baz, } from 'changed';", - "export { Foo as Bar, Baz as Qux } from 'changed';", - "export { Foo as Bar, Baz as Qux, } from 'changed';", - "export { Foo, Bar, Baz } from 'changed';", - "export { Foo, Bar, Baz, } from 'changed';", - "export { Foo as Bar, Baz, Qux } from 'changed';", - "export { Foo as Bar, Baz, Qux, } from 'changed';", - "export { Foo, Bar as Baz, Qux } from 'changed';", - "export { Foo, Bar as Baz, Qux, } from 'changed';", - "export { Foo, Bar, Baz as Qux } from 'changed';", - "export { Foo, Bar, Baz as Qux, } from 'changed';", - "export { Foo as Bar, Baz as Qux, Norf } from 'changed';", - "export { Foo as Bar, Baz as Qux, Norf, } from 'changed';", - "export { Foo as Bar, Baz, Qux as Norf } from 'changed';", - "export { Foo as Bar, Baz, Qux as Norf, } from 'changed';", - "export { Foo, Bar as Baz, Qux as Norf } from 'changed';", - "export { Foo, Bar as Baz, Qux as Norf, } from 'changed';", - "export { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';", - "export { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';", - "export Default, * as All from 'changed';", - "export Default, { } from 'changed';", - "export Default, { Foo } from 'changed';", - "export Default, { Foo, } from 'changed';", - "export Default, { Foo as Bar } from 'changed';", - "export Default, { Foo as Bar, } from 'changed';", - "export Default, { Foo, Bar } from 'changed';", - "export Default, { Foo, Bar, } from 'changed';", - "export Default, { Foo as Bar, Baz } from 'changed';", - "export Default, { Foo as Bar, Baz, } from 'changed';", - "export Default, { Foo, Bar as Baz } from 'changed';", - "export Default, { Foo, Bar as Baz, } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux, } from 'changed';", - "export Default, { Foo, Bar, Baz } from 'changed';", - "export Default, { Foo, Bar, Baz, } from 'changed';", - "export Default, { Foo as Bar, Baz, Qux } from 'changed';", - "export Default, { Foo as Bar, Baz, Qux, } from 'changed';", - "export Default, { Foo, Bar as Baz, Qux } from 'changed';", - "export Default, { Foo, Bar as Baz, Qux, } from 'changed';", - "export Default, { Foo, Bar, Baz as Qux } from 'changed';", - "export Default, { Foo, Bar, Baz as Qux, } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';", - "export Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';", - "export Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';", - "export Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';", - "export Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';", - "export Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';", - "export Default , { } from 'changed';", - 'export "changed";', - 'export Default from "changed";', - 'export * as All from "changed";', - 'export { } from "changed";', - 'export { Foo } from "changed";', - 'export { Foo, } from "changed";', - 'export { Foo as Bar } from "changed";', - 'export { Foo as Bar, } from "changed";', - 'export { Foo, Bar } from "changed";', - 'export { Foo, Bar, } from "changed";', - 'export { Foo as Bar, Baz } from "changed";', - 'export { Foo as Bar, Baz, } from "changed";', - 'export { Foo, Bar as Baz } from "changed";', - 'export { Foo, Bar as Baz, } from "changed";', - 'export { Foo as Bar, Baz as Qux } from "changed";', - 'export { Foo as Bar, Baz as Qux, } from "changed";', - 'export { Foo, Bar, Baz } from "changed";', - 'export { Foo, Bar, Baz, } from "changed";', - 'export { Foo as Bar, Baz, Qux } from "changed";', - 'export { Foo as Bar, Baz, Qux, } from "changed";', - 'export { Foo, Bar as Baz, Qux } from "changed";', - 'export { Foo, Bar as Baz, Qux, } from "changed";', - 'export { Foo, Bar, Baz as Qux } from "changed";', - 'export { Foo, Bar, Baz as Qux, } from "changed";', - 'export { Foo as Bar, Baz as Qux, Norf } from "changed";', - 'export { Foo as Bar, Baz as Qux, Norf, } from "changed";', - 'export { Foo as Bar, Baz, Qux as Norf } from "changed";', - 'export { Foo as Bar, Baz, Qux as Norf, } from "changed";', - 'export { Foo, Bar as Baz, Qux as Norf } from "changed";', - 'export { Foo, Bar as Baz, Qux as Norf, } from "changed";', - 'export { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";', - 'export { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";', - 'export Default, * as All from "changed";', - 'export Default, { } from "changed";', - 'export Default, { Foo } from "changed";', - 'export Default, { Foo, } from "changed";', - 'export Default, { Foo as Bar } from "changed";', - 'export Default, { Foo as Bar, } from "changed";', - 'export Default, { Foo, Bar } from "changed";', - 'export Default, { Foo, Bar, } from "changed";', - 'export Default, { Foo as Bar, Baz } from "changed";', - 'export Default, { Foo as Bar, Baz, } from "changed";', - 'export Default, { Foo, Bar as Baz } from "changed";', - 'export Default, { Foo, Bar as Baz, } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux, } from "changed";', - 'export Default, { Foo, Bar, Baz } from "changed";', - 'export Default, { Foo, Bar, Baz, } from "changed";', - 'export Default, { Foo as Bar, Baz, Qux } from "changed";', - 'export Default, { Foo as Bar, Baz, Qux, } from "changed";', - 'export Default, { Foo, Bar as Baz, Qux } from "changed";', - 'export Default, { Foo, Bar as Baz, Qux, } from "changed";', - 'export Default, { Foo, Bar, Baz as Qux } from "changed";', - 'export Default, { Foo, Bar, Baz as Qux, } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux, Norf } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";', - 'export Default, { Foo as Bar, Baz, Qux as Norf } from "changed";', - 'export Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";', - 'export Default, { Foo, Bar as Baz, Qux as Norf } from "changed";', - 'export Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";', - 'export Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";', - 'export Default from "Y";', - 'export * as All from \'z\';', - // export with support for new lines - "export { Foo,\n Bar }\n from 'changed';", - "export { \nFoo,\nBar,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz\n }\n from 'changed';", - "export { \nFoo as Bar,\n Baz\n, }\n from 'changed';", - "export { Foo,\n Bar as Baz\n }\n from 'changed';", - "export { Foo,\n Bar as Baz,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';", - "export { Foo,\n Bar,\n Baz }\n from 'changed';", - "export { Foo,\n Bar,\n Baz,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';", - "export { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';", - "export { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';", - "export { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';", - "export { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';", - "export { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz,\n Qux as Norf\n }\n from 'changed';", - "export { Foo as Bar,\n Baz,\n Qux as Norf,\n }\n from 'changed';", - "export { Foo,\n Bar as Baz,\n Qux as Norf\n }\n from 'changed';", - "export { Foo,\n Bar as Baz,\n Qux as Norf,\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf\n }\n from 'changed';", - "export { Foo as Bar,\n Baz as Qux,\n Norf as Enuf,\n }\n from 'changed';", - "export Default,\n * as All from 'changed';", - "export Default,\n { } from 'changed';", - "export Default,\n { Foo\n }\n from 'changed';", - "export Default,\n { Foo,\n }\n from 'changed';", - "export Default,\n { Foo as Bar\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar\n } from\n 'changed';", - "export Default,\n { Foo,\n Bar,\n } from\n 'changed';", - "export Default,\n { Foo as Bar,\n Baz\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz,\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar as Baz\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar as Baz,\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux,\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar,\n Baz\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar,\n Baz,\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz,\n Qux\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz,\n Qux,\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar as Baz,\n Qux\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar as Baz,\n Qux,\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar,\n Baz as Qux\n }\n from 'changed';", - "export Default,\n { Foo,\n Bar,\n Baz as Qux,\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf,\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz,\n Qux as Norf, }\n from 'changed';", - "export Default,\n { Foo, Bar as Baz,\n Qux as Norf }\n from 'changed';", - "export Default,\n { Foo, Bar as Baz,\n Qux as Norf, }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore\n }\n from 'changed';", - "export Default,\n { Foo as Bar,\n Baz as Qux,\n Norf as NoMore,\n }\n from 'changed';", - "export Default\n , { } from 'changed';", - // require - 'require("changed")', - 'require("Y")', - 'require( \'z\' )', - 'require( "a")', - 'require("b" )', - '});', - ].join('\n')); + + // extract the converted code from the module wrapper + const cases = + processedCode.code + .match(/__d\(.*?\{\s*([\s\S]*)\}/)[1] // match code in wrapper + .replace(/\s+$/, '') // remove trailing whitespace + .split(magicJoiner); // extract every tested case + + testCases.forEach((inputCode, i) => { + expect(cases[i]).toEqual(makeExpected(inputCode)); + if(cases[i]!==makeExpected(inputCode)) { + console.log('FAIL %s: input(%s) expected(%s) actual(%s)', i, inputCode, makeExpected(inputCode), cases[i]); + } + }); }); }); diff --git a/react-packager/src/Resolver/index.js b/react-packager/src/Resolver/index.js index 0166681f..c657aae5 100644 --- a/react-packager/src/Resolver/index.js +++ b/react-packager/src/Resolver/index.js @@ -49,6 +49,10 @@ const validateOpts = declareOpts({ type: 'object', required: true, }, + getModuleId: { + type: 'function', + required: true, + } }); const getDependenciesValidateOpts = declareOpts({ @@ -98,6 +102,7 @@ class Resolver { shouldThrowOnUnresolvedErrors: (_, platform) => platform === 'ios', }); + this._getModuleId = options.getModuleId; this._polyfillModuleNames = opts.polyfillModuleNames || []; } @@ -177,36 +182,32 @@ class Resolver { } const resolvedDeps = Object.create(null); - const resolvedDepsArr = []; return Promise.all( resolutionResponse.getResolvedDependencyPairs(module).map( ([depName, depModule]) => { if (depModule) { - return depModule.getName().then(name => { - resolvedDeps[depName] = name; - resolvedDepsArr.push(name); - }); + resolvedDeps[depName] = this._getModuleId(depModule); } } ) ).then(() => { - const relativizeCode = (codeMatch, pre, quot, depName, post) => { - const depId = resolvedDeps[depName]; - if (depId) { - return pre + quot + depId + post; + const replaceModuleId = (codeMatch, pre, quot, depName, post = '') => { + if (depName in resolvedDeps) { + const replacement = `${quot}${resolvedDeps[depName]}${quot}`; + return `${pre}${replacement} /* ${depName} */${post}`; } else { return codeMatch; } }; code = code - .replace(replacePatterns.IMPORT_RE, relativizeCode) - .replace(replacePatterns.EXPORT_RE, relativizeCode) - .replace(replacePatterns.REQUIRE_RE, relativizeCode); + .replace(replacePatterns.IMPORT_RE, replaceModuleId) + .replace(replacePatterns.EXPORT_RE, replaceModuleId) + .replace(replacePatterns.REQUIRE_RE, replaceModuleId); return module.getName().then(name => { - return {name, code}; + return {name, code, id: this._getModuleId(module)}; }); }); }); @@ -220,8 +221,8 @@ class Resolver { } return this.resolveRequires(resolutionResponse, module, code).then( - ({name, code}) => { - return {name, code: defineModuleCode(name, code)}; + ({name, code, id}) => { + return {id, name, code: defineModuleCode(id, code, name)}; }); } @@ -231,10 +232,10 @@ class Resolver { } -function defineModuleCode(moduleName, code) { +function defineModuleCode(moduleId, code, verboseName = '') { return [ `__d(`, - `'${moduleName}',`, + `${JSON.stringify(moduleId)} /* ${verboseName} */ ,`, 'function(global, require, module, exports) {', ` ${code}`, '\n});', diff --git a/react-packager/src/Resolver/polyfills/require.js b/react-packager/src/Resolver/polyfills/require.js index a5a7a55f..bc14a6e8 100644 --- a/react-packager/src/Resolver/polyfills/require.js +++ b/react-packager/src/Resolver/polyfills/require.js @@ -59,18 +59,29 @@ function requireImpl(id) { ); } + + // `require` calls int the require polyfill itself are not analyzed and + // replaced so that they use numeric module IDs. + // The systrace module will expose itself on the require function so that + // it can be used here. + // TODO(davidaurelio) Scan polyfills for dependencies, too (t9759686) + const {Systrace} = require; try { // We must optimistically mark mod as initialized before running the factory to keep any // require cycles inside the factory from causing an infinite require loop. mod.isInitialized = true; - __DEV__ && Systrace().beginEvent('JS_require_' + id); + if (__DEV__) { + Systrace.beginEvent('JS_require_' + id); + } // keep args in sync with with defineModuleCode in // packager/react-packager/src/Resolver/index.js mod.factory.call(global, global, require, mod.module, mod.module.exports); - __DEV__ && Systrace().endEvent(); + if (__DEV__) { + Systrace.endEvent(); + } } catch (e) { mod.hasError = true; mod.isInitialized = false; @@ -80,15 +91,9 @@ function requireImpl(id) { return mod.module.exports; } -const Systrace = __DEV__ && (() => { - var _Systrace; - try { - _Systrace = require('Systrace'); - } catch (e) {} - - return _Systrace && _Systrace.beginEvent ? - _Systrace : { beginEvent: () => {}, endEvent: () => {} }; -}); +if (__DEV__) { + require.Systrace = { beginEvent: () => {}, endEvent: () => {} }; +} global.__d = define; global.require = require;