webpack-dev-service 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +17 -0
  3. package/client/cjs/client.cjs +128 -0
  4. package/client/cjs/events.cjs +64 -0
  5. package/client/cjs/hot.cjs +111 -0
  6. package/client/cjs/index.cjs +15 -0
  7. package/client/cjs/main.cjs +53 -0
  8. package/client/cjs/ui/overlay.cjs +236 -0
  9. package/client/cjs/ui/progress.cjs +94 -0
  10. package/client/cjs/ui/utils/ansi/index.cjs +443 -0
  11. package/client/cjs/ui/utils/ansi/regx.cjs +70 -0
  12. package/client/cjs/ui/utils/ansi/utils.cjs +27 -0
  13. package/client/cjs/ui/utils/index.cjs +126 -0
  14. package/client/esm/client.js +126 -0
  15. package/client/esm/events.js +60 -0
  16. package/client/esm/hot.js +106 -0
  17. package/client/esm/index.js +10 -0
  18. package/client/esm/main.js +51 -0
  19. package/client/esm/ui/overlay.js +234 -0
  20. package/client/esm/ui/progress.js +92 -0
  21. package/client/esm/ui/utils/ansi/index.js +441 -0
  22. package/client/esm/ui/utils/ansi/regx.js +66 -0
  23. package/client/esm/ui/utils/ansi/utils.js +24 -0
  24. package/client/esm/ui/utils/index.js +120 -0
  25. package/global.d.ts +14 -0
  26. package/package.json +121 -0
  27. package/server/cjs/dev.cjs +50 -0
  28. package/server/cjs/hot.cjs +216 -0
  29. package/server/cjs/index.cjs +33 -0
  30. package/server/esm/dev.js +42 -0
  31. package/server/esm/hot.js +207 -0
  32. package/server/esm/index.js +25 -0
  33. package/types/client/client.d.ts +13 -0
  34. package/types/client/events.d.ts +35 -0
  35. package/types/client/hot.d.ts +27 -0
  36. package/types/client/index.d.ts +4 -0
  37. package/types/client/main.d.ts +4 -0
  38. package/types/client/message.d.ts +39 -0
  39. package/types/client/ui/overlay.d.ts +19 -0
  40. package/types/client/ui/progress.d.ts +15 -0
  41. package/types/client/ui/utils/ansi/enum.d.ts +12 -0
  42. package/types/client/ui/utils/ansi/index.d.ts +18 -0
  43. package/types/client/ui/utils/ansi/interface.d.ts +68 -0
  44. package/types/client/ui/utils/ansi/regx.d.ts +6 -0
  45. package/types/client/ui/utils/ansi/utils.d.ts +6 -0
  46. package/types/client/ui/utils/index.d.ts +9 -0
  47. package/types/server/dev.d.ts +17 -0
  48. package/types/server/hot.d.ts +16 -0
  49. package/types/server/index.d.ts +42 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.1.0
