@modern-js/server 1.4.0 → 1.4.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @modern-js/server
2
2
 
3
+ ## 1.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - deeaa602: support svg/proxy/multi-version in unbundled
8
+ - fab92861: fix: @modern-js/core phantom dep
9
+ - Updated dependencies [deeaa602]
10
+ - Updated dependencies [54786e58]
11
+ - @modern-js/hmr-client@1.2.2
12
+ - @modern-js/utils@1.3.2
13
+ - @modern-js/core@1.4.3
14
+
15
+ ## 1.4.2
16
+
17
+ ### Patch Changes
18
+
19
+ - 735b2a81: prevent ssr compiler to send socket message
20
+ - Updated dependencies [b376c8d6]
21
+ - Updated dependencies [e62c4efd]
22
+ - Updated dependencies [e2a8233f]
23
+ - @modern-js/core@1.4.2
24
+
25
+ ## 1.4.1
26
+
27
+ ### Patch Changes
28
+
29
+ - 2cfc4235: support cssPath/jsPath/mediaPath in production mode
30
+ - 8d55e234: fix: catch api error
31
+ - Updated dependencies [53aca274]
32
+ - Updated dependencies [78279953]
33
+ - Updated dependencies [e116ace5]
34
+ - Updated dependencies [4d72edea]
35
+ - @modern-js/core@1.4.1
36
+ - @modern-js/utils@1.3.1
37
+
3
38
  ## 1.4.0
4
39
 
5
40
  ### Minor Changes
@@ -8,6 +8,7 @@ export default class SocketServer {
8
8
  this.options = void 0;
9
9
  this.app = void 0;
10
10
  this.stats = void 0;
11
+ this.timer = null;
11
12
  this.options = options;
12
13
  } // create socket, install socket handler, bind socket event
13
14
 
@@ -32,7 +33,7 @@ export default class SocketServer {
32
33
  // only dev server, use default logger
33
34
  logger.error(err);
34
35
  });
35
- setInterval(() => {
36
+ this.timer = setInterval(() => {
36
37
  this.wsServer.clients.forEach(socket => {
37
38
  const extWs = socket;
38
39
 
@@ -45,49 +46,7 @@ export default class SocketServer {
45
46
  });
46
47
  }, 30000);
47
48
  this.wsServer.on('connection', socket => {
48
- const connection = socket;
49
- connection.isAlive = true;
50
- connection.on('pong', () => {
51
- connection.isAlive = true;
52
- });
53
-
54
- if (!connection) {
55
- return;
56
- }
57
-
58
- this.sockets.push(connection);
59
- connection.on('close', () => {
60
- const idx = this.sockets.indexOf(connection);
61
-
62
- if (idx >= 0) {
63
- this.sockets.splice(idx, 1);
64
- }
65
- });
66
-
67
- if (this.options.client.logging) {
68
- this.sockWrite('logging', this.options.client.logging);
69
- }
70
-
71
- if (this.options.hot || this.options.hot === 'only') {
72
- this.sockWrite('hot');
73
- }
74
-
75
- if (this.options.liveReload) {
76
- this.sockWrite('liveReload');
77
- }
78
-
79
- if (this.options.client.progress) {
80
- this.sockWrite('progress', this.options.client.progress);
81
- }
82
-
83
- if (this.options.client.overlay) {
84
- this.sockWrite('overlay', this.options.client.overlay);
85
- } // send first stats to active client sock if stats exist
86
-
87
-
88
- if (this.stats) {
89
- this.sendStats(true);
90
- }
49
+ this.onConnect(socket);
91
50
  });
92
51
  }
93
52
 
@@ -106,10 +65,68 @@ export default class SocketServer {
106
65
  });
107
66
  }
108
67
 
