Skip to content

Commit f635547

Browse files
committed
Add a custom StatusFilePlugin for webpack.
The plugin creates a file that says whether webpack is running, has succeeded, or has failed. front.py reads the file and waits for the build to finish if it's currently in progress. This is essentially a custom substitute for webpack-dev-server. We could use that instead, but I couldn't find a way to configure it to do what I want. webpack-dev-server has two modes: inline mode and iframe mode. In inline mode, it injects its own client library into every bundle. This is a problem for Votr since we load both prologue.?.js and votr.?.js on every page. In iframe mode, they are separated into different frames, but the server on being on top and putting Votr in the iframe, not vice versa. When Votr navigates to another URL or changes the page title, the user won't see. There might be a third option to load /webpack-dev-server.js as a separate script in front.py, but it is not documented anywhere. The documentation is lacking in general. It's also arguable if we even want automatic refresh after every rebuild, when AIS requests can take so long. Hot module reloading could solve that, but it's also more difficult to configure. We can take another look later.
1 parent 41d1ee0 commit f635547

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

votrfront/front.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
import os
33
import json
4+
import time
45
import traceback
56
from werkzeug.routing import Rule
67
from werkzeug.wrappers import Response
@@ -67,6 +68,21 @@ def app_response(request, **my_data):
6768
if 'csrf_token' not in my_data:
6869
my_data['servers'] = request.app.settings.servers
6970

71+
for i in range(60):
72+
try:
73+
with open(static_path + 'status') as f:
74+
status = f.read().strip()
75+
except FileNotFoundError:
76+
return Response('Missing static files.', status=500)
77+
if status != 'busy':
78+
break
79+
time.sleep(0.1)
80+
else:
81+
return Response('Timed out waiting for webpack.', status=500)
82+
83+
if status == 'failed':
84+
return Response('Webpack build failed.', status=500)
85+
7086
if not os.path.exists(static_path + 'ok'):
7187
return Response('buildstatic failed!', status=500)
7288

webpack.config.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,33 @@ function importerWhichRewritesBootstrapNormalizeScss(url, prev, done) {
3232

3333
const outputPath = __dirname + '/votrfront/static';
3434

35+
// A plugin which writes the current status to votrfront/static/status.
36+
// - "busy" during compilation
37+
// - "failed" on errors
38+
// - "ok_dev" or "ok_prod" on success
39+
// votrfront/front.py reads the status to check if it can serve the page.
40+
function StatusFilePlugin(mode) {
41+
this.apply = function(compiler) {
42+
function writeStatus(content, callback) {
43+
fs.mkdir(outputPath, function (err) {
44+
if (err && err.code != 'EEXIST') return callback(err);
45+
fs.writeFile(outputPath + '/status', content + '\n', 'utf8', callback);
46+
});
47+
}
48+
49+
function handleRunEvent(compilationParams, callback) {
50+
writeStatus('busy', callback);
51+
}
52+
53+
compiler.hooks.run.tapAsync('StatusFilePlugin', handleRunEvent);
54+
compiler.hooks.watchRun.tapAsync('StatusFilePlugin', handleRunEvent);
55+
compiler.hooks.done.tapAsync('StatusFilePlugin', (stats, callback) => {
56+
const status = stats.compilation.errors.length ? 'failed' : 'ok_' + mode;
57+
writeStatus(status, callback);
58+
});
59+
};
60+
}
61+
3562
module.exports = function (env, args) {
3663
const mode = args.mode;
3764

@@ -47,6 +74,7 @@ module.exports = function (env, args) {
4774
},
4875
plugins: [
4976
new MiniCssExtractPlugin({ filename: 'style.css' }),
77+
new StatusFilePlugin(mode == 'development' ? 'dev' : 'prod'),
5078
],
5179
module: {
5280
rules: [

0 commit comments

Comments
 (0)