5
+ * @author nuintun <nuintun@qq.com>
6
+ * @description A koa 2 middleware for webpack development and hot reloading.
7
+ * @see https://github.com/nuintun/webpack-dev-service#readme
8
+ */
9
+
10
+ import Ansi from './ansi/index.js';
11
+
12
+ /**
13
+ * @module utils
14
+ */
15
+ const ansi = new Ansi();
16
+ const defaultStyleElement = document.createElement('style');
17
+ function injectCSS(css, styleElement = defaultStyleElement) {
18
+ const { head } = document;
19
+ styleElement.appendChild(document.createTextNode(css.trim()));
20
+ if (!head.contains(styleElement)) {
21
+ head.appendChild(styleElement);
22
+ }
23
+ return styleElement;
24
+ }
25
+ function appendHTML(html, parent) {
26
+ const nodes = [];
27
+ const parser = new DOMParser();
28
+ const stage = parent || document.body;
29
+ const fragment = document.createDocumentFragment();
30
+ const { body } = parser.parseFromString(html.trim(), 'text/html');
31
+ while (body.firstChild) {
32
+ nodes.push(fragment.appendChild(body.firstChild));
33
+ }
34
+ stage.appendChild(fragment);
35
+ return nodes;
36
+ }
37
+ function escapeHTML(text) {
38
+ return text.replace(/[&<>"']/gm, match => {
39
+ switch (match) {
40
+ case '&':
41
+ return '&amp;';
42
+ case '<':
43
+ return '&lt;';
44
+ case '>':
45
+ return '&gt;';
46
+ case '"':
47
+ return '&quot;';
48
+ case "'":
49
+ return '&#x27;';
50
+ default:
51
+ return match;
52
+ }
53
+ });
54
+ }
55
+ function blockToHTML({ style, value, url }) {
56
+ const styles = [];
57
+ const textDecorations = [];
58
+ if (style.dim) {
59
+ styles.push(`opacity:0.5`);
60
+ }
61
+ if (style.bold) {
62
+ styles.push(`font-weight:bold`);
63
+ }
64
+ if (style.italic) {
65
+ styles.push(`font-style:italic`);
66
+ }
67
+ if (style.inverse) {
68
+ styles.push(`filter:invert(1)`);
69
+ }
70
+ if (style.hidden) {
71
+ styles.push(`visibility:hidden`);
72
+ }
73
+ if (style.blink) {
74
+ textDecorations.push('blink');
75
+ }
76
+ if (style.overline) {
77
+ textDecorations.push('overline');
78
+ }
79
+ if (style.underline) {
80
+ textDecorations.push('underline');
81
+ }
82
+ if (style.strikethrough) {
83
+ textDecorations.push('line-through');
84
+ }
85
+ const { color, background } = style;
86
+ if (color) {
87
+ styles.push(`color:rgb(${color})`);
88
+ }
89
+ if (background) {
90
+ styles.push(`background-color:rgb(${background})`);
91
+ }
92
+ if (textDecorations.length > 0) {
93
+ styles.push(`text-decoration:${textDecorations.join(' ')}`);
94
+ }
95
+ const escapedValue = escapeHTML(value);
96
+ const href = url ? JSON.stringify(escapeHTML(url)) : null;
97
+ if (styles.length <= 0) {
98
+ if (!href) {
99
+ return escapedValue;
100
+ }
101
+ return `<a href=${href} target="_blank">${escapedValue}</a>`;
102
+ }
103
+ const inlineStyle = JSON.stringify(`${styles.join(';')};`);
104
+ if (!href) {
105
+ return `<span style=${inlineStyle}>${escapedValue}</span>`;
106
+ }
107
+ return `<a style=${inlineStyle} href=${href} target="_blank">${escapedValue}</a>`;
108
+ }
109
+ function ansiToHTML(text) {
110
+ let html = '';
111
+ ansi.write(text, block => {
112
+ html += blockToHTML(block);
113
+ });
114
+ ansi.flush(block => {
115
+ html += blockToHTML(block);
116
+ });
117
+ return html;
118
+ }
119
+
120
+ export { ansiToHTML, appendHTML, blockToHTML, escapeHTML, injectCSS };
package/global.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @module global.d.ts
3
+ */
4
+
5
+ /// <reference types="webpack/module" />
6
+
7
+ declare const __WDS_HOT_OPTIONS__: {
8
+ hmr: boolean;
9
+ name: string;
10
+ path: string;
11
+ progress: boolean;
12
+ };
13
+
14
+ declare type HotUpdateStatus = `${webpack.HotUpdateStatus}`;
package/package.json ADDED
@@ -0,0 +1,121 @@
1
+ {
2
+ "name": "webpack-dev-service",
3
+ "version": "0.1.0",
4
+ "description": "A koa 2 middleware for webpack development and hot reloading.",
5
+ "type": "module",
6
+ "sideEffects": [
7
+ "client/esm/main.js",
8
+ "client/cjs/main.cjs"
9
+ ],
10
+ "main": "server/cjs/index.cjs",
11
+ "module": "server/esm/index.js",
12
+ "types": "types/server/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./server/esm/index.js",
16
+ "require": "./server/cjs/index.cjs",
17
+ "types": "./types/server/index.d.ts"
18
+ },
19
+ "./client": {
20
+ "import": "./client/esm/main.js",
21
+ "require": "./client/cjs/main.cjs",
22
+ "types": "./types/client/main.d.ts"
23
+ },
24
+ "./client?*": {
25
+ "import": "./client/esm/main.js",
26
+ "require": "./client/cjs/main.cjs",
27
+ "types": "./types/client/main.d.ts"
28
+ },
29
+ "./events": {
30
+ "import": "./client/esm/index.js",
31
+ "require": "./client/cjs/index.cjs",
32
+ "types": "./types/client/index.d.ts"
33
+ }
34
+ },
35
+ "typesVersions": {
36
+ "*": {
37
+ "client": [
38
+ "./types/client/main.d.ts"
39
+ ],
40
+ "events": [
41
+ "./types/client/index.d.ts"
42
+ ]
43
+ }
44
+ },
45
+ "files": [
46
+ "types",
47
+ "server",
48
+ "client",
49
+ "index.d.ts",
50
+ "client.d.ts",
51
+ "global.d.ts"
52
+ ],
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/nuintun/webpack-dev-service.git"
56
+ },
57
+ "keywords": [
58
+ "dev",
59
+ "koa",
60
+ "server",
61
+ "webpack",
62
+ "middleware"
63
+ ],
64
+ "author": {
65
+ "name": "nuintun",
66
+ "email": "nuintun@qq.com"
67
+ },
68
+ "license": "MIT",
69
+ "bugs": {
70
+ "url": "https://github.com/nuintun/webpack-dev-service/issues"
71
+ },
72
+ "homepage": "https://github.com/nuintun/webpack-dev-service#readme",
73
+ "scripts": {
74
+ "lint": "tsc --noEmit",
75
+ "clean": "node tools/clean.js",
76
+ "format": "prettier --write .",
77
+ "prepublishOnly": "npm run build",
78
+ "test": "cd tests && node webpack.js",
79
+ "build:cjs": "rollup -c tools/rollup.cjs.js",
80
+ "build:esm": "rollup -c tools/rollup.esm.js",
81
+ "build": "npm run clean && npm run build:main && npm run format",
82
+ "build:main": "npm run build:cjs && npm run build:esm && npm run build:types",
83
+ "build:types": "tsc --declaration --emitDeclarationOnly --declarationDir types"
84
+ },
85
+ "dependencies": {
86
+ "@types/koa": "^2.13.6",
87
+ "@types/ws": "^8.5.4",
88
+ "koa-compose": "^4.1.0",
89
+ "tslib": "^2.5.0",
90
+ "webpack-dev-middleware": "^6.1.0",
91
+ "ws": "^8.13.0"
92
+ },
93
+ "devDependencies": {
94
+ "@rollup/plugin-typescript": "^11.1.0",
95
+ "@swc/core": "^1.3.57",
96
+ "@swc/helpers": "^0.5.1",
97
+ "@types/koa-compose": "^3.2.5",
98
+ "@types/node": "^20.1.2",
99
+ "css-loader": "^6.7.3",
100
+ "html-webpack-plugin": "^5.5.1",
101
+ "koa": "^2.14.2",
102
+ "magic-string": "^0.30.0",
103
+ "memfs": "^3.5.1",
104
+ "mini-css-extract-plugin": "^2.7.5",
105
+ "prettier": "^2.8.8",
106
+ "react": "^18.2.0",
107
+ "react-dom": "^18.2.0",
108
+ "rimraf": "^5.0.0",
109
+ "rollup": "^3.21.6",
110
+ "swc-loader": "^0.2.3",
111
+ "typescript": "^5.0.4",
112
+ "webpack": "^5.82.1"
113
+ },
114
+ "optionalDependencies": {
115
+ "bufferutil": ">=4.0.0",
116
+ "utf-8-validate": ">=5.0.0"
117
+ },
118
+ "peerDependencies": {
119
+ "webpack": "^5.0.0"
120
+ }
121
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.1.0
5
+ * @author nuintun <nuintun@qq.com>
6
+ * @description A koa 2 middleware for webpack development and hot reloading.
7
+ * @see https://github.com/nuintun/webpack-dev-service#readme
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const webpackDevMiddleware = require('webpack-dev-middleware');
13
+
14
+ function _interopDefault(e) {
15
+ return e && e.__esModule ? e : { default: e };
16
+ }
17
+
18
+ const webpackDevMiddleware__default = /*#__PURE__*/ _interopDefault(webpackDevMiddleware);
19
+
20
+ /**
21
+ * @module dev
22
+ */
23
+ function dev(compiler, options) {
24
+ const middleware = webpackDevMiddleware__default.default(compiler, options);
25
+ const devMiddleware = async (context, next) => {
26
+ context.remove('Content-Type');
27
+ await middleware(
28
+ context.req,
29
+ {
30
+ locals: context.state,
31
+ send(body) {
32
+ context.body = body;
33
+ },
34
+ status(statusCode) {
35
+ context.status = statusCode;
36
+ },
37
+ set(field, value) {
38
+ context.response.set(field, value);
39
+ },
40
+ get(field) {
41
+ return context.response.get(field);
42
+ }
43
+ },
44
+ next
45
+ );
46
+ };
47
+ return Object.assign(devMiddleware, middleware);
48
+ }
49
+
50
+ module.exports = dev;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.1.0
5
+ * @author nuintun <nuintun@qq.com>
6
+ * @description A koa 2 middleware for webpack development and hot reloading.
7
+ * @see https://github.com/nuintun/webpack-dev-service#readme
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const WebSocket = require('ws');
13
+ const webpack = require('webpack');
14
+
15
+ function _interopDefault(e) {
16
+ return e && e.__esModule ? e : { default: e };
17
+ }
18
+
19
+ const WebSocket__default = /*#__PURE__*/ _interopDefault(WebSocket);
20
+ const webpack__default = /*#__PURE__*/ _interopDefault(webpack);
21
+
22
+ /**
23
+ * @module hot
24
+ */
25
+ const WEBSOCKET_RE = /^websocket$/i;
26
+ function isObject(value) {
27
+ return Object.prototype.toString.call(value) === '[object Object]';
28
+ }
29
+ function resolveStatsOptions(compiler) {
30
+ const options = {
31
+ all: false,
32
+ hash: true,
33
+ colors: true,
34
+ errors: true,
35
+ assets: false,
36
+ builtAt: true,
37
+ warnings: true,
38
+ errorDetails: false
39
+ };
40
+ const { stats } = compiler.options;
41
+ if (isObject(stats)) {
42
+ const { warningsFilter } = stats;
43
+ if (warningsFilter !== undefined) {
44
+ options.warningsFilter = warningsFilter;
45
+ }
46
+ }
47
+ return options;
48
+ }
49
+ function normalize(path) {
50
+ const segments = [];
51
+ const parts = path.split(/[\\/]+/);
52
+ for (const segment of parts) {
53
+ switch (segment) {
54
+ case '.':
55
+ break;
56
+ case '..':
57
+ segments.pop();
58
+ break;
59
+ default:
60
+ segments.push(segment);
61
+ break;
62
+ }
63
+ }
64
+ const pathname = segments.join('/');
65
+ return pathname.startsWith('/') ? pathname : `/${pathname}`;
66
+ }
67
+ function resolveOptions(options) {
68
+ const settings = {
69
+ hmr: true,
70
+ path: '/hot',
71
+ progress: true,
72
+ ...options
73
+ };
74
+ settings.path = normalize(settings.path);
75
+ return settings;
76
+ }
77
+ function isUpgradable(context, detector) {
78
+ const { upgrade } = context.headers;
79
+ return !!upgrade && detector.test(upgrade.trim());
80
+ }
81
+ function hasProblems(problems) {
82
+ return !!problems && problems.length > 0;
83
+ }
84
+ class HotServer {
85
+ stats;
86
+ compiler;
87
+ server;
88
+ options;
89
+ name = 'webpack-hot-middleware';
90
+ logger;
91
+ constructor(compiler, options) {
92
+ this.compiler = compiler;
93
+ this.options = resolveOptions(options);
94
+ this.logger = compiler.getInfrastructureLogger(this.name);
95
+ this.server = new WebSocket.WebSocketServer({ path: this.options.path, noServer: true });
96
+ this.setup();
97
+ }
98
+ setup() {
99
+ this.setupWss();
100
+ this.setupHooks();
101
+ this.setupPlugins();
102
+ }
103
+ setupWss() {
104
+ const { server, logger } = this;
105
+ server.on('error', error => {
106
+ logger.error(error.message);
107
+ });
108
+ server.on('connection', client => {
109
+ if (this.stats) {
110
+ this.broadcastStats([client], this.stats);
111
+ }
112
+ });
113
+ }
114
+ setupHooks() {
115
+ const { compiler } = this;
116
+ const { hooks } = compiler;
117
+ const statsOptions = resolveStatsOptions(compiler);
118
+ hooks.done.tapAsync(this.name, (stats, next) => {
119
+ next();
120
+ this.stats = stats.toJson(statsOptions);
121
+ this.broadcastStats(this.clients(), this.stats);
122
+ });
123
+ hooks.invalid.tap(this.name, (path, builtAt) => {
124
+ this.broadcast(this.clients(), 'invalid', { path, builtAt });
125
+ });
126
+ }
127
+ setupPlugins() {
128
+ const { options, compiler } = this;
129
+ const plugins = [
130
+ new webpack__default.default.NoEmitOnErrorsPlugin(),
131
+ new webpack__default.default.DefinePlugin({
132
+ __WDS_HOT_OPTIONS__: JSON.stringify({ ...options, name: compiler.name })
133
+ })
134
+ ];
135
+ if (options.hmr) {
136
+ plugins.push(new webpack__default.default.HotModuleReplacementPlugin());
137
+ }
138
+ if (options.progress) {
139
+ let value = 0;
140
+ plugins.push(
141
+ new webpack__default.default.ProgressPlugin((percentage, status, message) => {
142
+ const nextValue = Math.floor(percentage * 100);
143
+ if (nextValue > value || nextValue === 0) {
144
+ value = nextValue;
145
+ switch (value) {
146
+ case 0:
147
+ status = 'start';
148
+ message = 'end idle';
149
+ break;
150
+ case 100:
151
+ status = 'finish';
152
+ message = 'begin idle';
153
+ break;
154
+ }
155
+ this.broadcast(this.clients(), 'progress', { status, message, value });
156
+ }
157
+ })
158
+ );
159
+ }
160
+ for (const plugin of plugins) {
161
+ plugin.apply(compiler);
162
+ }
163
+ }
164
+ clients() {
165
+ return this.server.clients;
166
+ }
167
+ upgrade(context) {
168
+ const { server } = this;
169
+ const { req: request } = context;
170
+ if (isUpgradable(context, WEBSOCKET_RE) && server.shouldHandle(request)) {
171
+ context.respond = false;
172
+ const { socket } = context;
173
+ const head = Buffer.alloc(0);
174
+ server.handleUpgrade(request, socket, head, client => {
175
+ server.emit('connection', client, request);
176
+ });
177
+ return true;
178
+ }
179
+ return false;
180
+ }
181
+ broadcast(clients, action, payload) {
182
+ for (const client of clients) {
183
+ if (client.readyState === WebSocket__default.default.OPEN) {
184
+ client.send(JSON.stringify({ action, payload }));
185
+ }
186
+ }
187
+ }
188
+ broadcastStats(clients, stats) {
189
+ if (clients.size > 0 || clients.length > 0) {
190
+ const { hash, builtAt, errors, warnings } = stats;
191
+ this.broadcast(clients, 'hash', { hash });
192
+ if (hasProblems(errors) || hasProblems(warnings)) {
193
+ this.broadcast(clients, 'problems', { errors, warnings, builtAt });
194
+ } else {
195
+ this.broadcast(clients, 'ok', { builtAt });
196
+ }
197
+ }
198
+ }
199
+ }
200
+ function hot(compiler, options = {}) {
201
+ const server = new HotServer(compiler, options);
202
+ const hotMiddleware = async (context, next) => {
203
+ if (!server.upgrade(context)) {
204
+ await next();
205
+ }
206
+ };
207
+ hotMiddleware.clients = () => {
208
+ return server.clients();
209
+ };
210
+ hotMiddleware.broadcast = (clients, action, payload) => {
211
+ server.broadcast(clients, action, payload);
212
+ };
213
+ return hotMiddleware;
214
+ }
215
+
216
+ module.exports = hot;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.1.0
5
+ * @author nuintun <nuintun@qq.com>
6
+ * @description A koa 2 middleware for webpack development and hot reloading.
7
+ * @see https://github.com/nuintun/webpack-dev-service#readme
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const compose = require('koa-compose');
13
+ const dev = require('./dev.cjs');
14
+ const hot = require('./hot.cjs');
15
+
16
+ function _interopDefault(e) {
17
+ return e && e.__esModule ? e : { default: e };
18
+ }
19
+
20
+ const compose__default = /*#__PURE__*/ _interopDefault(compose);
21
+
22
+ /**
23
+ * @module index
24
+ */
25
+ function server(compiler, options = {}) {
26
+ const { hot: hotOptions, ...devOptions } = options;
27
+ const devMiddleware = dev(compiler, devOptions);
28
+ if (hotOptions === false) return devMiddleware;
29
+ const hotMiddleware = hot(compiler, hotOptions);
30
+ return Object.assign(compose__default.default([devMiddleware, hotMiddleware]), devMiddleware, hotMiddleware);
31
+ }
32
+
33
+ module.exports = server;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.1.0
5
+ * @author nuintun <nuintun@qq.com>
6
+ * @description A koa 2 middleware for webpack development and hot reloading.
7
+ * @see https://github.com/nuintun/webpack-dev-service#readme
8
+ */
9
+
10
+ import webpackDevMiddleware from 'webpack-dev-middleware';
11
+
12
+ /**
13
+ * @module dev
14
+ */
15
+ function dev(compiler, options) {
16
+ const middleware = webpackDevMiddleware(compiler, options);
17
+ const devMiddleware = async (context, next) => {
18
+ context.remove('Content-Type');
19
+ await middleware(
20
+ context.req,
21
+ {
22
+ locals: context.state,
23
+ send(body) {
24
+ context.body = body;
25
+ },
26
+ status(statusCode) {
27
+ context.status = statusCode;
28
+ },
29
+ set(field, value) {
30
+ context.response.set(field, value);
31
+ },
32
+ get(field) {
33
+ return context.response.get(field);
34
+ }
35
+ },
36
+ next
37
+ );
38
+ };
39
+ return Object.assign(devMiddleware, middleware);
40
+ }
41
+
42
+ export { dev as default };