webpack-dev-service 0.10.0 → 0.10.2

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 (57) hide show
  1. package/cjs/client/client.cjs +128 -0
  2. package/cjs/client/events.cjs +64 -0
  3. package/cjs/client/hot.cjs +111 -0
  4. package/cjs/client/index.cjs +15 -0
  5. package/cjs/client/main.cjs +59 -0
  6. package/cjs/client/ui/overlay.cjs +233 -0
  7. package/cjs/client/ui/progress.cjs +92 -0
  8. package/cjs/client/ui/utils.cjs +136 -0
  9. package/cjs/server/compose.cjs +56 -0
  10. package/cjs/server/dev/Service.cjs +269 -0
  11. package/cjs/server/dev/index.cjs +60 -0
  12. package/cjs/server/dev/middleware.cjs +96 -0
  13. package/cjs/server/dev/utils/fs.cjs +29 -0
  14. package/cjs/server/dev/utils/hash.cjs +46 -0
  15. package/cjs/server/dev/utils/http.cjs +227 -0
  16. package/cjs/server/dev/utils/path.cjs +46 -0
  17. package/cjs/server/dev/utils/paths.cjs +59 -0
  18. package/cjs/server/dev/utils/ready.cjs +23 -0
  19. package/cjs/server/dev/utils/setupHooks.cjs +106 -0
  20. package/cjs/server/dev/utils/setupOutputFileSystem.cjs +31 -0
  21. package/cjs/server/dev/utils/setupWatching.cjs +43 -0
  22. package/cjs/server/dev/utils/setupWriteToDisk.cjs +54 -0
  23. package/cjs/server/hot/Socket.cjs +185 -0
  24. package/cjs/server/hot/index.cjs +34 -0
  25. package/cjs/server/hot/utils.cjs +100 -0
  26. package/cjs/server/index.cjs +1 -1
  27. package/cjs/server/schema.cjs +127 -0
  28. package/cjs/server/utils.cjs +45 -0
  29. package/esm/client/client.js +126 -0
  30. package/esm/client/events.js +60 -0
  31. package/esm/client/hot.js +106 -0
  32. package/esm/client/index.js +10 -0
  33. package/esm/client/main.js +57 -0
  34. package/esm/client/ui/overlay.js +231 -0
  35. package/esm/client/ui/progress.js +90 -0
  36. package/esm/client/ui/utils.js +123 -0
  37. package/esm/server/compose.js +54 -0
  38. package/esm/server/dev/Service.js +260 -0
  39. package/esm/server/dev/index.js +58 -0
  40. package/esm/server/dev/middleware.js +94 -0
  41. package/esm/server/dev/utils/fs.js +27 -0
  42. package/esm/server/dev/utils/hash.js +44 -0
  43. package/esm/server/dev/utils/http.js +216 -0
  44. package/esm/server/dev/utils/path.js +42 -0
  45. package/esm/server/dev/utils/paths.js +57 -0
  46. package/esm/server/dev/utils/ready.js +21 -0
  47. package/esm/server/dev/utils/setupHooks.js +98 -0
  48. package/esm/server/dev/utils/setupOutputFileSystem.js +29 -0
  49. package/esm/server/dev/utils/setupWatching.js +41 -0
  50. package/esm/server/dev/utils/setupWriteToDisk.js +52 -0
  51. package/esm/server/hot/Socket.js +176 -0
  52. package/esm/server/hot/index.js +32 -0
  53. package/esm/server/hot/utils.js +93 -0
  54. package/esm/server/index.js +37 -0
  55. package/esm/server/schema.js +125 -0
  56. package/esm/server/utils.js +37 -0
  57. package/package.json +4 -4
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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 Ansi = require('@nuintun/ansi');
13
+
14
+ function _interopDefault(e) {
15
+ return e && e.__esModule ? e : { default: e };
16
+ }
17
+
18
+ const Ansi__default = /*#__PURE__*/ _interopDefault(Ansi);
19
+
20
+ /**
21
+ * @module utils
22
+ */
23
+ const ansi = new Ansi__default.default();
24
+ function escapeHTML(text) {
25
+ return text.replace(/[&<>"']/gm, match => {
26
+ switch (match) {
27
+ case '&':
28
+ return '&amp;';
29
+ case '<':
30
+ return '&lt;';
31
+ case '>':
32
+ return '&gt;';
33
+ case '"':
34
+ return '&quot;';
35
+ case "'":
36
+ return '&#x27;';
37
+ default:
38
+ return match;
39
+ }
40
+ });
41
+ }
42
+ function blockToHTML({ style, value, url }) {
43
+ const styles = [];
44
+ const textDecorations = [];
45
+ if (style.dim) {
46
+ styles.push(`opacity: 0.5`);
47
+ }
48
+ if (style.bold) {
49
+ styles.push(`font-weight: bold`);
50
+ }
51
+ if (style.italic) {
52
+ styles.push(`font-style: italic`);
53
+ }
54
+ if (style.inverse) {
55
+ styles.push(`filter: invert(1)`);
56
+ }
57
+ if (style.hidden) {
58
+ styles.push(`visibility: hidden`);
59
+ }
60
+ if (style.blink) {
61
+ textDecorations.push('blink');
62
+ }
63
+ if (style.overline) {
64
+ textDecorations.push('overline');
65
+ }
66
+ if (style.underline) {
67
+ textDecorations.push('underline');
68
+ }
69
+ if (style.strikethrough) {
70
+ textDecorations.push('line-through');
71
+ }
72
+ const { color, background } = style;
73
+ if (color) {
74
+ styles.push(`color: rgb(${color})`);
75
+ }
76
+ if (background) {
77
+ styles.push(`background-color: rgb(${background})`);
78
+ }
79
+ if (textDecorations.length > 0) {
80
+ styles.push(`text-decoration: ${textDecorations.join(' ')}`);
81
+ }
82
+ const escapedValue = escapeHTML(value);
83
+ const href = url ? JSON.stringify(new URL(url).toString()) : null;
84
+ if (styles.length <= 0) {
85
+ if (!href) {
86
+ return escapedValue;
87
+ }
88
+ return `<a href=${href} target="_blank">${escapedValue}</a>`;
89
+ }
90
+ const inlineStyle = JSON.stringify(`${styles.join('; ')};`);
91
+ if (!href) {
92
+ return `<span style=${inlineStyle}>${escapedValue}</span>`;
93
+ }
94
+ return `<a style=${inlineStyle} href=${href} target="_blank">${escapedValue}</a>`;
95
+ }
96
+ function ansiToHTML(text) {
97
+ let html = '';
98
+ ansi.write(text, block => {
99
+ html += blockToHTML(block);
100
+ });
101
+ ansi.flush(block => {
102
+ html += blockToHTML(block);
103
+ });
104
+ return html;
105
+ }
106
+ function getRootElement(tagName) {
107
+ const stage = document.createElement(tagName);
108
+ const root = stage.attachShadow({ mode: 'closed' });
109
+ document.body.appendChild(stage);
110
+ return root;
111
+ }
112
+ function injectCSS(css, root = document.body, styleElement = document.createElement('style')) {
113
+ styleElement.appendChild(document.createTextNode(css.trim()));
114
+ if (!root.contains(styleElement)) {
115
+ root.appendChild(styleElement);
116
+ }
117
+ return styleElement;
118
+ }
119
+ function appendHTML(html, root = document.body) {
120
+ const nodes = [];
121
+ const parser = new DOMParser();
122
+ const fragment = document.createDocumentFragment();
123
+ const { body } = parser.parseFromString(html.trim(), 'text/html');
124
+ while (body.firstChild) {
125
+ nodes.push(fragment.appendChild(body.firstChild));
126
+ }
127
+ root.appendChild(fragment);
128
+ return nodes;
129
+ }
130
+
131
+ exports.ansiToHTML = ansiToHTML;
132
+ exports.appendHTML = appendHTML;
133
+ exports.blockToHTML = blockToHTML;
134
+ exports.escapeHTML = escapeHTML;
135
+ exports.getRootElement = getRootElement;
136
+ exports.injectCSS = injectCSS;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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
+ /**
13
+ * @module compose
14
+ */
15
+ /**
16
+ * @function dispatch
17
+ * @param middlewares 中间件数组
18
+ * @param index 要执行的中间件索引
19
+ * @param stack 调用栈信息
20
+ * @param context 执行上下文
21
+ * @param [next] 下一个中间件
22
+ */
23
+ async function dispatch(middlewares, index, stack, context, next) {
24
+ if (index <= stack.index) {
25
+ throw new Error('next() called multiple times');
26
+ }
27
+ stack.index = index;
28
+ const { length } = middlewares;
29
+ if (index < length) {
30
+ const middleware = middlewares[index];
31
+ await middleware(context, () => {
32
+ return dispatch(middlewares, index + 1, stack, context, next);
33
+ });
34
+ } else if (next) {
35
+ await next();
36
+ }
37
+ }
38
+ /**
39
+ * @function compose
40
+ * @description 生成融合中间件
41
+ * @param middlewares 中间件数组
42
+ */
43
+ function compose(...middlewares) {
44
+ /**
45
+ * @function middleware
46
+ * @description 融合中间件
47
+ * @param context 执行上下文
48
+ * @param [next] 下一个中间件
49
+ */
50
+ return (context, next) => {
51
+ const stack = { index: -1 };
52
+ return dispatch(middlewares, 0, stack, context, next);
53
+ };
54
+ }
55
+
56
+ exports.compose = compose;
@@ -0,0 +1,269 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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 createEtag = require('etag');
13
+ const destroy = require('destroy');
14
+ const stream = require('stream');
15
+ const utils = require('../utils.cjs');
16
+ const fs = require('./utils/fs.cjs');
17
+ const path$1 = require('path');
18
+ const path = require('./utils/path.cjs');
19
+ const http = require('./utils/http.cjs');
20
+
21
+ function _interopDefault(e) {
22
+ return e && e.__esModule ? e : { default: e };
23
+ }
24
+
25
+ const createEtag__default = /*#__PURE__*/ _interopDefault(createEtag);
26
+ const destroy__default = /*#__PURE__*/ _interopDefault(destroy);
27
+
28
+ /**
29
+ * @module Service
30
+ */
31
+ /**
32
+ * @class Service
33
+ */
34
+ class Service {
35
+ /**
36
+ * @constructor
37
+ * @description Create file service.
38
+ * @param root File service root.
39
+ * @param options File service options.
40
+ */
41
+ constructor(root, options) {
42
+ this.options = options;
43
+ this.root = path.unixify(path$1.resolve(root));
44
+ }
45
+ /**
46
+ * @private
47
+ * @method isIgnore
48
+ * @description Check if path is ignore.
49
+ * @param path File path.
50
+ */
51
+ isIgnore(path) {
52
+ const { ignore } = this.options;
53
+ return (utils.isFunction(ignore) ? ignore(path) : false) === true;
54
+ }
55
+ /**
56
+ * @private
57
+ * @method setupHeaders
58
+ * @description Setup headers
59
+ * @param context Koa context
60
+ * @param path File path
61
+ * @param stats File stats
62
+ */
63
+ setupHeaders(context, path, stats) {
64
+ const { options } = this;
65
+ const { headers, etag } = options;
66
+ // Set status.
67
+ context.status = 200;
68
+ // Set Content-Type.
69
+ context.type = path$1.extname(path);
70
+ // Accept-Ranges.
71
+ if (options.acceptRanges === false) {
72
+ // Set Accept-Ranges to none tell client not support.
73
+ context.set('Accept-Ranges', 'none');
74
+ } else {
75
+ // Set Accept-Ranges.
76
+ context.set('Accept-Ranges', 'bytes');
77
+ }
78
+ // ETag.
79
+ if (etag === false) {
80
+ // Remove ETag.
81
+ context.remove('ETag');
82
+ } else {
83
+ // Set ETag.
84
+ context.set('ETag', createEtag__default.default(stats));
85
+ }
86
+ // Last-Modified.
87
+ if (options.lastModified === false) {
88
+ // Remove Last-Modified.
89
+ context.remove('Last-Modified');
90
+ } else {
91
+ // Set mtime utc string.
92
+ context.set('Last-Modified', stats.mtime.toUTCString());
93
+ }
94
+ // Set headers.
95
+ if (headers) {
96
+ if (utils.isFunction(headers)) {
97
+ const fields = headers(path, stats);
98
+ if (fields) {
99
+ context.set(fields);
100
+ }
101
+ } else {
102
+ context.set(headers);
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * @private
108
+ * @method write
109
+ * @description Write file to stream.
110
+ * @param stream Destination stream.
111
+ * @param path The file path to read.
112
+ * @param range The range to read.
113
+ * @param end Is destory destination stream after read complete.
114
+ */
115
+ write(stream, path, range, end) {
116
+ const { fs } = this.options;
117
+ return new Promise(resolve => {
118
+ // Range prefix and suffix.
119
+ const { prefix, suffix } = range;
120
+ // Create file stream reader.
121
+ const reader = fs.createReadStream(path, range);
122
+ // File read stream open.
123
+ if (prefix) {
124
+ reader.once('open', () => {
125
+ // Write prefix boundary.
126
+ stream.write(prefix);
127
+ });
128
+ }
129
+ // File read stream end.
130
+ if (suffix) {
131
+ reader.once('end', () => {
132
+ // Push suffix boundary.
133
+ stream.write(suffix);
134
+ });
135
+ }
136
+ // File read stream error.
137
+ reader.once('error', () => {
138
+ // End stream.
139
+ stream.end();
140
+ // Unpipe.
141
+ reader.unpipe();
142
+ // Destroy.
143
+ destroy__default.default(reader);
144
+ // Resolve.
145
+ resolve(false);
146
+ });
147
+ // File read stream close.
148
+ reader.once('close', () => {
149
+ // Unpipe.
150
+ reader.unpipe();
151
+ // Destroy.
152
+ destroy__default.default(reader);
153
+ // Resolve.
154
+ resolve(true);
155
+ });
156
+ // Write data to buffer.
157
+ reader.pipe(stream, { end });
158
+ });
159
+ }
160
+ /**
161
+ * @private
162
+ * @method send
163
+ * @description Send file.
164
+ * @param context Koa context.
165
+ * @param path File path.
166
+ * @param ranges Read ranges.
167
+ */
168
+ async send(context, path, ranges) {
169
+ // Set stream body, highWaterMark 64kb.
170
+ const stream$1 = new stream.PassThrough({
171
+ highWaterMark: 65536
172
+ });
173
+ // Set response body.
174
+ context.body = stream$1;
175
+ // Ranges length.
176
+ let { length } = ranges;
177
+ // Write ranges to stream.
178
+ for (const range of ranges) {
179
+ // Write range.
180
+ const passed = await this.write(stream$1, path, range, --length === 0);
181
+ // If not passed, break.
182
+ if (!passed) {
183
+ break;
184
+ }
185
+ }
186
+ }
187
+ /**
188
+ * @public
189
+ * @method response
190
+ * @description Response to koa context.
191
+ * @param context Koa context.
192
+ */
193
+ async response(context) {
194
+ const { root } = this;
195
+ // Only support GET and HEAD (405).
196
+ if (context.method !== 'GET' && context.method !== 'HEAD') {
197
+ return false;
198
+ }
199
+ // Get path of file.
200
+ const path$2 = path.unixify(path$1.join(root, context.path));
201
+ // Malicious path (403).
202
+ if (path.isOutRoot(path$2, root)) {
203
+ return false;
204
+ }
205
+ // Is ignore path or file (403).
206
+ if (this.isIgnore(path$2)) {
207
+ return false;
208
+ }
209
+ // File stats.
210
+ const stats = await fs.stat(this.options.fs, path$2);
211
+ // Check file stats.
212
+ if (
213
+ // File not exist (404 | 500).
214
+ stats == null ||
215
+ // Is directory (403).
216
+ stats.isDirectory() ||
217
+ // Not a directory but has trailing slash (404).
218
+ path.hasTrailingSlash(path$2)
219
+ ) {
220
+ return false;
221
+ }
222
+ // Setup headers.
223
+ this.setupHeaders(context, path$2, stats);
224
+ // Conditional get support.
225
+ if (http.isConditionalGET(context)) {
226
+ // Request precondition failure.
227
+ if (http.isPreconditionFailure(context)) {
228
+ return context.throw(412);
229
+ }
230
+ // Request fresh (304).
231
+ if (context.fresh) {
232
+ // Set status.
233
+ context.status = 304;
234
+ // Set body null.
235
+ context.body = null;
236
+ // File found.
237
+ return true;
238
+ }
239
+ }
240
+ // Head request.
241
+ if (context.method === 'HEAD') {
242
+ // Set Content-Length.
243
+ context.length = stats.size;
244
+ // Set body null
245
+ context.body = null;
246
+ // File found.
247
+ return true;
248
+ }
249
+ // Parsed ranges.
250
+ const ranges = http.parseRanges(context, stats);
251
+ // 416
252
+ if (ranges === -1) {
253
+ // Set Content-Range.
254
+ context.set('Content-Range', `bytes */${stats.size}`);
255
+ // Unsatisfiable 416.
256
+ return context.throw(416);
257
+ }
258
+ // 400.
259
+ if (ranges === -2) {
260
+ return context.throw(400);
261
+ }
262
+ // Send file.
263
+ this.send(context, path$2, ranges);
264
+ // File found.
265
+ return true;
266
+ }
267
+ }
268
+
269
+ exports.Service = Service;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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 ready = require('./utils/ready.cjs');
13
+ const middleware = require('./middleware.cjs');
14
+ const utils = require('../utils.cjs');
15
+ const setupHooks = require('./utils/setupHooks.cjs');
16
+ const setupWatching = require('./utils/setupWatching.cjs');
17
+ const setupWriteToDisk = require('./utils/setupWriteToDisk.cjs');
18
+ const setupOutputFileSystem = require('./utils/setupOutputFileSystem.cjs');
19
+
20
+ /**
21
+ * @module index
22
+ */
23
+ function setup(compiler, options) {
24
+ const context = {
25
+ options,
26
+ compiler,
27
+ stats: null,
28
+ callbacks: [],
29
+ logger: compiler.getInfrastructureLogger(utils.PLUGIN_NAME)
30
+ };
31
+ setupHooks.setupHooks(context);
32
+ if (options.writeToDisk) {
33
+ setupWriteToDisk.setupWriteToDisk(context);
34
+ }
35
+ setupOutputFileSystem.setupOutputFileSystem(context);
36
+ setupWatching.setupWatching(context);
37
+ return context;
38
+ }
39
+ function dev(compiler, options) {
40
+ const context = setup(compiler, options);
41
+ return Object.assign(middleware.middleware(context), {
42
+ get state() {
43
+ return !!context.stats;
44
+ },
45
+ get logger() {
46
+ return context.logger;
47
+ },
48
+ ready(callback) {
49
+ ready.ready(context, callback);
50
+ },
51
+ close(callback) {
52
+ context.watching.close(callback);
53
+ },
54
+ invalidate(callback) {
55
+ context.watching.invalidate(callback);
56
+ }
57
+ });
58
+ }
59
+
60
+ exports.dev = dev;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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 Service = require('./Service.cjs');
13
+ const ready = require('./utils/ready.cjs');
14
+ const http = require('./utils/http.cjs');
15
+ const paths = require('./utils/paths.cjs');
16
+
17
+ /**
18
+ * @module middleware
19
+ */
20
+ function getFileServices(context, stats) {
21
+ const cached = context.services;
22
+ // Cache hit.
23
+ if (cached) {
24
+ return cached;
25
+ }
26
+ const paths$1 = paths.getPaths(stats);
27
+ const { fs, options } = context;
28
+ const services = [];
29
+ const { etag, ignore, headers, acceptRanges, lastModified } = options;
30
+ // Get the file services.
31
+ for (const [outputPath, publicPath] of paths$1) {
32
+ services.push([
33
+ publicPath,
34
+ new Service.Service(outputPath, {
35
+ fs,
36
+ etag,
37
+ ignore,
38
+ headers,
39
+ acceptRanges,
40
+ lastModified
41
+ })
42
+ ]);
43
+ }
44
+ // Cache services.
45
+ context.services = services;
46
+ // Return services.
47
+ return services;
48
+ }
49
+ function getFileServicesAsync(context, path) {
50
+ return new Promise(resolve => {
51
+ const { stats } = context;
52
+ // If stats exists, resolve immediately.
53
+ if (stats) {
54
+ resolve(getFileServices(context, stats));
55
+ } else {
56
+ // Log waiting info.
57
+ context.logger.info(`wait until bundle finished: ${path}`);
58
+ // Otherwise, wait until bundle finished.
59
+ ready.ready(context, stats => {
60
+ resolve(getFileServices(context, stats));
61
+ });
62
+ }
63
+ });
64
+ }
65
+ function middleware(context) {
66
+ // Middleware.
67
+ return async (ctx, next) => {
68
+ const path = http.decodeURI(ctx.path);
69
+ // Path -1 or null byte(s).
70
+ if (path === -1 || path.includes('\0')) {
71
+ return ctx.throw(400);
72
+ }
73
+ // Is path respond.
74
+ let respond = false;
75
+ // Get the file services.
76
+ const services = await getFileServicesAsync(context, path);
77
+ // Try to respond.
78
+ for (const [publicPath, service] of services) {
79
+ if (path.startsWith(publicPath)) {
80
+ ctx.path = path.slice(publicPath.length);
81
+ respond = await service.response(ctx);
82
+ if (respond) {
83
+ return;
84
+ } else {
85
+ ctx.path = path;
86
+ }
87
+ }
88
+ }
89
+ // Not respond.
90
+ if (!respond) {
91
+ await next();
92
+ }
93
+ };
94
+ }
95
+
96
+ exports.middleware = middleware;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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
+ /**
13
+ * @module fs
14
+ */
15
+ /**
16
+ * @function stat
17
+ * @description Get file stats.
18
+ * @param fs The file system to used.
19
+ * @param path The file path.
20
+ */
21
+ function stat(fs, path) {
22
+ return new Promise(resolve => {
23
+ fs.stat(path, (error, stats) => {
24
+ resolve(error ? null : stats);
25
+ });
26
+ });
27
+ }
28
+
29
+ exports.stat = stat;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @package webpack-dev-service
3
+ * @license MIT
4
+ * @version 0.10.2
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 crypto = require('crypto');
13
+
14
+ /**
15
+ * @module hash
16
+ */
17
+ // prettier-ignore
18
+ const CHARS = [
19
+ // 0-9
20
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
21
+ // A-M
22
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
23
+ // N-Z
24
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
25
+ // a-m
26
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
27
+ // n-z
28
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
29
+ ];
30
+ /**
31
+ * @function generate
32
+ * @description Generate a hash.
33
+ * @param length The length of hash.
34
+ */
35
+ function generate(length = 32) {
36
+ let hash = '';
37
+ const randomValues = crypto.getRandomValues(new Uint8Array(length));
38
+ // Create hash.
39
+ for (const value of randomValues) {
40
+ hash += CHARS[value % 62];
41
+ }
42
+ // Return hash.
43
+ return hash;
44
+ }
45
+
46
+ exports.generate = generate;