Created
October 24, 2020 04:20
-
-
Save huozhi/b72d26de6e1a4f56027e6737451a2a80 to your computer and use it in GitHub Desktop.
webpack5 compile integration test of twilio.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require('path'); | |
const webpack = require('webpack'); | |
const fs = require('fs'); | |
// Based on the NodeWatchFileSystem class at: | |
// - https://github.com/webpack/webpack/blob/master/lib/node/NodeWatchFileSystem.js | |
// which in turn exposes: | |
// - https://www.npmjs.com/package/watchpack | |
class CustomWatchFileSystem { | |
constructor(watchStart, watchEnd) { | |
this.closed = false; | |
// paused allows the watchers to stay open for the next build | |
this.paused = false; | |
this.changeCallback = undefined; | |
this.watchStart = watchStart; | |
this.watchEnd = watchEnd; | |
// Webpack requires us to track this stuff | |
this.files = undefined; | |
this.dirs = undefined; | |
this.missing = undefined; | |
this.timestamps = new Map(); | |
// this will be populated for us by ncc | |
this.inputFileSystem = undefined; | |
} | |
triggerChanges (changed, removed) { | |
if (!this.paused) { | |
const newTime = +Date.now(); | |
for (const file of changed) | |
this.timestamps.set(file, { | |
safeTime: newTime + 10, | |
accuracy: 10, | |
timestamp: newTime | |
}); | |
for (const file of removed) | |
this.timestamps.set(file, null); | |
for (const file of changed) | |
this.inputFileSystem.purge(file); | |
for (const file of removed) | |
this.inputFileSystem.purge(file); | |
this.changeCallback( | |
null, | |
this.timestamps, | |
this.timestamps, | |
removed | |
); | |
} | |
} | |
// This is called on every rebuild | |
watch (files, dirs, missing, startTime, options, changeCallback) { | |
this.files = new Set(files); | |
this.dirs = new Set(dirs); | |
this.missing = new Set(missing); | |
// empty object indicates "unknown" timestamp | |
// (that is, not cached) | |
for (const item of files) | |
this.timestamps.set(item, {}); | |
for (const item of dirs) | |
this.timestamps.set(item, {}); | |
// null represents "no file" | |
for (const item of missing) | |
this.timestamps.set(item, null); | |
this.paused = false; | |
this.changeCallback = changeCallback; | |
// ...Start watching files, dirs, mising | |
setImmediate(() => { | |
this.watchStart(files, dirs, missing); | |
}); | |
return { | |
close: () => { | |
this.watchEnd(); | |
}, | |
pause: () => { | |
this.paused = true; | |
}, | |
getFileTimestamps: () => { | |
return this.timestamps; | |
}, | |
getContextTimestamps: () => { | |
return this.timestamps; | |
} | |
}; | |
} | |
} | |
async function main() { | |
let buildCnt = 0; | |
const buildFile = path.resolve('./twilio.js'); | |
await new Promise((resolve, reject) => { | |
const watcher = new CustomWatchFileSystem(function watchStart (files, dirs, missing) { | |
console.log('db:files', files._set.size) | |
console.log('db:missing', missing._set.size) | |
if (buildCnt < 3) { | |
setTimeout(() => { | |
// NOTE: We actually have to make the change for the rebuild to happen! | |
fs.writeFileSync(buildFile, fs.readFileSync(buildFile).toString() + '\n'); | |
watcher.triggerChanges([buildFile], []); | |
}, 100); | |
} | |
}, function watchEnd () { | |
resolve(); | |
}); | |
console.time('First Build'); | |
const compiler = webpack({ | |
entry: buildFile, | |
}) | |
compiler.watchFileSystem = watcher; | |
watcher.inputFileSystem = compiler.inputFileSystem; | |
let cachedResult; | |
let watchHandler, rebuildHandler; | |
const returnedWatcher = compiler.watch({}, (err, stats) => { | |
if (err) { | |
console.error('db:err', err) | |
return watchHandler({ err }); | |
} | |
if (stats.hasErrors()) { | |
console.error('db:err', stats.toString()) | |
return watchHandler({ err: stats.toString() }); | |
} | |
const returnValue = finalizeHandler(stats); | |
if (watchHandler) | |
watchHandler(returnValue); | |
else | |
cachedResult = returnValue; | |
}); | |
let closed = false; | |
const { handler, rebuild, close } = { | |
close () { | |
if (!returnedWatcher) { | |
console.error('db:err', 'No watcher to close.') | |
throw new Error('No watcher to close.'); | |
} | |
if (closed) { | |
console.error('db:err', 'Watcher already closed.') | |
throw new Error('Watcher already closed.'); | |
} | |
closed = true; | |
returnedWatcher.close(); | |
}, | |
handler (handler) { | |
if (watchHandler) { | |
console.error('db:err', 'Watcher handler already provided.') | |
throw new Error('Watcher handler already provided.'); | |
} | |
watchHandler = handler; | |
if (cachedResult) { | |
handler(cachedResult); | |
cachedResult = null; | |
} | |
}, | |
rebuild (handler) { | |
if (rebuildHandler) { | |
console.error('db:err', 'Rebuild handler already provided.') | |
throw new Error('Rebuild handler already provided.'); | |
} | |
rebuildHandler = handler; | |
} | |
}; | |
handler(({ err, code, map, assets, permissions }) => { | |
if (err) return reject(err); | |
buildCnt++; | |
console.log('db:buildCnt', buildCnt) | |
if (buildCnt === 1) { | |
console.timeEnd('First Build'); | |
} | |
else { | |
console.timeEnd('Watched Build'); | |
} | |
if (buildCnt === 3) { | |
close(); | |
fs.writeFileSync(buildFile, fs.readFileSync(buildFile).toString().slice(0, -2)); | |
} | |
}); | |
rebuild(() => { | |
console.time('Watched Build'); | |
}); | |
}); | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment