Send HMR updates only for files on the bundle
Summary: public Compute the dependencies of the bundle entry file just before sending HMR updates. In case the file that was changed doesn't belong to the bundle bail. Reviewed By: vjeux Differential Revision: D2793736 fb-gh-sync-id: f858e71b0dd5fe4f5b2307a22c6cef627eb66a22
This commit is contained in:
parent
5f850fbede
commit
b5081abae3
|
@ -22,16 +22,76 @@ function attachHMRServer({httpServer, path, packagerServer}) {
|
||||||
client = null;
|
client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a promise with the full list of dependencies and the shallow
|
||||||
|
// dependencies each file on the dependency list has for the give platform
|
||||||
|
// and entry file.
|
||||||
|
function getDependencies(platform, bundleEntry) {
|
||||||
|
return packagerServer.getDependencies({
|
||||||
|
platform: platform,
|
||||||
|
dev: true,
|
||||||
|
entryFile: bundleEntry,
|
||||||
|
}).then(response => {
|
||||||
|
// for each dependency builds the object:
|
||||||
|
// `{path: '/a/b/c.js', deps: ['modA', 'modB', ...]}`
|
||||||
|
return Promise.all(Object.values(response.dependencies).map(dep => {
|
||||||
|
if (dep.isAsset() || dep.isAsset_DEPRECATED() || dep.isJSON()) {
|
||||||
|
return Promise.resolve({path: dep.path, deps: []});
|
||||||
|
}
|
||||||
|
return packagerServer.getShallowDependencies(dep.path)
|
||||||
|
.then(deps => {
|
||||||
|
return {
|
||||||
|
path: dep.path,
|
||||||
|
deps,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
.then(deps => {
|
||||||
|
// list with all the dependencies the bundle entry has
|
||||||
|
const dependenciesCache = response.dependencies.map(dep => dep.path);
|
||||||
|
|
||||||
|
// map that indicates the shallow dependency each file included on the
|
||||||
|
// bundle has
|
||||||
|
const shallowDependencies = {};
|
||||||
|
deps.forEach(dep => shallowDependencies[dep.path] = dep.deps);
|
||||||
|
|
||||||
|
return {dependenciesCache, shallowDependencies};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
packagerServer.addFileChangeListener(filename => {
|
packagerServer.addFileChangeListener(filename => {
|
||||||
if (!client) {
|
if (!client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
packagerServer.buildBundleForHMR({
|
packagerServer.getShallowDependencies(filename)
|
||||||
entryFile: filename,
|
.then(deps => {
|
||||||
|
// if the file dependencies have change we need to invalidate the
|
||||||
|
// dependencies caches because the list of files we need to send to the
|
||||||
|
// client may have changed
|
||||||
|
if (arrayEquals(deps, client.shallowDependencies[filename])) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return getDependencies(client.platform, client.bundleEntry)
|
||||||
|
.then(({dependenciesCache, shallowDependencies}) => {
|
||||||
|
// invalidate caches
|
||||||
|
client.dependenciesCache = dependenciesCache;
|
||||||
|
client.shallowDependencies = shallowDependencies;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// make sure the file was modified is part of the bundle
|
||||||
|
if (!client.shallowDependencies[filename]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packagerServer.buildBundleForHMR({
|
||||||
platform: client.platform,
|
platform: client.platform,
|
||||||
|
entryFile: filename,
|
||||||
})
|
})
|
||||||
.then(bundle => client.ws.send(bundle));
|
.then(bundle => client.ws.send(bundle));
|
||||||
|
})
|
||||||
|
.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
const WebSocketServer = require('ws').Server;
|
const WebSocketServer = require('ws').Server;
|
||||||
|
@ -44,10 +104,15 @@ function attachHMRServer({httpServer, path, packagerServer}) {
|
||||||
wss.on('connection', ws => {
|
wss.on('connection', ws => {
|
||||||
console.log('[Hot Module Replacement] Client connected');
|
console.log('[Hot Module Replacement] Client connected');
|
||||||
const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
|
const params = querystring.parse(url.parse(ws.upgradeReq.url).query);
|
||||||
|
|
||||||
|
getDependencies(params.platform, params.bundleEntry)
|
||||||
|
.then(({dependenciesCache, shallowDependencies}) => {
|
||||||
client = {
|
client = {
|
||||||
ws,
|
ws,
|
||||||
platform: params.platform,
|
platform: params.platform,
|
||||||
bundleEntry: params.bundleEntry,
|
bundleEntry: params.bundleEntry,
|
||||||
|
dependenciesCache,
|
||||||
|
shallowDependencies,
|
||||||
};
|
};
|
||||||
|
|
||||||
client.ws.on('error', e => {
|
client.ws.on('error', e => {
|
||||||
|
@ -56,7 +121,20 @@ function attachHMRServer({httpServer, path, packagerServer}) {
|
||||||
});
|
});
|
||||||
|
|
||||||
client.ws.on('close', () => disconnect());
|
client.ws.on('close', () => disconnect());
|
||||||
|
})
|
||||||
|
.done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function arrayEquals(arrayA, arrayB) {
|
||||||
|
arrayA = arrayA || [];
|
||||||
|
arrayB = arrayB || [];
|
||||||
|
return (
|
||||||
|
arrayA.length === arrayB.length &&
|
||||||
|
arrayA.every((element, index) => {
|
||||||
|
return element === arrayB[index];
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = attachHMRServer;
|
module.exports = attachHMRServer;
|
||||||
|
|
|
@ -310,6 +310,10 @@ class Bundler {
|
||||||
this._transformer.invalidateFile(filePath);
|
this._transformer.invalidateFile(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShallowDependencies(entryFile) {
|
||||||
|
return this._resolver.getShallowDependencies(entryFile);
|
||||||
|
}
|
||||||
|
|
||||||
getDependencies(main, isDev, platform) {
|
getDependencies(main, isDev, platform) {
|
||||||
return this._resolver.getDependencies(main, { dev: isDev, platform });
|
return this._resolver.getDependencies(main, { dev: isDev, platform });
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,14 @@ class DependencyGraph {
|
||||||
return this._loading;
|
return this._loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise with the direct dependencies the module associated to
|
||||||
|
* the given entryPath has.
|
||||||
|
*/
|
||||||
|
getShallowDependencies(entryPath) {
|
||||||
|
return this._moduleCache.getModule(entryPath).getDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
getDependencies(entryPath, platform) {
|
getDependencies(entryPath, platform) {
|
||||||
return this.load().then(() => {
|
return this.load().then(() => {
|
||||||
platform = this._getRequestPlatform(entryPath, platform);
|
platform = this._getRequestPlatform(entryPath, platform);
|
||||||
|
|
|
@ -99,6 +99,10 @@ class Resolver {
|
||||||
this._polyfillModuleNames = opts.polyfillModuleNames || [];
|
this._polyfillModuleNames = opts.polyfillModuleNames || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShallowDependencies(entryFile) {
|
||||||
|
return this._depGraph.getShallowDependencies(entryFile);
|
||||||
|
}
|
||||||
|
|
||||||
getDependencies(main, options) {
|
getDependencies(main, options) {
|
||||||
const opts = getDependenciesValidateOpts(options);
|
const opts = getDependenciesValidateOpts(options);
|
||||||
|
|
||||||
|
|
|
@ -246,6 +246,10 @@ class Server {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShallowDependencies(entryFile) {
|
||||||
|
return this._bundler.getShallowDependencies(entryFile);
|
||||||
|
}
|
||||||
|
|
||||||
getDependencies(options) {
|
getDependencies(options) {
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
if (!options.platform) {
|
if (!options.platform) {
|
||||||
|
|
Loading…
Reference in New Issue