UNPKG

3.33 kBJavaScriptView Raw
1/*
2 Copyright © 2018 Andrew Powell
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 The above copyright notice and this permission notice shall be
9 included in all copies or substantial portions of this Source Code Form.
10*/
11const router = require('koa-route');
12const stringify = require('json-stringify-safe');
13const stripAnsi = require('strip-ansi');
14
15const prep = (data) => stringify(data);
16
17const statsOptions = {
18 all: false,
19 cached: true,
20 children: true,
21 hash: true,
22 modules: true,
23 timings: true,
24 exclude: ['node_modules', 'bower_components', 'components']
25};
26
27const setupRoutes = function setupRoutes() {
28 const { app, options } = this;
29 const events = ['build', 'done', 'invalid', 'progress'];
30 const connect = async (ctx) => {
31 if (ctx.ws) {
32 const socket = await ctx.ws();
33 const send = (data) => {
34 if (socket.readyState !== 1) {
35 return;
36 }
37 socket.send(data);
38 };
39
40 socket.build = (compilerName = '<unknown>', { wpsId }) => {
41 send(prep({ action: 'build', data: { compilerName, wpsId } }));
42 };
43
44 socket.done = (stats, { wpsId }) => {
45 const { hash } = stats;
46
47 if (socket.lastHash === hash) {
48 return;
49 }
50
51 send(prep({ action: 'done', data: { hash, wpsId } }));
52
53 socket.lastHash = hash;
54
55 const { errors = [], warnings = [] } = stats.toJson(statsOptions);
56
57 if (errors.length || warnings.length) {
58 send(
59 prep({
60 action: 'problems',
61 data: {
62 errors: errors.slice(0).map((e) => stripAnsi(e)),
63 hash,
64 warnings: warnings.slice(0).map((e) => stripAnsi(e)),
65 wpsId
66 }
67 })
68 );
69
70 if (errors.length) {
71 return;
72 }
73 }
74
75 if (options.hmr || options.liveReload) {
76 const action = options.liveReload ? 'reload' : 'replace';
77 send(prep({ action, data: { hash, wpsId } }));
78 }
79 };
80
81 socket.invalid = (filePath = '<unknown>', compiler) => {
82 const context = compiler.context || compiler.options.context || process.cwd();
83 const fileName = (filePath && filePath.replace && filePath.replace(context, '')) || filePath;
84 const { wpsId } = compiler;
85
86 send(prep({ action: 'invalid', data: { fileName, wpsId } }));
87 };
88
89 socket.progress = (data) => {
90 send(prep({ action: 'progress', data }));
91 };
92
93 for (const event of events) {
94 this.on(event, socket[event]);
95
96 socket.on('close', () => {
97 this.removeListener(event, socket[event]);
98 });
99 }
100
101 // #138. handle emitted events that don't have a listener registered, and forward the message
102 // onto the client via the socket
103 const unhandled = ({ eventName, data }) => send(prep({ action: eventName, data }));
104 this.on('unhandled', unhandled);
105 socket.on('close', () => {
106 this.off('unhandled', unhandled);
107 });
108
109 send(prep({ action: 'connected' }));
110 }
111 };
112
113 app.use(router.get('/wps', connect));
114};
115
116module.exports = { setupRoutes };