68
+ singleWrite(socket, type, data) {
69
+ this.send(socket, JSON.stringify({
70
+ type,
71
+ data
72
+ }));
73
+ }
74
+
109
75
  close() {
110
76
  this.sockets.forEach(socket => {
111
77
  socket.close();
112
78
  });
79
+
80
+ if (this.timer) {
81
+ clearInterval(this.timer);
82
+ this.timer = null;
83
+ }
84
+ }
85
+
86
+ onConnect(socket) {
87
+ const connection = socket;
88
+ connection.isAlive = true;
89
+ connection.on('pong', () => {
90
+ connection.isAlive = true;
91
+ });
92
+
93
+ if (!connection) {
94
+ return;
95
+ }
96
+
97
+ this.sockets.push(connection);
98
+ connection.on('close', () => {
99
+ const idx = this.sockets.indexOf(connection);
100
+
101
+ if (idx >= 0) {
102
+ this.sockets.splice(idx, 1);
103
+ }
104
+ });
105
+
106
+ if (this.options.client.logging) {
107
+ this.singleWrite(connection, 'logging', this.options.client.logging);
108
+ }
109
+
110
+ if (this.options.hot || this.options.hot === 'only') {
111
+ this.singleWrite(connection, 'hot');
112
+ }
113
+
114
+ if (this.options.liveReload) {
115
+ this.singleWrite(connection, 'liveReload');
116
+ }
117
+
118
+ if (this.options.client.progress) {
119
+ this.singleWrite(connection, 'progress', this.options.client.progress);
120
+ }
121
+
122
+ if (this.options.client.overlay) {
123
+ this.singleWrite(connection, 'overlay', this.options.client.overlay);
124
+ } // send first stats to active client sock if stats exist
125
+
126
+
127
+ if (this.stats) {
128
+ this.sendStats(true);
129
+ }
113
130
  } // get standard stats
114
131
 
115
132
 
@@ -1,10 +1,5 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
-
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
-
5
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
-
7
1
  import { createProxyMiddleware } from 'http-proxy-middleware';
