1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | const router = require('koa-route');
|
12 | const stringify = require('json-stringify-safe');
|
13 | const stripAnsi = require('strip-ansi');
|
14 |
|
15 | const prep = (data) => stringify(data);
|
16 |
|
17 | const 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 |
|
27 | const 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 |
|
102 |
|
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 |
|
116 | module.exports = { setupRoutes };
|