129 lines
3.6 KiB
JavaScript
129 lines
3.6 KiB
JavaScript
|
const fs = require('fs');
|
|||
|
const path = require('path');
|
|||
|
|
|||
|
const log = (msg, ...rest) => console.log(`IncrementalWebpackCompiler: ${msg}`, ...rest);
|
|||
|
|
|||
|
// If we force a recompile immediately, the page reload doesn't seem to work.
|
|||
|
// Five seconds seem to work fine and the user can read the message
|
|||
|
const TIMEOUT = 5000;
|
|||
|
|
|||
|
class NoopCompiler {
|
|||
|
constructor() {
|
|||
|
this.enabled = false;
|
|||
|
}
|
|||
|
|
|||
|
filterEntryPoints(entryPoints) {
|
|||
|
return entryPoints;
|
|||
|
}
|
|||
|
|
|||
|
logStatus() {}
|
|||
|
|
|||
|
setupMiddleware() {}
|
|||
|
}
|
|||
|
|
|||
|
class IncrementalWebpackCompiler {
|
|||
|
constructor(historyFilePath) {
|
|||
|
this.enabled = true;
|
|||
|
this.history = {};
|
|||
|
this.compiledEntryPoints = new Set([
|
|||
|
// Login page
|
|||
|
'pages.sessions.new',
|
|||
|
// Explore page
|
|||
|
'pages.root',
|
|||
|
]);
|
|||
|
this.historyFilePath = historyFilePath;
|
|||
|
this._loadFromHistory();
|
|||
|
}
|
|||
|
|
|||
|
filterEntryPoints(entrypoints) {
|
|||
|
return Object.fromEntries(
|
|||
|
Object.entries(entrypoints).map(([key, val]) => {
|
|||
|
if (this.compiledEntryPoints.has(key)) {
|
|||
|
return [key, val];
|
|||
|
}
|
|||
|
return [key, ['./webpack_non_compiled_placeholder.js']];
|
|||
|
}),
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
logStatus(totalCount) {
|
|||
|
const current = this.compiledEntryPoints.size;
|
|||
|
log(`Currently compiling route entrypoints: ${current} of ${totalCount}`);
|
|||
|
}
|
|||
|
|
|||
|
setupMiddleware(app, server) {
|
|||
|
app.use((req, res, next) => {
|
|||
|
const fileName = path.basename(req.url);
|
|||
|
|
|||
|
/**
|
|||
|
* We are only interested in files that have a name like `pages.foo.bar.chunk.js`
|
|||
|
* because those are the ones corresponding to our entry points.
|
|||
|
*
|
|||
|
* This filters out hot update files that are for example named "pages.foo.bar.[hash].hot-update.js"
|
|||
|
*/
|
|||
|
if (fileName.startsWith('pages.') && fileName.endsWith('.chunk.js')) {
|
|||
|
const chunk = fileName.replace(/\.chunk\.js$/, '');
|
|||
|
|
|||
|
this._addToHistory(chunk);
|
|||
|
|
|||
|
if (!this.compiledEntryPoints.has(chunk)) {
|
|||
|
log(`First time we are seeing ${chunk}. Adding to compilation.`);
|
|||
|
|
|||
|
this.compiledEntryPoints.add(chunk);
|
|||
|
|
|||
|
setTimeout(() => {
|
|||
|
server.middleware.invalidate(() => {
|
|||
|
if (server.sockets) {
|
|||
|
server.sockWrite(server.sockets, 'content-changed');
|
|||
|
}
|
|||
|
});
|
|||
|
}, TIMEOUT);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
next();
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// private methods
|
|||
|
|
|||
|
_addToHistory(chunk) {
|
|||
|
if (!this.history[chunk]) {
|
|||
|
this.history[chunk] = { lastVisit: null, count: 0 };
|
|||
|
}
|
|||
|
this.history[chunk].lastVisit = Date.now();
|
|||
|
this.history[chunk].count += 1;
|
|||
|
|
|||
|
try {
|
|||
|
fs.writeFileSync(this.historyFilePath, JSON.stringify(this.history), 'utf8');
|
|||
|
} catch (e) {
|
|||
|
log('Warning – Could not write to history', e.message);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_loadFromHistory() {
|
|||
|
try {
|
|||
|
this.history = JSON.parse(fs.readFileSync(this.historyFilePath, 'utf8'));
|
|||
|
const entryPoints = Object.keys(this.history);
|
|||
|
log(`Successfully loaded history containing ${entryPoints.length} entry points`);
|
|||
|
/*
|
|||
|
TODO: Let's ask a few folks to give us their history file after a milestone of usage
|
|||
|
Then we can make smarter decisions on when to throw out rather than rendering everything
|
|||
|
Something like top 20/30/40 entries visited in the last 7/10/15 days might be sufficient
|
|||
|
*/
|
|||
|
this.compiledEntryPoints = new Set([...this.compiledEntryPoints, ...entryPoints]);
|
|||
|
} catch (e) {
|
|||
|
log(`No history found...`);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
module.exports = (enabled, historyFilePath) => {
|
|||
|
log(`Status – ${enabled ? 'enabled' : 'disabled'}`);
|
|||
|
|
|||
|
if (enabled) {
|
|||
|
return new IncrementalWebpackCompiler(historyFilePath);
|
|||
|
}
|
|||
|
return new NoopCompiler();
|
|||
|
};
|