@modern-js/server 1.3.0 → 1.3.1-beta.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.
@@ -19,13 +19,13 @@ export default class Watcher {
19
19
  this.watcher = void 0;
20
20
  }
21
21
 
22
- listen(files, callback) {
22
+ listen(files, options, callback) {
23
23
  const watched = files.filter(Boolean);
24
+ const filenames = watched.map(filename => filename.replace(/\\/g, '/')); // eslint-disable-next-line no-console
25
+
26
+ console.log('watched files:', filenames);
24
27
  const cache = new StatsCache();
25
- const watcher = chokidar.watch(watched, {
26
- // 初始化的时候不触发 add、addDir 事件
27
- ignoreInitial: true
28
- });
28
+ const watcher = chokidar.watch(filenames, options);
29
29
  watcher.on('ready', () => {
30
30
  cache.add(getWatchedFiles(watcher));
31
31
  });
@@ -121,9 +121,13 @@ export class ModernDevServer extends ModernServer {
121
121
  super.close();
122
122
  await this.watcher.close();
123
123
  await new Promise(resolve => {
124
- this.devMiddleware.close(() => {
124
+ if (this.devMiddleware) {
125
+ this.devMiddleware.close(() => {
126
+ resolve();
127
+ });
128
+ } else {
125
129
  resolve();
126
- });
130
+ }
127
131
  });
128
132
  }
129
133
 
@@ -239,16 +243,22 @@ export class ModernDevServer extends ModernServer {
239
243
  const {
240
244
  mock
241
245
  } = AGGRED_DIR;
242
- const defaultWatched = [`${pwd}/${mock}/**/*`, `${pwd}/${SERVER_DIR}/**/*`, `${pwd}/${API_DIR}/!(typings)/**`, `${pwd}/${SHARED_DIR}/**/*`];
246
+ const defaultWatched = [`${mock}/**/*`, `${SERVER_DIR}/**/*`, `${API_DIR}/**`, `${SHARED_DIR}/**/*`];
247
+ const defaultWatchedPaths = defaultWatched.map(p => path.normalize(path.join(pwd, p)));
248
+ const mockPath = path.normalize(path.join(pwd, mock));
243
249
  const watcher = new Watcher();
244
250
  watcher.createDepTree(); // 监听文件变动,如果有变动则给 client,也就是 start 启动的插件发消息
245
251
 
246
- watcher.listen(defaultWatched, filepath => {
252
+ watcher.listen(defaultWatchedPaths, {
253
+ // 初始化的时候不触发 add、addDir 事件
254
+ ignoreInitial: true,
255
+ ignored: /api\/typings\/.*/
256
+ }, filepath => {
247
257
  watcher.updateDepTree();
248
258
  watcher.cleanDepCache(filepath);
249
259
  this.runner.reset();
250
260
 
251
- if (filepath.startsWith(`${pwd}/${mock}`)) {
261
+ if (filepath.startsWith(mockPath)) {
252
262
  this.mockHandler = createMockHandler({
253
263
  pwd
254
264
  });
@@ -30,14 +30,14 @@ class Watcher {
30
30
  this.watcher = void 0;
31
31
  }
32
32
 
33
- listen(files, callback) {
33
+ listen(files, options, callback) {
34
34
  const watched = files.filter(Boolean);
35
+ const filenames = watched.map(filename => filename.replace(/\\/g, '/')); // eslint-disable-next-line no-console
36
+
37
+ console.log('watched files:', filenames);
35
38
  const cache = new _statsCache.StatsCache();
36
39
 
37
- const watcher = _chokidar.default.watch(watched, {
38
- // 初始化的时候不触发 add、addDir 事件
39
- ignoreInitial: true
40
- });
40
+ const watcher = _chokidar.default.watch(filenames, options);
41
41
 
42
42
  watcher.on('ready', () => {
43
43
  cache.add(getWatchedFiles(watcher));
@@ -150,9 +150,13 @@ class ModernDevServer extends _modernServer.ModernServer {
150
150
  super.close();
151
151
  await this.watcher.close();
152
152
  await new Promise(resolve => {
153
- this.devMiddleware.close(() => {
153
+ if (this.devMiddleware) {
154
+ this.devMiddleware.close(() => {
155
+ resolve();
156
+ });
157
+ } else {
154
158
  resolve();
155
- });
159
+ }
156
160
  });
157
161
  }
158
162
 
@@ -268,16 +272,24 @@ class ModernDevServer extends _modernServer.ModernServer {
268
272
  const {
269
273
  mock
270
274
  } = _constants.AGGRED_DIR;
271
- const defaultWatched = [`${pwd}/${mock}/**/*`, `${pwd}/${_utils.SERVER_DIR}/**/*`, `${pwd}/${_utils.API_DIR}/!(typings)/**`, `${pwd}/${_utils.SHARED_DIR}/**/*`];
275
+ const defaultWatched = [`${mock}/**/*`, `${_utils.SERVER_DIR}/**/*`, `${_utils.API_DIR}/**`, `${_utils.SHARED_DIR}/**/*`];
276
+ const defaultWatchedPaths = defaultWatched.map(p => _path.default.normalize(_path.default.join(pwd, p)));
277
+
278
+ const mockPath = _path.default.normalize(_path.default.join(pwd, mock));
279
+
272
280
  const watcher = new _watcher.default();
273
281
  watcher.createDepTree(); // 监听文件变动,如果有变动则给 client,也就是 start 启动的插件发消息
274
282
 
275
- watcher.listen(defaultWatched, filepath => {
283
+ watcher.listen(defaultWatchedPaths, {
284
+ // 初始化的时候不触发 add、addDir 事件
285
+ ignoreInitial: true,
286
+ ignored: /api\/typings\/.*/
287
+ }, filepath => {
276
288
  watcher.updateDepTree();
277
289
  watcher.cleanDepCache(filepath);
278
290
  this.runner.reset();
279
291
 
280
- if (filepath.startsWith(`${pwd}/${mock}`)) {
292
+ if (filepath.startsWith(mockPath)) {
281
293
  this.mockHandler = (0, _mock.createMockHandler)({
282
294
  pwd
283
295
  });
@@ -1,7 +1,8 @@
1
+ import { WatchOptions } from 'chokidar';
1
2
  export default class Watcher {
2
3
  private dependencyTree;
3
4
  private watcher;
4
- listen(files: string[], callback: (changed: string) => void): void;
5
+ listen(files: string[], options: WatchOptions, callback: (changed: string) => void): void;
5
6
  createDepTree(): void;
6
7
  updateDepTree(): void;
7
8
  cleanDepCache(filepath: string): void;
package/jest.config.js CHANGED
@@ -4,5 +4,6 @@ const sharedConfig = require('@scripts/jest-config');
4
4
  module.exports = {
5
5
  // eslint-disable-next-line node/no-unsupported-features/es-syntax
6
6
  ...sharedConfig,
7
+ testEnvironment: 'node',
7
8
  rootDir: __dirname,
8
9
  };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.3.0",
14
+ "version": "1.3.1-beta.0",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -1,4 +1,4 @@
1
- import chokidar, { FSWatcher } from 'chokidar';
1
+ import chokidar, { FSWatcher, WatchOptions } from 'chokidar';
2
2
  import { DependencyTree } from './dependency-tree';
3
3
  import { StatsCache } from './stats-cache';
4
4
 
@@ -18,14 +18,18 @@ export default class Watcher {
18
18
 
19
19
  private watcher!: FSWatcher;
20
20
 
21
- public listen(files: string[], callback: (changed: string) => void) {
21
+ public listen(
22
+ files: string[],
23
+ options: WatchOptions,
24
+ callback: (changed: string) => void,
25
+ ) {
22
26
  const watched = files.filter(Boolean);
27
+ const filenames = watched.map(filename => filename.replace(/\\/g, '/'));
28
+ // eslint-disable-next-line no-console
29
+ console.log('watched files:', filenames);
23
30
 
24
31
  const cache = new StatsCache();
25
- const watcher = chokidar.watch(watched, {
26
- // 初始化的时候不触发 add、addDir 事件
27
- ignoreInitial: true,
28
- });
32
+ const watcher = chokidar.watch(filenames, options);
29
33
 
30
34
  watcher.on('ready', () => {
31
35
  cache.add(getWatchedFiles(watcher));
@@ -84,7 +84,6 @@ export class ModernDevServer extends ModernServer {
84
84
  // Complete the preparation of services
85
85
  public async init(runner: ServerHookRunner) {
86
86
  const { conf, pwd, compiler } = this;
87
-
88
87
  // mock handler
89
88
  this.mockHandler = createMockHandler({ pwd });
90
89
  this.addHandler((ctx: ModernServerContext, next: NextFunction) => {
@@ -150,9 +149,13 @@ export class ModernDevServer extends ModernServer {
150
149
  super.close();
151
150
  await this.watcher.close();
152
151
  await new Promise<void>(resolve => {
153
- this.devMiddleware.close(() => {
152
+ if (this.devMiddleware) {
153
+ this.devMiddleware.close(() => {
154
+ resolve();
155
+ });
156
+ } else {
154
157
  resolve();
155
- });
158
+ }
156
159
  });
157
160
  }
158
161
 
@@ -252,32 +255,45 @@ export class ModernDevServer extends ModernServer {
252
255
  const { pwd } = this;
253
256
  const { mock } = AGGRED_DIR;
254
257
  const defaultWatched = [
255
- `${pwd}/${mock}/**/*`,
256
- `${pwd}/${SERVER_DIR}/**/*`,
257
- `${pwd}/${API_DIR}/!(typings)/**`,
258
- `${pwd}/${SHARED_DIR}/**/*`,
258
+ `${mock}/**/*`,
259
+ `${SERVER_DIR}/**/*`,
260
+ `${API_DIR}/**`,
261
+ `${SHARED_DIR}/**/*`,
259
262
  ];
260
263
 
264
+ const defaultWatchedPaths = defaultWatched.map(p =>
265
+ path.normalize(path.join(pwd, p)),
266
+ );
267
+ const mockPath = path.normalize(path.join(pwd, mock));
268
+
261
269
  const watcher = new Watcher();
262
270
  watcher.createDepTree();
263
271
 
264
272
  // 监听文件变动,如果有变动则给 client,也就是 start 启动的插件发消息
265
- watcher.listen(defaultWatched, (filepath: string) => {
266
- watcher.updateDepTree();
267
- watcher.cleanDepCache(filepath);
268
-
269
- this.runner.reset();
270
-
271
- if (filepath.startsWith(`${pwd}/${mock}`)) {
272
- this.mockHandler = createMockHandler({ pwd });
273
- } else {
274
- try {
275
- this.prepareFrameHandler();
276
- } catch (e) {
277
- this.logger.error(e as Error);
273
+ watcher.listen(
274
+ defaultWatchedPaths,
275
+ {
276
+ // 初始化的时候不触发 add、addDir 事件
277
+ ignoreInitial: true,
278
+ ignored: /api\/typings\/.*/,
279
+ },
280
+ (filepath: string) => {
281
+ watcher.updateDepTree();
282
+ watcher.cleanDepCache(filepath);
283
+
284
+ this.runner.reset();
285
+
286
+ if (filepath.startsWith(mockPath)) {
287
+ this.mockHandler = createMockHandler({ pwd });
288
+ } else {
289
+ try {
290
+ this.prepareFrameHandler();
291
+ } catch (e) {
292
+ this.logger.error(e as Error);
293
+ }
278
294
  }
279
- }
280
- });
295
+ },
296
+ );
281
297
 
282
298
  this.watcher = watcher;
283
299
  }
@@ -3,6 +3,7 @@ import { defaultsConfig, NormalizedConfig } from '@modern-js/core';
3
3
  import { ModernServerContext, NextFunction } from '@modern-js/types';
4
4
  import createServer, { Server } from '../src';
5
5
  import { ModernServer } from '../src/server/modern-server';
6
+ import Watcher from '../src/dev-tools/watcher';
6
7
 
7
8
  describe('test server', () => {
8
9
  test('should throw error when ', resolve => {
@@ -99,3 +100,21 @@ describe('test server', () => {
99
100
  });
100
101
  });
101
102
  });
103
+
104
+ describe('dev server', () => {
105
+ const pwd = path.join(__dirname, './fixtures/pure');
106
+ let devServer: Server;
107
+
108
+ test('watch', async () => {
109
+ devServer = await createServer({
110
+ config: defaultsConfig as NormalizedConfig,
111
+ pwd,
112
+ dev: true,
113
+ });
114
+
115
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
116
+ // @ts-expect-error
117
+ expect(devServer.server.watcher).toBeInstanceOf(Watcher);
118
+ await devServer.close();
119
+ });
120
+ });
@@ -0,0 +1,96 @@
1
+ import * as path from 'path';
2
+ import { fs } from '@modern-js/utils';
3
+ import Watcher from '../src/dev-tools/watcher';
4
+
5
+ jest.useRealTimers();
6
+
7
+ describe('watcher', () => {
8
+ let watcher: Watcher;
9
+ jest.setTimeout(25000);
10
+ beforeAll(() => {
11
+ watcher = new Watcher();
12
+ });
13
+
14
+ test('should emit change', done => {
15
+ const pwd = path.join(__dirname, './fixtures/pure');
16
+ const serverDir = path.normalize(path.join(pwd, './tmp-server'));
17
+
18
+ const callback = jest.fn();
19
+ if (fs.pathExistsSync(serverDir)) {
20
+ fs.removeSync(serverDir);
21
+ }
22
+ const writeFiles = () => {
23
+ fs.mkdirSync(serverDir);
24
+ fs.writeFileSync(
25
+ path.normalize(path.join(serverDir, 'index.js')),
26
+ 'test',
27
+ 'utf8',
28
+ );
29
+ };
30
+
31
+ const clear = () => {
32
+ fs.removeSync(serverDir);
33
+ };
34
+
35
+ watcher.listen(
36
+ [`${serverDir}/**/*`],
37
+ {
38
+ ignoreInitial: true,
39
+ ignored: /api\/typings\/.*/,
40
+ },
41
+ async () => {
42
+ callback();
43
+ expect(callback).toHaveBeenCalledTimes(1);
44
+ await watcher.close();
45
+ clear();
46
+ done();
47
+ },
48
+ );
49
+
50
+ setTimeout(writeFiles, 100);
51
+ });
52
+
53
+ test('should not emit change when typings file changed', done => {
54
+ const pwd = path.join(__dirname, './fixtures/pure');
55
+ const apiDir = path.normalize(path.join(pwd, './api'));
56
+
57
+ const callback = jest.fn();
58
+
59
+ if (fs.pathExistsSync(apiDir)) {
60
+ fs.removeSync(apiDir);
61
+ }
62
+
63
+ const writeFiles = () => {
64
+ fs.mkdirSync(path.normalize(path.join(apiDir, 'typings')), {
65
+ recursive: true,
66
+ });
67
+ fs.writeFileSync(
68
+ path.normalize(path.join(apiDir, 'typings/index.js')),
69
+ 'test',
70
+ 'utf8',
71
+ );
72
+ };
73
+
74
+ const clear = () => {
75
+ fs.removeSync(apiDir);
76
+ };
77
+
78
+ watcher.listen(
79
+ [`${apiDir}/**/*`],
80
+ {
81
+ ignoreInitial: true,
82
+ ignored: /api\/typings\/.*/,
83
+ },
84
+ callback,
85
+ );
86
+
87
+ setTimeout(async () => {
88
+ expect(callback).toHaveBeenCalledTimes(0);
89
+ await watcher.close();
90
+ clear();
91
+ done();
92
+ }, 1000);
93
+
94
+ setTimeout(writeFiles);
95
+ });
96
+ });