Introduce `getOrderedDependencyPaths` that gets all concrete dependecy paths

Summary: @​public
Since we added packager-managed assets -- internally we still think of asset dependency as a single "module". In reality there are multiple files that represent this module. This becomes important with the `getDependencies` API which is used by Buck to inform it on what to rebuild. Since `getDependencies` deals with modules, and is more of an internal API, I've introduced a new one and would go on to deprecate this.

Reviewed By: @frantic

Differential Revision: D2487207
This commit is contained in:
Amjad Masad 2015-09-29 18:32:12 -07:00 committed by facebook-github-bot-3
parent d9c7205e17
commit 4072c564ca
5 changed files with 148 additions and 24 deletions

View File

@ -24,6 +24,27 @@ var sizeOf = require('image-size');
var fs = require('fs'); var fs = require('fs');
describe('Bundler', function() { 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 getDependencies;
var wrapModule; var wrapModule;
var bundler; var bundler;
@ -59,27 +80,6 @@ describe('Bundler', function() {
assetServer: assetServer, 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 = [ modules = [
createModule({id: 'foo', path: '/root/foo.js', dependencies: []}), createModule({id: 'foo', path: '/root/foo.js', dependencies: []}),
createModule({id: 'bar', path: '/root/bar.js', dependencies: []}), createModule({id: 'bar', path: '/root/bar.js', dependencies: []}),
@ -129,18 +129,23 @@ describe('Bundler', function() {
sizeOf.mockImpl(function(path, cb) { sizeOf.mockImpl(function(path, cb) {
cb(null, { width: 50, height: 100 }); cb(null, { width: 50, height: 100 });
}); });
});
assetServer.getAssetData.mockImpl(function() { pit('create a bundle', function() {
assetServer.getAssetData.mockImpl(() => {
return { return {
scales: [1,2,3], scales: [1,2,3],
files: [
'/root/img/img.png',
'/root/img/img@2x.png',
'/root/img/img@3x.png',
],
hash: 'i am a hash', hash: 'i am a hash',
name: 'img', name: 'img',
type: 'png', type: 'png',
}; };
}); });
});
pit('create a bundle', function() {
return bundler.bundle('/root/foo.js', true, 'source_map_url') return bundler.bundle('/root/foo.js', true, 'source_map_url')
.then(function(p) { .then(function(p) {
expect(p.addModule.mock.calls[0][0]).toEqual({ expect(p.addModule.mock.calls[0][0]).toEqual({
@ -186,6 +191,11 @@ describe('Bundler', function() {
width: 25, width: 25,
height: 50, height: 50,
scales: [1, 2, 3], scales: [1, 2, 3],
files: [
'/root/img/img.png',
'/root/img/img@2x.png',
'/root/img/img@3x.png',
],
hash: 'i am a hash', hash: 'i am a hash',
name: 'img', name: 'img',
type: 'png', type: 'png',
@ -235,4 +245,64 @@ describe('Bundler', function() {
.toBeCalledWith('/root/foo.js', { dev: true }) .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',
]));
});
});
}); });

View File

@ -187,6 +187,38 @@ class Bundler {
return this._resolver.getDependencies(main, { dev: isDev, platform }); 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) { _transformModule(bundle, response, module, platform = null) {
let transform; let transform;

View File

@ -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) { _onFileChange(type, filepath, root) {
const absPath = path.join(root, filepath); const absPath = path.join(root, filepath);
this._bundler.invalidateFile(absPath); this._bundler.invalidateFile(absPath);

View File

@ -86,6 +86,13 @@ class SocketClient {
}); });
} }
getOrderedDependencyPaths(main) {
return this._send({
type: 'getOrderedDependencyPaths',
data: main,
});
}
buildBundle(options) { buildBundle(options) {
return this._send({ return this._send({
type: 'buildBundle', type: 'buildBundle',

View File

@ -121,6 +121,14 @@ class SocketServer {
); );
break; break;
case 'getOrderedDependencyPaths':
this._jobs++;
this._packagerServer.getOrderedDependencyPaths(m.data).then(
(dependencies) => this._reply(sock, m.id, 'result', dependencies),
handleError,
);
break;
default: default:
this._reply(sock, m.id, 'error', 'Unknown message type: ' + m.type); this._reply(sock, m.id, 'error', 'Unknown message type: ' + m.type);
} }