diff --git a/lib/utils/create_app.js b/lib/utils/create_app.js index 024028c..a5c2bcc 100644 --- a/lib/utils/create_app.js +++ b/lib/utils/create_app.js @@ -23,4 +23,8 @@ module.exports = function create_app(src, dest, routes, options) { const main = template.replace('__routes__', code); fs.writeFileSync(main_built, main); + + // need to fudge the mtime, because webpack is soft in the head + const stats = fs.statSync(main_built); + fs.utimesSync(main_built, stats.atimeMs - 9999, stats.mtimeMs - 9999); }; \ No newline at end of file diff --git a/lib/utils/create_compiler.js b/lib/utils/create_compiler.js index a748355..fef8f4d 100644 --- a/lib/utils/create_compiler.js +++ b/lib/utils/create_compiler.js @@ -2,72 +2,52 @@ const fs = require('fs'); const path = require('path'); const glob = require('glob'); const webpack = require('webpack'); +const { dev } = require('../config.js'); const templates = require('../templates.js'); module.exports = function create_webpack_compiler(dest, routes, dev) { const compiler = {}; - const client = webpack( - require(path.resolve('webpack.client.config.js')) - ); + function go() { + const client = webpack( + require(path.resolve('webpack.client.config.js')) + ); - const server = webpack( - require(path.resolve('webpack.server.config.js')) - ); + const server = webpack( + require(path.resolve('webpack.server.config.js')) + ); - if (false) { // TODO watch in dev - // TODO how can we invalidate compiler.client_main when watcher restarts? - compiler.client_main = new Promise((fulfil, reject) => { - client.watch({}, (err, stats) => { - if (err || stats.hasErrors()) { - // TODO handle errors - } + function client_updated(err, stats, reject) { + console.log(stats.toString({ colors: true })); - const filename = stats.toJson().assetsByChunkName.main; - fulfil(`/client/${filename}`); + const info = stats.toJson(); + + if (err || stats.hasErrors()) { + reject(err || info.errors[0]); + } + + compiler.client_main = `/client/${info.assetsByChunkName.main}`; + compiler.assets = info.assets.map(asset => `/client/${asset.name}`); + + compiler.asset_cache = {}; + compiler.assets.forEach(file => { + compiler.asset_cache[file] = fs.readFileSync(path.join(dest, file), 'utf-8'); }); - }); + } - // TODO server - } else { - compiler.ready = Promise.all([ - new Promise((fulfil, reject) => { - client.run((err, stats) => { - console.log(stats.toString({ colors: true })); + function server_updated(err, stats, reject) { + console.log(stats.toString({ colors: true })); - const info = stats.toJson(); + const info = stats.toJson(); - if (err || stats.hasErrors()) { - reject(err || info.errors[0]); - } + if (err || stats.hasErrors()) { + reject(err || info.errors[0]); + } - compiler.client_main = `/client/${info.assetsByChunkName.main}`; - compiler.assets = info.assets.map(asset => `/client/${asset.name}`); + compiler.chunks = info.assetsByChunkName; + } - compiler.asset_cache = {}; - compiler.assets.forEach(file => { - compiler.asset_cache[file] = fs.readFileSync(path.join(dest, file), 'utf-8'); - }); - - fulfil(); - }); - }), - - new Promise((fulfil, reject) => { - server.run((err, stats) => { - console.log(stats.toString({ colors: true })); - - const info = stats.toJson(); - - if (err || stats.hasErrors()) { - reject(err || info.errors[0]); - } - - compiler.chunks = info.assetsByChunkName; - fulfil(); - }); - }) - ]).then(() => { + function both_updated() { const assets = glob.sync('**', { cwd: 'assets', nodir: true }); const route_code = `[${ @@ -93,12 +73,65 @@ module.exports = function create_webpack_compiler(dest, routes, dev) { // useful for debugging, but the files are served from memory fs.writeFileSync(path.resolve(dest, 'service-worker.js'), compiler.service_worker); fs.writeFileSync(path.resolve(dest, 'index.html'), compiler.shell); - }); + } - compiler.get_chunk = async id => { - return path.resolve(dest, 'server', compiler.chunks[id]); - }; + if (dev) { + let client_is_ready = false; + let server_is_ready = false; + + let fulfil; + let reject; + + const invalidate = () => new Promise((f, r) => { + fulfil = f; + reject = r; + }); + + compiler.ready = invalidate(); + + client.plugin('invalid', () => { + client_is_ready = false; + compiler.ready = invalidate(); + }); + + server.plugin('invalid', () => { + server_is_ready = false; + compiler.ready = invalidate(); + }); + + client.watch({}, (err, stats) => { + client_updated(err, stats, reject); + client_is_ready = true; + if (server_is_ready) fulfil(); + }); + + server.watch({}, (err, stats) => { + server_updated(err, stats, reject); + server_is_ready = true; + if (client_is_ready) fulfil(); + }); + } else { + compiler.ready = Promise.all([ + new Promise((fulfil, reject) => { + client.run((err, stats) => { + client_updated(err, stats, reject); + fulfil(); + }); + }), + + new Promise((fulfil, reject) => { + server.run((err, stats) => { + server_updated(err, stats, reject); + fulfil(); + }); + }) + ]).then(both_updated); + } } + // TODO rerun go when routes are added/renamed + // (or webpack config/templates change?) + go(); + return compiler; }; \ No newline at end of file