diff --git a/packages/metro/src/Bundler/__tests__/Bundler-test.js b/packages/metro/src/Bundler/__tests__/Bundler-test.js index 567db72e..e9acf602 100644 --- a/packages/metro/src/Bundler/__tests__/Bundler-test.js +++ b/packages/metro/src/Bundler/__tests__/Bundler-test.js @@ -105,63 +105,4 @@ describe('Bundler', function() { }); expect(b._opts.platforms).toEqual(['android', 'vr']); }); - - it('.generateAssetObjAndCode', async () => { - const mockAsset = { - __packager_asset: true, - fileSystemLocation: '/root/img', - scales: [1, 2, 3], - files: [ - '/root/img/img.png', - '/root/img/img@2x.png', - '/root/img/img@3x.png', - ], - hash: 'i am a hash', - height: 100, - httpServerLocation: '/assets/img', - name: 'img', - type: 'png', - width: 50, - }; - - assetServer.getAssetData.mockImplementation(() => - Promise.resolve(mockAsset), - ); - - jest.mock( - 'mockPlugin1', - () => { - return asset => { - asset.extraReverseHash = asset.hash - .split('') - .reverse() - .join(''); - return asset; - }; - }, - {virtual: true}, - ); - - jest.mock( - 'asyncMockPlugin2', - () => { - return asset => { - expect(asset.extraReverseHash).toBeDefined(); - return new Promise(resolve => { - asset.extraPixelCount = asset.width * asset.height; - resolve(asset); - }); - }; - }, - {virtual: true}, - ); - - expect( - await bundler.generateAssetObjAndCode( - {}, - ['mockPlugin1', 'asyncMockPlugin2'], - 'ios', - ), - ).toMatchSnapshot(); - }); }); diff --git a/packages/metro/src/Bundler/__tests__/__snapshots__/Bundler-test.js.snap b/packages/metro/src/Bundler/__tests__/__snapshots__/Bundler-test.js.snap deleted file mode 100644 index 3aa3e60b..00000000 --- a/packages/metro/src/Bundler/__tests__/__snapshots__/Bundler-test.js.snap +++ /dev/null @@ -1,38 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Bundler .generateAssetObjAndCode 1`] = ` -Object { - "asset": Object { - "__packager_asset": true, - "extraPixelCount": 5000, - "extraReverseHash": "hsah a ma i", - "fileSystemLocation": "/root/img", - "files": Array [ - "/root/img/img.png", - "/root/img/img@2x.png", - "/root/img/img@3x.png", - ], - "hash": "i am a hash", - "height": 100, - "httpServerLocation": "/assets/img", - "name": "img", - "scales": Array [ - 1, - 2, - 3, - ], - "type": "png", - "width": 50, - }, - "code": "module.exports=require(\\"/AssetRegistry.js\\").registerAsset({\\"__packager_asset\\":true,\\"scales\\":[1,2,3],\\"hash\\":\\"i am a hash\\",\\"height\\":100,\\"httpServerLocation\\":\\"/assets/img\\",\\"name\\":\\"img\\",\\"type\\":\\"png\\",\\"width\\":50,\\"extraReverseHash\\":\\"hsah a ma i\\",\\"extraPixelCount\\":5000});", - "meta": Object { - "dependencies": Array [ - "/AssetRegistry.js", - ], - "dependencyOffsets": Array [ - 23, - ], - "preloaded": null, - }, -} -`; diff --git a/packages/metro/src/Bundler/index.js b/packages/metro/src/Bundler/index.js index 095dabec..86e029a1 100644 --- a/packages/metro/src/Bundler/index.js +++ b/packages/metro/src/Bundler/index.js @@ -22,8 +22,6 @@ const path = require('path'); const defaults = require('../defaults'); const createModuleIdFactory = require('../lib/createModuleIdFactory'); -const {generateAssetTransformResult} = require('./util'); - const {sep: pathSeparator} = require('path'); const VERSION = require('../../package.json').version; @@ -242,51 +240,6 @@ class Bundler { ); } - async generateAssetObjAndCode( - path: string, - assetPlugins: Array, - platform: ?string = null, - ) { - const assetData = await this._assetServer.getAssetData(path, platform); - const asset = await this._applyAssetPlugins(assetPlugins, assetData); - - const { - code, - dependencies, - dependencyOffsets, - } = generateAssetTransformResult(this._opts.assetRegistryPath, asset); - - return { - asset, - code, - meta: {dependencies, dependencyOffsets, preloaded: null}, - }; - } - - _applyAssetPlugins( - assetPlugins: Array, - asset: ExtendedAssetDescriptor, - ) { - if (!assetPlugins.length) { - return asset; - } - - const [currentAssetPlugin, ...remainingAssetPlugins] = assetPlugins; - /* $FlowFixMe: dynamic requires prevent static typing :'( */ - const assetPluginFunction = require(currentAssetPlugin); - const result = assetPluginFunction(asset); - - // If the plugin was an async function, wait for it to fulfill before - // applying the remaining plugins - if (typeof result.then === 'function') { - return result.then(resultAsset => - this._applyAssetPlugins(remainingAssetPlugins, resultAsset), - ); - } else { - return this._applyAssetPlugins(remainingAssetPlugins, result); - } - } - /** * Returns the transform options related to a specific entry file, by calling * the config parameter getTransformOptions(). diff --git a/packages/metro/src/Bundler/util.js b/packages/metro/src/Bundler/util.js index 8b68751b..8aaacf14 100644 --- a/packages/metro/src/Bundler/util.js +++ b/packages/metro/src/Bundler/util.js @@ -160,23 +160,6 @@ function generateRemoteAssetCodeFileAst( ); } -function generateAssetTransformResult( - assetRegistryPath: string, - assetDescriptor: ExtendedAssetDescriptor, -): {| - code: string, - dependencies: Array, - dependencyOffsets: Array, -|} { - const {code} = babelGenerate( - generateAssetCodeFileAst(assetRegistryPath, assetDescriptor), - {comments: false, compact: true}, - ); - const dependencies = [assetRegistryPath]; - const dependencyOffsets = [code.indexOf(assetRegistryPath) - 1]; - return {code, dependencies, dependencyOffsets}; -} - // Test extension against all types supported by image-size module. // If it's not one of these, we won't treat it as an image. function isAssetTypeAnImage(type: string): boolean { @@ -272,7 +255,6 @@ class ArrayMap extends Map> { module.exports = { createRamBundleGroups, generateAssetCodeFileAst, - generateAssetTransformResult, generateRemoteAssetCodeFileAst, isAssetTypeAnImage, }; diff --git a/packages/metro/src/DeltaBundler/DeltaTransformer.js b/packages/metro/src/DeltaBundler/DeltaTransformer.js index 06aa5cb0..4c521e77 100644 --- a/packages/metro/src/DeltaBundler/DeltaTransformer.js +++ b/packages/metro/src/DeltaBundler/DeltaTransformer.js @@ -505,38 +505,6 @@ class DeltaTransformer extends EventEmitter { return addParamsToDefineCall(code, ...params); } - /** - * Temporary function to wrap an asset. This logic will go away once we - * generate the needed JS code for assets in the transformer. - */ - async _wrapAsset({ - code, - dependencyPairs, - name, - path, - }: { - code: string, - dependencyPairs: Map, - name: string, - path: string, - }): Promise { - const asset = await this._bundler.generateAssetObjAndCode( - path, - this._bundleOptions.assetPlugins, - this._bundleOptions.platform, - ); - - return await this._resolver.wrapModule({ - path, - getModuleId: this._getModuleId, - dependencyPairs, - dependencyOffsets: asset.meta.dependencyOffsets, - name, - code: asset.code, - dev: this._bundleOptions.dev, - }); - } - _getModuleType(module: Module): DeltaEntryType { if (module.isAsset()) { return 'asset'; diff --git a/packages/metro/src/Resolver/__tests__/Resolver-test.js b/packages/metro/src/Resolver/__tests__/Resolver-test.js index 379d9166..ca65acee 100644 --- a/packages/metro/src/Resolver/__tests__/Resolver-test.js +++ b/packages/metro/src/Resolver/__tests__/Resolver-test.js @@ -19,7 +19,6 @@ jest.mock('path'); const DependencyGraph = jest.fn(); jest.setMock('../../node-haste/DependencyGraph', DependencyGraph); let Module; -let Polyfill; describe('Resolver', function() { let Resolver, path; @@ -28,21 +27,16 @@ describe('Resolver', function() { Resolver = require('../'); path = require('path'); DependencyGraph.mockClear(); + Module = jest.fn(function() { - this.getName = jest.fn(); - this.getDependencies = jest.fn(); this.isPolyfill = jest.fn().mockReturnValue(false); this.isJSON = jest.fn().mockReturnValue(false); }); - Polyfill = jest.fn(function() { - var polyfill = new Module(); - polyfill.isPolyfill.mockReturnValue(true); - return polyfill; - }); DependencyGraph.load = jest .fn() .mockImplementation(opts => Promise.resolve(new DependencyGraph(opts))); + DependencyGraph.prototype.createPolyfill = jest.fn(); DependencyGraph.prototype.getDependencies = jest.fn(); @@ -52,237 +46,53 @@ describe('Resolver', function() { DependencyGraph.prototype.load = jest.fn(() => Promise.resolve()); }); - class ResolutionResponseMock { - constructor({dependencies, mainModuleId}) { - this.dependencies = dependencies; - this.mainModuleId = mainModuleId; - this.getModuleId = createGetModuleId(); - } - - prependDependency(dependency) { - this.dependencies.unshift(dependency); - } - - finalize() { - return Promise.resolve(this); - } - - getResolvedDependencyPairs() { - return []; - } - } - function createModule(id, dependencies) { var module = new Module({}); module.path = id; - module.getName.mockImplementation(() => Promise.resolve(id)); - module.getDependencies.mockImplementation(() => - Promise.resolve(dependencies), - ); + return module; } - function createJsonModule(id) { - const module = createModule(id, []); - module.isJSON.mockReturnValue(true); - return module; - } + describe('minification:', () => { + const code = 'arbitrary(code)'; + const id = 'arbitrary.js'; + let depResolver, minifyCode, module, sourceMap; - function createPolyfill(id, dependencies) { - var polyfill = new Polyfill({}); - polyfill.getName = jest.fn(() => Promise.resolve(id)); - polyfill.getDependencies = jest.fn(() => Promise.resolve(dependencies)); - return polyfill; - } - - describe('wrapModule', function() { - let depResolver; beforeEach(() => { + minifyCode = jest.fn((filename, code, map) => + Promise.resolve({code, map}), + ); + module = createModule(id); + module.path = '/arbitrary/path.js'; + + sourceMap = []; return Resolver.load({ projectRoot: '/root', + minifyCode, + postMinifyProcess: e => e, }).then(r => { depResolver = r; }); }); - it('should resolve modules', function() { - expect.assertions(1); - - var code = [ - // require - 'require("x")', - 'require("y");require(\'abc\');', - "require( 'z' )", - 'require( "a")', - 'require("b" )', - ].join('\n'); - /*eslint-disable */ - - function* findDependencyOffsets() { - const re = /(['"']).*?\1/g; - let match; - while ((match = re.exec(code))) { - yield match.index; - } - } - - const dependencyOffsets = Array.from(findDependencyOffsets()); - const module = createModule('test module', ['x', 'y']); - const resolutionResponse = new ResolutionResponseMock({ - dependencies: [module], - mainModuleId: 'test module', - }); - - resolutionResponse.getResolvedDependencyPairs = module => { - return [ - ['x', createModule('changed')], - ['y', createModule('Y')], - ['abc', createModule('abc')], - ]; + it('should use minified code', () => { + expect.assertions(2); + const minifiedCode = 'minified(code)'; + const minifiedMap = { + version: 3, + file: ['minified'], + sources: [], + mappings: '', }; - - const moduleIds = new Map( - resolutionResponse - .getResolvedDependencyPairs() - .map(([importId, module]) => [ - importId, - padRight( - resolutionResponse.getModuleId(module.path), - importId.length + 2, - ), - ]), + minifyCode.mockReturnValue( + Promise.resolve({code: minifiedCode, map: minifiedMap}), ); - - const dependencyPairs = new Map(); - for (const [ - relativePath, - dependencyModule, - ] of resolutionResponse.getResolvedDependencyPairs(module)) { - dependencyPairs.set(relativePath, dependencyModule.path); - } - - const processedCode = depResolver.wrapModule({ - path: module.path, - getModuleId: resolutionResponse.getModuleId, - dependencyPairs, - name: 'test module', - code, - dependencyOffsets, - dev: false, - }); - - expect(processedCode).toEqual( - [ - '__d(/* test module */function(global, require, module, exports) {' + - // require - `require(${moduleIds.get('x')}) // ${moduleIds - .get('x') - .trim()} = x`, - `require(${moduleIds.get('y')});require(${moduleIds.get( - 'abc', - )}); // ${moduleIds.get('abc').trim()} = abc // ${moduleIds - .get('y') - .trim()} = y`, - "require( 'z' )", - 'require( "a")', - 'require("b" )', - `}, ${resolutionResponse.getModuleId(module.path)});`, - ].join('\n'), - ); - }); - - it('should add module transport names as fourth argument to `__d`', () => { - expect.assertions(1); - - const module = createModule('test module'); - const code = 'arbitrary(code)'; - const resolutionResponse = new ResolutionResponseMock({ - dependencies: [module], - mainModuleId: 'test module', - }); - - const processedCode = depResolver.wrapModule({ - getModuleId: resolutionResponse.getModuleId, - dependencyPairs: resolutionResponse.getResolvedDependencyPairs(module), - code, - path: module.path, - name: 'test module', - dev: true, - }); - expect(processedCode).toEqual( - [ - '__d(/* test module */function(global, require, module, exports) {' + - code, - `}, ${resolutionResponse.getModuleId( - module.path, - )}, null, "test module");`, - ].join('\n'), - ); - }); - - describe('minification:', () => { - const code = 'arbitrary(code)'; - const id = 'arbitrary.js'; - let depResolver, minifyCode, module, resolutionResponse, sourceMap; - - beforeEach(() => { - minifyCode = jest.fn((filename, code, map) => - Promise.resolve({code, map}), - ); - module = createModule(id); - module.path = '/arbitrary/path.js'; - resolutionResponse = new ResolutionResponseMock({ - dependencies: [module], - mainModuleId: id, + return depResolver + .minifyModule(module.path, code, sourceMap) + .then(({code, map}) => { + expect(code).toEqual(minifiedCode); + expect(map).toEqual([]); }); - sourceMap = []; - return Resolver.load({ - projectRoot: '/root', - minifyCode, - postMinifyProcess: e => e, - }).then(r => { - depResolver = r; - }); - }); - - it('should use minified code', () => { - expect.assertions(2); - const minifiedCode = 'minified(code)'; - const minifiedMap = { - version: 3, - file: ['minified'], - sources: [], - mappings: '', - }; - minifyCode.mockReturnValue( - Promise.resolve({code: minifiedCode, map: minifiedMap}), - ); - return depResolver - .minifyModule(module.path, code, sourceMap) - .then(({code, map}) => { - expect(code).toEqual(minifiedCode); - expect(map).toEqual([]); - }); - }); }); }); - - function createGetModuleId() { - let nextId = 1; - const knownIds = new Map(); - function createId(path) { - const id = nextId; - nextId += 1; - knownIds.set(path, id); - return id; - } - - return path => knownIds.get(path) || createId(path); - } - - function padRight(value, width) { - const s = String(value); - const diff = width - s.length; - return diff > 0 ? s + Array(diff + 1).join(' ') : s; - } }); diff --git a/packages/metro/src/Resolver/index.js b/packages/metro/src/Resolver/index.js index 85b53a16..d7adb5db 100644 --- a/packages/metro/src/Resolver/index.js +++ b/packages/metro/src/Resolver/index.js @@ -116,66 +116,6 @@ class Resolver { ); } - resolveRequires( - getModuleId: (path: string) => number, - code: string, - dependencyPairs: Map, - dependencyOffsets: Array = [], - ): string { - const resolvedDeps = Object.create(null); - - // here, we build a map of all require strings (relative and absolute) - // to the canonical ID of the module they reference - for (const [name, path] of dependencyPairs) { - resolvedDeps[name] = getModuleId(path); - } - - // if we have a canonical ID for the module imported here, - // we use it, so that require() is always called with the same - // id for every module. - // Example: - // -- in a/b.js: - // require('./c') => require(3); - // -- in b/index.js: - // require('../a/c') => require(3); - return dependencyOffsets - .reduceRight( - ([unhandled, handled], offset) => [ - unhandled.slice(0, offset), - replaceDependencyID(unhandled.slice(offset) + handled, resolvedDeps), - ], - [code, ''], - ) - .join(''); - } - - wrapModule({ - path, - getModuleId, - dependencyPairs, - dependencyOffsets, - name, - code, - dev = true, - }: { - path: string, - getModuleId: (path: string) => number, - dependencyPairs: Map, - dependencyOffsets: Array, - name: string, - code: string, - dev?: boolean, - }): string { - code = this.resolveRequires( - getModuleId, - code, - dependencyPairs, - dependencyOffsets, - ); - - return defineModuleCode(getModuleId(path), code, name, dev); - } - async minifyModule( path: string, code: string, @@ -200,48 +140,4 @@ class Resolver { } } -function defineModuleCode(moduleName, code, verboseName = '', dev = true) { - return [ - `__d(/* ${verboseName} */`, - 'function(global, require, module, exports) {', // module factory - code, - '\n}, ', - `${JSON.stringify(moduleName)}`, // module id, null = id map. used in ModuleGraph - dev ? `, null, ${JSON.stringify(verboseName)}` : '', - ');', - ].join(''); -} - -function definePolyfillCode(code) { - return [ - '(function(global) {', - code, - `\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);`, - ].join(''); -} - -const reDepencencyString = /^(['"])([^'"']*)\1/; -function replaceDependencyID(stringWithDependencyIDAtStart, resolvedDeps) { - const match = reDepencencyString.exec(stringWithDependencyIDAtStart); - const dependencyName = match && match[2]; - if (match != null && dependencyName in resolvedDeps) { - const {length} = match[0]; - const id = String(resolvedDeps[dependencyName]); - return ( - padRight(id, length) + - stringWithDependencyIDAtStart - .slice(length) - .replace(/$/m, ` // ${id} = ${dependencyName}`) - ); - } else { - return stringWithDependencyIDAtStart; - } -} - -function padRight(string, length) { - return string.length < length - ? string + Array(length - string.length + 1).join(' ') - : string; -} - module.exports = Resolver;