2
+ import { formatProxyOptions } from '@modern-js/utils';
8
3
  export const createProxyHandler = proxyOptions => {
9
4
  if (!proxyOptions) {
10
5
  return null;
@@ -12,28 +7,7 @@ export const createProxyHandler = proxyOptions => {
12
7
  // or an object in the form of { source: ProxyDetail }
13
8
 
14
9
 
15
- const formatedProxy = [];
16
-
17
- if (!Array.isArray(proxyOptions)) {
18
- if ('target' in proxyOptions) {
19
- formatedProxy.push(proxyOptions);
20
- } else {
21
- Array.prototype.push.apply(formatedProxy, Object.keys(proxyOptions).reduce((total, source) => {
22
- const option = proxyOptions[source];
23
- total.push(_objectSpread({
24
- context: source,
25
- changeOrigin: true,
26
- logLevel: 'warn'
27
- }, typeof option === 'string' ? {
28
- target: option
29
- } : option));
30
- return total;
31
- }, []));
32
- }
33
- } else {
34
- formatedProxy.push(...proxyOptions);
35
- }
36
-
10
+ const formatedProxy = formatProxyOptions(proxyOptions);
37
11
  const middlewares = formatedProxy.map(option => {
38
12
  const middleware = createProxyMiddleware(option.context, option); // eslint-disable-next-line consistent-return
39
13
 
@@ -14,7 +14,7 @@ const createCacheItem = async (filepath, mtime) => {
14
14
  };
15
15
  };
16
16
 
17
- class LruReader {
17
+ export class LruReader {
18
18
  // private timer?: NodeJS.Timeout;
19
19
  constructor() {
20
20
  this.cache = void 0;
@@ -96,7 +96,6 @@ class LruReader {
96
96
 
97
97
 
98
98
  }
99
-
100
99
  const reader = new LruReader();
101
100
  export const readFile = async filepath => {
102
101
  const file = await reader.read(filepath);
@@ -183,6 +183,10 @@ export class ModernDevServer extends ModernServer {
183
183
  };
184
184
 
185
185
  const addHooks = compiler => {
186
+ if (compiler.name === 'server') {
187
+ return;
188
+ }
189
+
186
190
  const {
187
191
  compile,
188
192
  invalid,
@@ -21,7 +21,7 @@ import clone from 'lodash.clone';
21
21
  import { RouteMatchManager } from "../libs/route";
22
22
  import { createRenderHandler } from "../libs/render";
23
23
  import { createStaticFileHandler } from "../libs/serve-file";
24
- import { createErrorDocument, createMiddlewareCollecter, mergeExtension, noop } from "../utils";
24
+ import { createErrorDocument, createMiddlewareCollecter, getStaticReg, mergeExtension, noop } from "../utils";
25
25
  import * as reader from "../libs/render/reader";
26
26
  import { createProxyHandler } from "../libs/proxy";
27
27
  import { createContext } from "../libs/context";
@@ -126,15 +126,10 @@ export class ModernServer {
126
126
  this.warmupSSRBundle();
127
127
  }
128
128
 
129
- await this.prepareFrameHandler();
130
- const {
131
- favicon,
132
- faviconByEntries
133
- } = this.conf.output || {};
134
- const favicons = this.prepareFavicons(favicon, faviconByEntries); // Only work when without setting `assetPrefix`.
129
+ await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
135
130
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
136
131
 
137
- const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''})`);
132
+ const staticPathRegExp = getStaticReg(this.conf.output || {});
138
133
  this.staticFileHandler = createStaticFileHandler([{
139
134
  path: staticPathRegExp,
140
135
  target: distDir
@@ -374,7 +369,7 @@ export class ModernServer {
374
369
  }); // route is api service
375
370
 
376
371
  if (route.isApi) {
377
- this.handleAPI(context);
372
+ await this.handleAPI(context);
378
373
  return;
379
374
  }
380
375
 
@@ -585,25 +580,5 @@ export class ModernServer {
585
580
  res.end(createErrorDocument(status, text));
586
581
  }
587
582
 
588
- prepareFavicons(favicon, faviconByEntries) {
589
- const faviconNames = [];
590
-
591
- if (favicon) {
592
- faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
593
- }
594
-
595
- if (faviconByEntries) {
596
- Object.keys(faviconByEntries).forEach(f => {
597
- const curFavicon = faviconByEntries[f];
598
-
599
- if (curFavicon) {
600
- faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
601
- }
602
- });
603
- }
604
-
605
- return faviconNames;
606
- }
607
-
608
583
  }
609
584
  /* eslint-enable max-lines */
@@ -77,4 +77,36 @@ export const toPath = (reg, params) => {
77
77
  encode: encodeURIComponent
78
78
  });
79
79
  return fn(params);
80
+ };
81
+ export const getStaticReg = (output = {}) => {
82
+ const {
83
+ favicon,
84
+ faviconByEntries,
85
+ cssPath,
86
+ jsPath,
87
+ mediaPath
88
+ } = output;
89
+ const favicons = prepareFavicons(favicon, faviconByEntries);
90
+ const staticFiles = [cssPath, jsPath, mediaPath].filter(v => Boolean(v));
91
+ const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''}|${staticFiles.join('|')})`);
92
+ return staticPathRegExp;
93
+ };
94
+ export const prepareFavicons = (favicon, faviconByEntries) => {
95
+ const faviconNames = [];
96
+
97
+ if (favicon) {
98
+ faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
99
+ }
100
+
101
+ if (faviconByEntries) {
102
+ Object.keys(faviconByEntries).forEach(f => {
103
+ const curFavicon = faviconByEntries[f];
104
+
105
+ if (curFavicon) {
106
+ faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
107
+ }
108
+ });
109
+ }
110
+
111
+ return faviconNames;
80
112
  };
@@ -20,6 +20,7 @@ class SocketServer {
20
20
  this.options = void 0;
21
21
  this.app = void 0;
22
22
  this.stats = void 0;
23
+ this.timer = null;
23
24
  this.options = options;
24
25
  } // create socket, install socket handler, bind socket event
25
26
 
@@ -44,7 +45,7 @@ class SocketServer {
44
45
  // only dev server, use default logger
45
46
  _utils.logger.error(err);
46
47
  });
47
- setInterval(() => {
48
+ this.timer = setInterval(() => {
48
49
  this.wsServer.clients.forEach(socket => {
49
50
  const extWs = socket;
50
51
 
@@ -57,49 +58,7 @@ class SocketServer {
57
58
  });
58
59
  }, 30000);
59
60
  this.wsServer.on('connection', socket => {
60
- const connection = socket;
61
- connection.isAlive = true;
62
- connection.on('pong', () => {
63
- connection.isAlive = true;
64
- });
65
-
66
- if (!connection) {
67
- return;
68
- }
69
-
70
- this.sockets.push(connection);
71
- connection.on('close', () => {
72
- const idx = this.sockets.indexOf(connection);
73
-
74
- if (idx >= 0) {
75
- this.sockets.splice(idx, 1);
76
- }
77
- });
78
-
79
- if (this.options.client.logging) {
80
- this.sockWrite('logging', this.options.client.logging);
81
- }
82
-
83
- if (this.options.hot || this.options.hot === 'only') {
84
- this.sockWrite('hot');
85
- }
86
-
87
- if (this.options.liveReload) {
88
- this.sockWrite('liveReload');
89
- }
90
-
91
- if (this.options.client.progress) {
92
- this.sockWrite('progress', this.options.client.progress);
93
- }
94
-
95
- if (this.options.client.overlay) {
96
- this.sockWrite('overlay', this.options.client.overlay);
97
- } // send first stats to active client sock if stats exist
98
-
99
-
100
- if (this.stats) {
101
- this.sendStats(true);
102
- }
61
+ this.onConnect(socket);
103
62
  });
104
63
  }
105
64
 
@@ -118,10 +77,68 @@ class SocketServer {
118
77
  });
119
78
  }
120
79
 
80
+ singleWrite(socket, type, data) {
81
+ this.send(socket, JSON.stringify({
82
+ type,
83
+ data
84
+ }));
85
+ }
86
+
121
87
  close() {
122
88
  this.sockets.forEach(socket => {
123
89
  socket.close();
124
90
  });
91
+
92
+ if (this.timer) {
93
+ clearInterval(this.timer);
94
+ this.timer = null;
95
+ }
96
+ }
97
+
98
+ onConnect(socket) {
99
+ const connection = socket;
100
+ connection.isAlive = true;
101
+ connection.on('pong', () => {
102
+ connection.isAlive = true;
103
+ });
104
+
105
+ if (!connection) {
106
+ return;
107
+ }
108
+
109
+ this.sockets.push(connection);
110
+ connection.on('close', () => {
111
+ const idx = this.sockets.indexOf(connection);
112
+
113
+ if (idx >= 0) {
114
+ this.sockets.splice(idx, 1);
115
+ }
116
+ });
117
+
118
+ if (this.options.client.logging) {
119
+ this.singleWrite(connection, 'logging', this.options.client.logging);
120
+ }
121
+
122
+ if (this.options.hot || this.options.hot === 'only') {
123
+ this.singleWrite(connection, 'hot');
124
+ }
125
+
126
+ if (this.options.liveReload) {
127
+ this.singleWrite(connection, 'liveReload');
128
+ }
129
+
130
+ if (this.options.client.progress) {
131
+ this.singleWrite(connection, 'progress', this.options.client.progress);
132
+ }
133
+
134
+ if (this.options.client.overlay) {
135
+ this.singleWrite(connection, 'overlay', this.options.client.overlay);
136
+ } // send first stats to active client sock if stats exist
137
+
138
+
139
+ if (this.stats) {
140
+ this.sendStats(true);
141
+ }
125
142
  } // get standard stats
126
143
 
127
144
 
@@ -7,11 +7,7 @@ exports.createProxyHandler = void 0;
7
7
 
8
8
  var _httpProxyMiddleware = require("http-proxy-middleware");
9
9
 
10
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
11
-
12
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
13
-
14
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
10
+ var _utils = require("@modern-js/utils");
15
11
 
16
12
  const createProxyHandler = proxyOptions => {
17
13
  if (!proxyOptions) {
@@ -20,28 +16,7 @@ const createProxyHandler = proxyOptions => {
20
16
  // or an object in the form of { source: ProxyDetail }
21
17
 
22
18
 
23
- const formatedProxy = [];
24
-
25
- if (!Array.isArray(proxyOptions)) {
26
- if ('target' in proxyOptions) {
27
- formatedProxy.push(proxyOptions);
28
- } else {
29
- Array.prototype.push.apply(formatedProxy, Object.keys(proxyOptions).reduce((total, source) => {
30
- const option = proxyOptions[source];
31
- total.push(_objectSpread({
32
- context: source,
33
- changeOrigin: true,
34
- logLevel: 'warn'
35
- }, typeof option === 'string' ? {
36
- target: option
37
- } : option));
38
- return total;
39
- }, []));
40
- }
41
- } else {
42
- formatedProxy.push(...proxyOptions);
43
- }
44
-
19
+ const formatedProxy = (0, _utils.formatProxyOptions)(proxyOptions);
45
20
  const middlewares = formatedProxy.map(option => {
46
21
  const middleware = (0, _httpProxyMiddleware.createProxyMiddleware)(option.context, option); // eslint-disable-next-line consistent-return
47
22
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.updateFile = exports.readFile = exports.init = exports.close = void 0;
6
+ exports.updateFile = exports.readFile = exports.init = exports.close = exports.LruReader = void 0;
7
7
 
8
8
  var _utils = require("@modern-js/utils");
9
9
 
@@ -110,6 +110,7 @@ class LruReader {
110
110
 
111
111
  }
112
112
 
113
+ exports.LruReader = LruReader;
113
114
  const reader = new LruReader();
114
115
 
115
116
  const readFile = async filepath => {
@@ -212,6 +212,10 @@ class ModernDevServer extends _modernServer.ModernServer {
212
212
  };
213
213
 
214
214
  const addHooks = compiler => {
215
+ if (compiler.name === 'server') {
216
+ return;
217
+ }
218
+
215
219
  const {
216
220
  compile,
217
221
  invalid,
@@ -156,15 +156,10 @@ class ModernServer {
156
156
  this.warmupSSRBundle();
157
157
  }
158
158
 
159
- await this.prepareFrameHandler();
160
- const {
161
- favicon,
162
- faviconByEntries
163
- } = this.conf.output || {};
164
- const favicons = this.prepareFavicons(favicon, faviconByEntries); // Only work when without setting `assetPrefix`.
159
+ await this.prepareFrameHandler(); // Only work when without setting `assetPrefix`.
165
160
  // Setting `assetPrefix` means these resources should be uploaded to CDN.
166
161
 
167
- const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''})`);
162
+ const staticPathRegExp = (0, _utils2.getStaticReg)(this.conf.output || {});
168
163
  this.staticFileHandler = (0, _serveFile.createStaticFileHandler)([{
169
164
  path: staticPathRegExp,
170
165
  target: distDir
@@ -409,7 +404,7 @@ class ModernServer {
409
404
  }); // route is api service
410
405
 
411
406
  if (route.isApi) {
412
- this.handleAPI(context);
407
+ await this.handleAPI(context);
413
408
  return;
414
409
  }
415
410
 
@@ -620,26 +615,6 @@ class ModernServer {
620
615
  res.end((0, _utils2.createErrorDocument)(status, text));
621
616
  }
622
617
 
623
- prepareFavicons(favicon, faviconByEntries) {
624
- const faviconNames = [];
625
-
626
- if (favicon) {
627
- faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
628
- }
629
-
630
- if (faviconByEntries) {
631
- Object.keys(faviconByEntries).forEach(f => {
632
- const curFavicon = faviconByEntries[f];
633
-
634
- if (curFavicon) {
635
- faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
636
- }
637
- });
638
- }
639
-
640
- return faviconNames;
641
- }
642
-
643
618
  }
644
619
  /* eslint-enable max-lines */
645
620
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.toPath = exports.toMessage = exports.noop = exports.mergeExtension = exports.createMiddlewareCollecter = exports.createErrorDocument = void 0;
6
+ exports.toPath = exports.toMessage = exports.prepareFavicons = exports.noop = exports.mergeExtension = exports.getStaticReg = exports.createMiddlewareCollecter = exports.createErrorDocument = void 0;
7
7
 
8
8
  var _pathToRegexp = require("path-to-regexp");
9
9
 
@@ -102,4 +102,42 @@ const toPath = (reg, params) => {
102
102
  return fn(params);
103
103
  };
104
104
 
105
- exports.toPath = toPath;
105
+ exports.toPath = toPath;
106
+
107
+ const getStaticReg = (output = {}) => {
108
+ const {
109
+ favicon,
110
+ faviconByEntries,
111
+ cssPath,
112
+ jsPath,
113
+ mediaPath
114
+ } = output;
115
+ const favicons = prepareFavicons(favicon, faviconByEntries);
116
+ const staticFiles = [cssPath, jsPath, mediaPath].filter(v => Boolean(v));
117
+ const staticPathRegExp = new RegExp(`^/(static/|upload/|favicon.ico|icon.png${favicons.length > 0 ? `|${favicons.join('|')}` : ''}|${staticFiles.join('|')})`);
118
+ return staticPathRegExp;
119
+ };
120
+
121
+ exports.getStaticReg = getStaticReg;
122
+
123
+ const prepareFavicons = (favicon, faviconByEntries) => {
124
+ const faviconNames = [];
125
+
126
+ if (favicon) {
127
+ faviconNames.push(favicon.substring(favicon.lastIndexOf('/') + 1));
128
+ }
129
+
130
+ if (faviconByEntries) {
131
+ Object.keys(faviconByEntries).forEach(f => {
132
+ const curFavicon = faviconByEntries[f];
133
+
134
+ if (curFavicon) {
135
+ faviconNames.push(curFavicon.substring(curFavicon.lastIndexOf('/') + 1));
136
+ }
137
+ });
138
+ }
139
+
140
+ return faviconNames;
141
+ };
142
+
143
+ exports.prepareFavicons = prepareFavicons;
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { Server } from 'http';
3
+ import ws from 'ws';
3
4
  import type { Stats } from 'webpack';
4
5
  import { DevServerOptions } from '../type';
5
6
  export default class SocketServer {
@@ -8,11 +9,14 @@ export default class SocketServer {
8
9
  private readonly options;
9
10
  private app?;
10
11
  private stats?;
12
+ private timer;
11
13
  constructor(options: DevServerOptions);
12
14
  prepare(app: Server): void;
13
15
  updateStats(stats: Stats): void;
14
16
  sockWrite(type: string, data?: Record<string, any> | string | boolean): void;
17
+ singleWrite(socket: ws, type: string, data?: Record<string, any> | string | boolean): void;
15
18
  close(): void;
19
+ private onConnect;
16
20
  private getStats;
17
21
  private sendStats;
18
22
  private send;
@@ -1,16 +1,4 @@
1
- /// <reference types="node" />
2
- import { IncomingMessage, ServerResponse } from 'http';
3
- import { NextFunction } from '../type';
1
+ import { NextFunction, ProxyOptions } from '@modern-js/types';
4
2
  import { ModernServerContext } from './context';
5
- declare type ProxyDetail = {
6
- target: string;
7
- pathRewrite?: Record<string, string>;
8
- secure?: boolean;
9
- logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
10
- bypass?: (req: IncomingMessage, res: ServerResponse, proxyOptions: ProxyOptions) => string | undefined | null | false;
11
- context?: string | string[];
12
- changeOrigin?: boolean;
13
- };
14
- export declare type ProxyOptions = Record<string, string> | Record<string, ProxyDetail> | ProxyDetail[] | ProxyDetail;
15
- export declare const createProxyHandler: (proxyOptions: ProxyOptions) => ((ctx: ModernServerContext, next: NextFunction) => Promise<void>)[] | null;
16
- export {};
3
+ export type { ProxyOptions };
4
+ export declare const createProxyHandler: (proxyOptions: ProxyOptions) => ((ctx: ModernServerContext, next: NextFunction) => Promise<void>)[] | null;
@@ -1,4 +1,17 @@
1
1
  /// <reference types="node" />
2
+ export declare class LruReader {
3
+ private readonly cache;
4
+ constructor();
5
+ init(): void;
6
+ close(): void;
7
+ read(filepath: string): Promise<{
8
+ content: Buffer;
9
+ mtime: Date;
10
+ } | {
11
+ content: Buffer;
12
+ } | null>;
13
+ update(): void;
14
+ }
2
15
  export declare const readFile: (filepath: string) => Promise<Buffer | undefined>;
3
16
  export declare const updateFile: () => void;
4
17
  export declare const init: () => void;
@@ -68,6 +68,5 @@ export declare class ModernServer {
68
68
  private requestHandler;
69
69
  private onError;
70
70
  private renderErrorPage;
71
- private prepareFavicons;
72
71
  }
73
72
  export {};
@@ -1,3 +1,4 @@
1
+ import type { NormalizedConfig } from '@modern-js/core';
1
2
  export declare const mergeExtension: (users: any[]) => {
2
3
  middleware: any[];
3
4
  };
@@ -13,4 +14,6 @@ export declare const createMiddlewareCollecter: () => {
13
14
  addWebMiddleware: (input: any) => void;
14
15
  addAPIMiddleware: (input: any) => void;
15
16
  };
16
- export declare const toPath: (reg: string, params: Record<string, any>) => string;
17
+ export declare const toPath: (reg: string, params: Record<string, any>) => string;
18
+ export declare const getStaticReg: (output?: NormalizedConfig['output']) => RegExp;
19
+ export declare const prepareFavicons: (favicon: string | undefined, faviconByEntries?: Record<string, string | undefined> | undefined) => string[];
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.4.0",
14
+ "version": "1.4.3",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -34,12 +34,11 @@
34
34
  "@babel/preset-typescript": "^7.15.0",
35
35
  "@babel/register": "^7.15.3",
36
36
  "@babel/runtime": "^7",
37
- "@modern-js/core": "^1.4.0",
38
- "@modern-js/hmr-client": "^1.2.1",
37
+ "@modern-js/hmr-client": "^1.2.2",
39
38
  "@modern-js/server-core": "^1.2.2",
40
39
  "@modern-js/server-utils": "^1.2.1",
41
40
  "@modern-js/bff-utils": "^1.2.2",
42
- "@modern-js/utils": "^1.3.0",
41
+ "@modern-js/utils": "^1.3.2",
43
42
  "axios": "^0.24.0",
44
43
  "babel-plugin-module-resolver": "^4.1.0",
45
44
  "chokidar": "^3.5.2",
@@ -64,8 +63,9 @@
64
63
  "cookie": "^0.4.2"
65
64
  },
66
65
  "devDependencies": {
66
+ "@modern-js/core": "^1.4.3",
67
67
  "@scripts/build": "0.0.0",
68
- "@modern-js/types": "^1.3.0",
68
+ "@modern-js/types": "^1.3.3",
69
69
  "@types/jest": "^26",
70
70
  "@types/lru-cache": "^5.1.1",
71
71
  "@types/mime-types": "^2.1.0",
@@ -90,7 +90,8 @@
90
90
  "websocket": "^1"
91
91
  },
92
92
  "peerDependencies": {
93
- "webpack": "^5.54.0"
93
+ "webpack": "^5.54.0",
94
+ "@modern-js/core": "^1.4.3"
94
95
  },
95
96
  "sideEffects": false,
96
97
  "modernConfig": {
@@ -100,8 +101,7 @@
100
101
  },
101
102
  "publishConfig": {
102
103
  "registry": "https://registry.npmjs.org/",
103
- "access": "public",
104
- "types": "./dist/types/index.d.ts"
104
+ "access": "public"
105
105
  },
106
106
  "scripts": {
107
107
  "new": "modern new",
package/tests/dev.test.ts CHANGED
@@ -53,14 +53,31 @@ describe('test dev tools', () => {
53
53
 
54
54
  const socket = {
55
55
  state: 1,
56
+ readyState: 1,
57
+ data: '',
56
58
  close() {
57
59
  socket.state = 0;
60
+ },
61
+ send(data: string) {
62
+ socket.data = data;
63
+ },
64
+ on() {
58
65
  // empty
59
66
  },
60
67
  };
68
+
69
+ socketServer.onConnect(socket);
70
+
61
71
  socketServer.sockets = [socket];
72
+ socketServer.sockWrite('test');
73
+ expect(socket.data).toBe(JSON.stringify({ type: 'test' }));
74
+
75
+ socketServer.singleWrite(socket, 'single');
76
+ expect(socket.data).toBe(JSON.stringify({ type: 'single' }));
77
+
62
78
  socketServer.close();
63
79
  expect(socket.state).toBe(0);
80
+ app.close();
64
81
  });
65
82
 
66
83
  test('should dev server plugin work correctly', () => {
@@ -0,0 +1,3 @@
1
+ export default {
2
+ name: 'modern',
3
+ };
@@ -0,0 +1,11 @@
1
+ <html lang="en">
2
+ <head>
3
+ <meta charset="UTF-8">
4
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>bar</title>
7
+ </head>
8
+ <body>
9
+
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <html lang="en">
2
+ <head>
3
+ <meta charset="UTF-8">
4
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>baz</title>
7
+ </head>
8
+ <body>
9
+
10
+ </body>
11
+ </html>
@@ -0,0 +1,11 @@
1
+ <html lang="en">
2
+ <head>
3
+ <meta charset="UTF-8">
4
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>foo</title>
7
+ </head>
8
+ <body>
9
+
10
+ </body>
11
+ </html>
@@ -0,0 +1,102 @@
1
+ import path from 'path';
2
+ import { render } from '../src/libs/render/ssr';
3
+ import { handleDirectory } from '../src/libs/render/static';
4
+ import { LruReader } from '../src/libs/render/reader';
5
+
6
+ describe('test render function', () => {
7
+ test('should return content correctly ', async () => {
8
+ const renderResult = await render(
9
+ {
10
+ params: {},
11
+ pathname: '/foo',
12
+ host: 'localhost:8080',
13
+ query: {},
14
+ url: 'localhost:8080/foo',
15
+ cookieMap: {},
16
+ headers: {},
17
+ } as any,
18
+ {
19
+ urlPath: '/foo',
20
+ bundle: 'bundle.js',
21
+ distDir: path.join(__dirname, 'fixtures', 'ssr'),
22
+ template: 'tpl.html',
23
+ entryName: 'foo',
24
+ staticGenerate: false,
25
+ } as any,
26
+ {
27
+ extendSSRContext: () => {
28
+ // empty
29
+ },
30
+ } as any,
31
+ );
32
+
33
+ expect(renderResult.content).toMatch('Modern.js');
34
+ expect(renderResult.contentType).toMatch('text/html; charset=utf-8');
35
+ });
36
+
37
+ test('should handle directory for .html correctly', async () => {
38
+ const entryPath = path.join(__dirname, 'fixtures', 'static-dir');
39
+
40
+ const res1 = await handleDirectory(
41
+ {
42
+ path: '/modern/bar',
43
+ } as any,
44
+ entryPath,
45
+ '/modern',
46
+ );
47
+
48
+ expect(res1?.content.toString()).toMatch('bar');
49
+ });
50
+
51
+ test('should handle directory for index.html correctly', async () => {
52
+ const entryPath = path.join(__dirname, 'fixtures', 'static-dir');
53
+
54
+ const res1 = await handleDirectory(
55
+ {
56
+ path: '/modern/foo',
57
+ } as any,
58
+ entryPath,
59
+ '/modern',
60
+ );
61
+
62
+ expect(res1?.content.toString()).toMatch('foo');
63
+ });
64
+
65
+ test('should handle directory for /index.html correctly', async () => {
66
+ const entryPath = path.join(__dirname, 'fixtures', 'static-dir');
67
+
68
+ const res1 = await handleDirectory(
69
+ {
70
+ path: '/modern/baz/',
71
+ } as any,
72
+ entryPath,
73
+ '/modern',
74
+ );
75
+
76
+ expect(res1?.content.toString()).toMatch('baz');
77
+ });
78
+
79
+ test('should reader work correctly', async () => {
80
+ const reader = new LruReader();
81
+ const dir = path.join(__dirname, 'fixtures', 'reader');
82
+
83
+ const nullRes = await reader.read(path.join(dir, 'foo.ts'));
84
+ expect(nullRes).toBeNull();
85
+
86
+ const dirRes = await reader.read(path.join(dir, 'test-dir'));
87
+ expect(dirRes).toBeNull();
88
+
89
+ const res = await reader.read(path.join(dir, 'index.ts'));
90
+ expect(res).not.toBeNull();
91
+ expect(res?.content.toString()).toMatch('modern');
92
+
93
+ const res1 = await reader.read(path.join(dir, 'index.ts'));
94
+ expect(res1).not.toBeNull();
95
+ expect(res1?.content.toString()).toMatch('modern');
96
+
97
+ reader.update();
98
+ const res2 = await reader.read(path.join(dir, 'index.ts'));
99
+ expect(res2).not.toBeNull();
100
+ expect(res2?.content.toString()).toMatch('modern');
101
+ });
102
+ });
@@ -5,6 +5,7 @@ import {
5
5
  toMessage,
6
6
  createErrorDocument,
7
7
  createMiddlewareCollecter,
8
+ getStaticReg,
8
9
  } from '../src/utils';
9
10
 
10
11
  describe('test server utils', () => {
@@ -74,4 +75,32 @@ describe('test server utils', () => {
74
75
  const fn = compile('/home/:id', { encode: encodeURIComponent });
75
76
  expect(fn({ id: 2 })).toBe('/home/2');
76
77
  });
78
+
79
+ describe('test create static reg', () => {
80
+ test('should test static path correctly', () => {
81
+ const reg = getStaticReg();
82
+ expect(reg.test('/static')).toBeTruthy();
83
+ expect(reg.test('/upload')).toBeTruthy();
84
+ });
85
+
86
+ test('should test custom static path correctly', () => {
87
+ const reg = getStaticReg({
88
+ cssPath: 'static-css',
89
+ });
90
+ expect(reg.test('/static-css')).toBeTruthy();
91
+ });
92
+
93
+ test('should test favicon path correctly', () => {
94
+ const reg = getStaticReg({
95
+ favicon: 'index.icon',
96
+ faviconByEntries: {
97
+ foo: 'foo.icon',
98
+ baz: 'baz.icon',
99
+ },
100
+ });
101
+ expect(reg.test('/index.icon')).toBeTruthy();
102
+ expect(reg.test('/foo.icon')).toBeTruthy();
103
+ expect(reg.test('/baz.icon')).toBeTruthy();
104
+ });
105
+ });
77
106
  });
package/tests/ssr.test.ts DELETED
@@ -1,34 +0,0 @@
1
- import path from 'path';
2
- import { render } from '../src/libs/render/ssr';
3
-
4
- describe('test ssr render function', () => {
5
- test('should return content correctly ', async () => {
6
- const renderResult = await render(
7
- {
8
- params: {},
9
- pathname: '/foo',
10
- host: 'localhost:8080',
11
- query: {},
12
- url: 'localhost:8080/foo',
13
- cookieMap: {},
14
- headers: {},
15
- } as any,
16
- {
17
- urlPath: '/foo',
18
- bundle: 'bundle.js',
19
- distDir: path.join(__dirname, 'fixtures', 'ssr'),
20
- template: 'tpl.html',
21
- entryName: 'foo',
22
- staticGenerate: false,
23
- } as any,
24
- {
25
- extendSSRContext: () => {
26
- // empty
27
- },
28
- } as any,
29
- );
30
-
31
- expect(renderResult.content).toMatch('Modern.js');
32
- expect(renderResult.contentType).toMatch('text/html; charset=utf-8');
33
- });
34
- });