diff --git a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js index b397f24e3..74a246b80 100644 --- a/packager/react-packager/src/Bundler/__tests__/Bundler-test.js +++ b/packager/react-packager/src/Bundler/__tests__/Bundler-test.js @@ -24,6 +24,27 @@ var sizeOf = require('image-size'); var fs = require('fs'); describe('Bundler', function() { + + function createModule({ + path, + id, + dependencies, + isAsset, + isAsset_DEPRECATED, + isJSON, + resolution, + }) { + return { + path, + resolution, + getDependencies() { return Promise.resolve(dependencies); }, + getName() { return Promise.resolve(id); }, + isJSON() { return isJSON; }, + isAsset() { return isAsset; }, + isAsset_DEPRECATED() { return isAsset_DEPRECATED; }, + }; + } + var getDependencies; var wrapModule; var bundler; @@ -59,27 +80,6 @@ describe('Bundler', function() { assetServer: assetServer, }); - - function createModule({ - path, - id, - dependencies, - isAsset, - isAsset_DEPRECATED, - isJSON, - resolution, - }) { - return { - path, - resolution, - getDependencies() { return Promise.resolve(dependencies); }, - getName() { return Promise.resolve(id); }, - isJSON() { return isJSON; }, - isAsset() { return isAsset; }, - isAsset_DEPRECATED() { return isAsset_DEPRECATED; }, - }; - } - modules = [ createModule({id: 'foo', path: '/root/foo.js', dependencies: []}), createModule({id: 'bar', path: '/root/bar.js', dependencies: []}), @@ -129,18 +129,23 @@ describe('Bundler', function() { sizeOf.mockImpl(function(path, cb) { cb(null, { width: 50, height: 100 }); }); + }); - assetServer.getAssetData.mockImpl(function() { + pit('create a bundle', function() { + assetServer.getAssetData.mockImpl(() => { return { scales: [1,2,3], + files: [ + '/root/img/img.png', + '/root/img/img@2x.png', + '/root/img/img@3x.png', + ], hash: 'i am a hash', name: 'img', type: 'png', }; }); - }); - pit('create a bundle', function() { return bundler.bundle('/root/foo.js', true, 'source_map_url') .then(function(p) { expect(p.addModule.mock.calls[0][0]).toEqual({ @@ -186,6 +191,11 @@ describe('Bundler', function() { width: 25, height: 50, scales: [1, 2, 3], + files: [ + '/root/img/img.png', + '/root/img/img@2x.png', + '/root/img/img@3x.png', + ], hash: 'i am a hash', name: 'img', type: 'png', @@ -235,4 +245,64 @@ describe('Bundler', function() { .toBeCalledWith('/root/foo.js', { dev: true }) ); }); + + describe('getOrderedDependencyPaths', () => { + beforeEach(() => { + assetServer.getAssetData.mockImpl(function(relPath) { + if (relPath === 'img/new_image.png') { + return { + scales: [1,2,3], + files: [ + '/root/img/new_image.png', + '/root/img/new_image@2x.png', + '/root/img/new_image@3x.png', + ], + hash: 'i am a hash', + name: 'img', + type: 'png', + }; + } else if (relPath === 'img/new_image2.png') { + return { + scales: [1,2,3], + files: [ + '/root/img/new_image2.png', + '/root/img/new_image2@2x.png', + '/root/img/new_image2@3x.png', + ], + hash: 'i am a hash', + name: 'img', + type: 'png', + }; + } + + throw new Error('unknown image ' + relPath); + }); + }); + + pit('should get the concrete list of all dependency files', () => { + modules.push( + createModule({ + id: 'new_image2.png', + path: '/root/img/new_image2.png', + isAsset: true, + resolution: 2, + dependencies: [] + }), + ); + + return bundler.getOrderedDependencyPaths('/root/foo.js', true) + .then((paths) => expect(paths).toEqual([ + '/root/foo.js', + '/root/bar.js', + '/root/img/img.png', + '/root/img/new_image.png', + '/root/img/new_image@2x.png', + '/root/img/new_image@3x.png', + '/root/file.json', + '/root/img/new_image2.png', + '/root/img/new_image2@2x.png', + '/root/img/new_image2@3x.png', + ])); + }); + }); }); diff --git a/packager/react-packager/src/Bundler/index.js b/packager/react-packager/src/Bundler/index.js index d2d8ae7f6..289911d4c 100644 --- a/packager/react-packager/src/Bundler/index.js +++ b/packager/react-packager/src/Bundler/index.js @@ -187,6 +187,38 @@ class Bundler { return this._resolver.getDependencies(main, { dev: isDev, platform }); } + getOrderedDependencyPaths({ entryFile, dev, platform }) { + return this.getDependencies(entryFile, dev, platform).then( + ({ dependencies }) => { + const ret = []; + const promises = []; + const placeHolder = {}; + dependencies.forEach(dep => { + if (dep.isAsset()) { + const relPath = getPathRelativeToRoot( + this._projectRoots, + dep.path + ); + promises.push( + this._assetServer.getAssetData(relPath, platform) + ); + ret.push(placeHolder); + } else { + ret.push(dep.path); + } + }); + + return Promise.all(promises).then(assetsData => { + assetsData.forEach(({ files }) => { + const index = ret.indexOf(placeHolder); + ret.splice(index, 1, ...files); + }); + return ret; + }); + } + ); + } + _transformModule(bundle, response, module, platform = null) { let transform; diff --git a/packager/react-packager/src/Server/index.js b/packager/react-packager/src/Server/index.js index 346f4bcb0..74e839272 100644 --- a/packager/react-packager/src/Server/index.js +++ b/packager/react-packager/src/Server/index.js @@ -200,6 +200,13 @@ class Server { }); } + getOrderedDependencyPaths(options) { + return Promise.resolve().then(() => { + const opts = dependencyOpts(options); + return this._bundler.getOrderedDependencyPaths(opts); + }); + } + _onFileChange(type, filepath, root) { const absPath = path.join(root, filepath); this._bundler.invalidateFile(absPath); diff --git a/packager/react-packager/src/SocketInterface/SocketClient.js b/packager/react-packager/src/SocketInterface/SocketClient.js index b89f5cca4..41ce0df14 100644 --- a/packager/react-packager/src/SocketInterface/SocketClient.js +++ b/packager/react-packager/src/SocketInterface/SocketClient.js @@ -86,6 +86,13 @@ class SocketClient { }); } + getOrderedDependencyPaths(main) { + return this._send({ + type: 'getOrderedDependencyPaths', + data: main, + }); + } + buildBundle(options) { return this._send({ type: 'buildBundle', diff --git a/packager/react-packager/src/SocketInterface/SocketServer.js b/packager/react-packager/src/SocketInterface/SocketServer.js index 5098ea870..8258873a4 100644 --- a/packager/react-packager/src/SocketInterface/SocketServer.js +++ b/packager/react-packager/src/SocketInterface/SocketServer.js @@ -121,6 +121,14 @@ class SocketServer { ); break; + case 'getOrderedDependencyPaths': + this._jobs++; + this._packagerServer.getOrderedDependencyPaths(m.data).then( + (dependencies) => this._reply(sock, m.id, 'result', dependencies), + handleError, + ); + break; + default: this._reply(sock, m.id, 'error', 'Unknown message type: ' + m.type); } diff --git a/private-cli/src/dependencies/dependencies.js b/private-cli/src/dependencies/dependencies.js index c0bb4a888..01bc79de9 100644 --- a/private-cli/src/dependencies/dependencies.js +++ b/private-cli/src/dependencies/dependencies.js @@ -39,7 +39,7 @@ function _dependencies(argv, conf, resolve, reject) { command: 'platform', description: 'The platform extension used for selecting modules', type: 'string', - }, + } ], argv); const rootModuleAbsolutePath = args['entry-file']; @@ -75,22 +75,22 @@ function _dependencies(argv, conf, resolve, reject) { log('Waiting for the packager.'); resolve(ReactPackager.createClientFor(config).then(client => { log('Packager client was created'); - return client.getDependencies(options) + return client.getOrderedDependencyPaths(options) .then(deps => { log('Packager returned dependencies'); client.close(); - deps.forEach(module => { + deps.forEach(modulePath => { // Temporary hack to disable listing dependencies not under this directory. // Long term, we need either // (a) JS code to not depend on anything outside this directory, or // (b) Come up with a way to declare this dependency in Buck. const isInsideProjectRoots = config.projectRoots.filter(root => - module.path.startsWith(root) + modulePath.startsWith(root) ).length > 0; if (isInsideProjectRoots) { - outStream.write(module.path + '\n'); + outStream.write(modulePath + '\n'); } }); writeToFile && outStream.end();