@bleedingdev/modern-js-server 3.2.0-ultramodern.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.
- package/LICENSE +21 -0
- package/README.md +26 -0
- package/dist/cjs/createDevServer.js +102 -0
- package/dist/cjs/dev-tools/https/index.js +57 -0
- package/dist/cjs/dev-tools/watcher/dependencyTree.js +94 -0
- package/dist/cjs/dev-tools/watcher/index.js +143 -0
- package/dist/cjs/dev-tools/watcher/statsCache.js +95 -0
- package/dist/cjs/dev.js +111 -0
- package/dist/cjs/helpers/devOptions.js +61 -0
- package/dist/cjs/helpers/fileReader.js +53 -0
- package/dist/cjs/helpers/index.js +173 -0
- package/dist/cjs/helpers/mock.js +136 -0
- package/dist/cjs/helpers/repack.js +50 -0
- package/dist/cjs/helpers/utils.js +37 -0
- package/dist/cjs/index.js +36 -0
- package/dist/cjs/types.js +18 -0
- package/dist/esm/createDevServer.mjs +58 -0
- package/dist/esm/dev-tools/https/index.mjs +23 -0
- package/dist/esm/dev-tools/watcher/dependencyTree.mjs +57 -0
- package/dist/esm/dev-tools/watcher/index.mjs +91 -0
- package/dist/esm/dev-tools/watcher/statsCache.mjs +50 -0
- package/dist/esm/dev.mjs +77 -0
- package/dist/esm/helpers/devOptions.mjs +24 -0
- package/dist/esm/helpers/fileReader.mjs +19 -0
- package/dist/esm/helpers/index.mjs +65 -0
- package/dist/esm/helpers/mock.mjs +86 -0
- package/dist/esm/helpers/repack.mjs +16 -0
- package/dist/esm/helpers/utils.mjs +3 -0
- package/dist/esm/index.mjs +1 -0
- package/dist/esm/types.mjs +0 -0
- package/dist/esm-node/createDevServer.mjs +59 -0
- package/dist/esm-node/dev-tools/https/index.mjs +28 -0
- package/dist/esm-node/dev-tools/watcher/dependencyTree.mjs +58 -0
- package/dist/esm-node/dev-tools/watcher/index.mjs +93 -0
- package/dist/esm-node/dev-tools/watcher/statsCache.mjs +51 -0
- package/dist/esm-node/dev.mjs +78 -0
- package/dist/esm-node/helpers/devOptions.mjs +25 -0
- package/dist/esm-node/helpers/fileReader.mjs +20 -0
- package/dist/esm-node/helpers/index.mjs +67 -0
- package/dist/esm-node/helpers/mock.mjs +87 -0
- package/dist/esm-node/helpers/repack.mjs +18 -0
- package/dist/esm-node/helpers/utils.mjs +4 -0
- package/dist/esm-node/index.mjs +2 -0
- package/dist/esm-node/types.mjs +1 -0
- package/dist/types/createDevServer.d.ts +8 -0
- package/dist/types/dev-tools/https/index.d.ts +6 -0
- package/dist/types/dev-tools/watcher/dependencyTree.d.ts +28 -0
- package/dist/types/dev-tools/watcher/index.d.ts +17 -0
- package/dist/types/dev-tools/watcher/statsCache.d.ts +10 -0
- package/dist/types/dev.d.ts +9 -0
- package/dist/types/helpers/devOptions.d.ts +11 -0
- package/dist/types/helpers/fileReader.d.ts +3 -0
- package/dist/types/helpers/index.d.ts +15 -0
- package/dist/types/helpers/mock.d.ts +16 -0
- package/dist/types/helpers/repack.d.ts +2 -0
- package/dist/types/helpers/utils.d.ts +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/types.d.ts +56 -0
- package/package.json +89 -0
- package/rslib.config.mts +4 -0
- package/rstest.config.mts +5 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import __rslib_shim_module__ from "node:module";
|
|
2
|
+
const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
|
|
3
|
+
import { chokidar, fs } from "@modern-js/utils";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { DependencyTree } from "./dependencyTree.mjs";
|
|
6
|
+
import { StatsCache } from "./statsCache.mjs";
|
|
7
|
+
const defaultWatchOptions = {
|
|
8
|
+
ignoreInitial: true,
|
|
9
|
+
ignored: /api\/typings\/.*/
|
|
10
|
+
};
|
|
11
|
+
const getWatchedFiles = (watcher)=>{
|
|
12
|
+
const watched = watcher.getWatched();
|
|
13
|
+
const files = [];
|
|
14
|
+
Object.keys(watched).forEach((dir)=>{
|
|
15
|
+
const dirFiles = watched[dir];
|
|
16
|
+
if (!dirFiles) return;
|
|
17
|
+
dirFiles.forEach((fileName)=>{
|
|
18
|
+
files.push(path.join(dir, fileName));
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return files;
|
|
22
|
+
};
|
|
23
|
+
const mergeWatchOptions = (options)=>{
|
|
24
|
+
const watchOptions = {
|
|
25
|
+
...options
|
|
26
|
+
};
|
|
27
|
+
if (watchOptions) {
|
|
28
|
+
const { ignored } = watchOptions;
|
|
29
|
+
const finalIgnored = ignored ? [
|
|
30
|
+
defaultWatchOptions.ignored,
|
|
31
|
+
...Array.isArray(ignored) ? ignored : [
|
|
32
|
+
ignored
|
|
33
|
+
]
|
|
34
|
+
] : ignored;
|
|
35
|
+
if (finalIgnored) watchOptions.ignored = finalIgnored;
|
|
36
|
+
}
|
|
37
|
+
const finalWatchOptions = {
|
|
38
|
+
...defaultWatchOptions,
|
|
39
|
+
...watchOptions
|
|
40
|
+
};
|
|
41
|
+
return finalWatchOptions;
|
|
42
|
+
};
|
|
43
|
+
class Watcher {
|
|
44
|
+
listen(files, options, callback) {
|
|
45
|
+
const watched = files.filter(Boolean);
|
|
46
|
+
const filenames = watched.map((filename)=>filename.replace(/\\/g, '/'));
|
|
47
|
+
const cache = new StatsCache();
|
|
48
|
+
const watcher = chokidar.watch(filenames, options);
|
|
49
|
+
watcher.on('ready', ()=>{
|
|
50
|
+
cache.add(getWatchedFiles(watcher));
|
|
51
|
+
});
|
|
52
|
+
watcher.on('change', (changed)=>{
|
|
53
|
+
if (!fs.existsSync(changed) || cache.isDiff(changed)) {
|
|
54
|
+
cache.refresh(changed);
|
|
55
|
+
callback(changed, 'change');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
watcher.on('add', (changed)=>{
|
|
59
|
+
if (!cache.has(changed)) {
|
|
60
|
+
cache.add([
|
|
61
|
+
changed
|
|
62
|
+
]);
|
|
63
|
+
callback(changed, 'add');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
watcher.on('unlink', (changed)=>{
|
|
67
|
+
cache.del(changed);
|
|
68
|
+
callback(changed, 'unlink');
|
|
69
|
+
});
|
|
70
|
+
this.watcher = watcher;
|
|
71
|
+
}
|
|
72
|
+
createDepTree() {
|
|
73
|
+
this.dependencyTree = new DependencyTree();
|
|
74
|
+
}
|
|
75
|
+
updateDepTree() {
|
|
76
|
+
this.dependencyTree?.update(require.cache);
|
|
77
|
+
}
|
|
78
|
+
cleanDepCache(filepath) {
|
|
79
|
+
const node = this.dependencyTree?.getNode(filepath);
|
|
80
|
+
if (node && require.cache[filepath]) {
|
|
81
|
+
delete require.cache[filepath];
|
|
82
|
+
for (const parentNode of node.parent.values())this.cleanDepCache(parentNode.module.filename);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
close() {
|
|
86
|
+
return this.watcher.close();
|
|
87
|
+
}
|
|
88
|
+
constructor(){
|
|
89
|
+
this.dependencyTree = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export default Watcher;
|
|
93
|
+
export { defaultWatchOptions, getWatchedFiles, mergeWatchOptions };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import crypto_0 from "crypto";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
class StatsCache {
|
|
5
|
+
add(files) {
|
|
6
|
+
const { cachedHash, cachedSize } = this;
|
|
7
|
+
for (const filename of files)if (fs.existsSync(filename)) {
|
|
8
|
+
const stats = fs.statSync(filename);
|
|
9
|
+
if (stats.isFile() && !cachedHash[filename]) {
|
|
10
|
+
cachedHash[filename] = this.hash(stats, filename);
|
|
11
|
+
cachedSize[filename] = stats.size;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
refresh(filename) {
|
|
16
|
+
const { cachedHash, cachedSize } = this;
|
|
17
|
+
if (fs.existsSync(filename)) {
|
|
18
|
+
const stats = fs.statSync(filename);
|
|
19
|
+
if (stats.isFile()) {
|
|
20
|
+
cachedHash[filename] = this.hash(stats, filename);
|
|
21
|
+
cachedSize[filename] = stats.size;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
del(filename) {
|
|
26
|
+
if (this.cachedHash[filename]) {
|
|
27
|
+
delete this.cachedHash[filename];
|
|
28
|
+
delete this.cachedSize[filename];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
isDiff(filename) {
|
|
32
|
+
const { cachedHash, cachedSize } = this;
|
|
33
|
+
const stats = fs.statSync(filename);
|
|
34
|
+
const hash = cachedHash[filename];
|
|
35
|
+
const size = cachedSize[filename];
|
|
36
|
+
if (stats.size !== size) return true;
|
|
37
|
+
if (this.hash(stats, filename) !== hash) return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
has(filename) {
|
|
41
|
+
return Boolean(this.cachedHash[filename]);
|
|
42
|
+
}
|
|
43
|
+
hash(stats, filename) {
|
|
44
|
+
return crypto_0.createHash('md5').update(fs.readFileSync(filename)).digest('hex');
|
|
45
|
+
}
|
|
46
|
+
constructor(){
|
|
47
|
+
this.cachedHash = {};
|
|
48
|
+
this.cachedSize = {};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export { StatsCache };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { connectMid2HonoMid } from "@modern-js/server-core/node";
|
|
3
|
+
import { API_DIR, SHARED_DIR } from "@modern-js/utils";
|
|
4
|
+
import { getDevOptions, getMockMiddleware, initFileReader, onRepack, startWatcher } from "./helpers/index.mjs";
|
|
5
|
+
const devPlugin = (options, compiler)=>({
|
|
6
|
+
name: '@modern-js/plugin-dev',
|
|
7
|
+
setup (api) {
|
|
8
|
+
const { config, pwd, builder, builderDevServer } = options;
|
|
9
|
+
const closeCb = [];
|
|
10
|
+
const dev = getDevOptions(options.dev);
|
|
11
|
+
api.onPrepare(async ()=>{
|
|
12
|
+
const { middlewares: builderMiddlewares, close, connectWebSocket } = builderDevServer || {};
|
|
13
|
+
close && closeCb.push(close);
|
|
14
|
+
const { middlewares, distDirectory, nodeServer, apiDirectory, sharedDirectory, serverBase } = api.getServerContext();
|
|
15
|
+
connectWebSocket && nodeServer && connectWebSocket({
|
|
16
|
+
server: nodeServer
|
|
17
|
+
});
|
|
18
|
+
const hooks = api.getHooks();
|
|
19
|
+
builder?.onDevCompileDone(({ stats })=>{
|
|
20
|
+
if ('server' !== stats.toJson({
|
|
21
|
+
all: false
|
|
22
|
+
}).name) onRepack(distDirectory, hooks);
|
|
23
|
+
});
|
|
24
|
+
const { watchOptions } = config.server;
|
|
25
|
+
const watcher = startWatcher({
|
|
26
|
+
pwd,
|
|
27
|
+
distDir: distDirectory,
|
|
28
|
+
apiDir: apiDirectory || API_DIR,
|
|
29
|
+
sharedDir: sharedDirectory || SHARED_DIR,
|
|
30
|
+
watchOptions,
|
|
31
|
+
server: serverBase
|
|
32
|
+
});
|
|
33
|
+
closeCb.push(watcher.close.bind(watcher));
|
|
34
|
+
closeCb.length > 0 && nodeServer?.on('close', ()=>{
|
|
35
|
+
closeCb.forEach((cb)=>{
|
|
36
|
+
cb();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
const before = [];
|
|
40
|
+
const after = [];
|
|
41
|
+
const { setupMiddlewares = [] } = dev;
|
|
42
|
+
setupMiddlewares.forEach((handler)=>{
|
|
43
|
+
handler({
|
|
44
|
+
unshift: (...handlers)=>before.unshift(...handlers),
|
|
45
|
+
push: (...handlers)=>after.push(...handlers)
|
|
46
|
+
}, {
|
|
47
|
+
sockWrite: ()=>{}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
before.forEach((middleware, index)=>{
|
|
51
|
+
middlewares.push({
|
|
52
|
+
name: `before-dev-server-${index}`,
|
|
53
|
+
handler: connectMid2HonoMid(middleware)
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
const mockMiddleware = await getMockMiddleware(pwd);
|
|
57
|
+
middlewares.push({
|
|
58
|
+
name: 'mock-dev',
|
|
59
|
+
handler: mockMiddleware
|
|
60
|
+
});
|
|
61
|
+
builderMiddlewares && middlewares.push({
|
|
62
|
+
name: 'rsbuild-dev',
|
|
63
|
+
handler: connectMid2HonoMid(builderMiddlewares)
|
|
64
|
+
});
|
|
65
|
+
after.forEach((middleware, index)=>{
|
|
66
|
+
middlewares.push({
|
|
67
|
+
name: `after-dev-server-${index}`,
|
|
68
|
+
handler: connectMid2HonoMid(middleware)
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
middlewares.push({
|
|
72
|
+
name: 'init-file-reader',
|
|
73
|
+
handler: initFileReader(compiler)
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
export { devPlugin };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const getDevOptions = (devOptions)=>{
|
|
3
|
+
const defaultOptions = {
|
|
4
|
+
https: false,
|
|
5
|
+
server: {}
|
|
6
|
+
};
|
|
7
|
+
return {
|
|
8
|
+
...defaultOptions,
|
|
9
|
+
...devOptions
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const getDevAssetPrefix = (builder)=>new Promise((resolve)=>{
|
|
13
|
+
if (!builder) return resolve('');
|
|
14
|
+
builder?.onAfterCreateCompiler((params)=>{
|
|
15
|
+
let webCompiler;
|
|
16
|
+
webCompiler = 'compilers' in params.compiler ? params.compiler.compilers.find((c)=>'web' === c.name || 'client' === c.name) : params.compiler;
|
|
17
|
+
const publicPath = webCompiler?.options?.output?.publicPath;
|
|
18
|
+
if (publicPath && 'string' == typeof publicPath) {
|
|
19
|
+
const formatPublicPath = publicPath.replace(/^https?:\/\/[^/]+/, '');
|
|
20
|
+
return resolve(formatPublicPath);
|
|
21
|
+
}
|
|
22
|
+
return resolve('');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
export { getDevAssetPrefix, getDevOptions };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
3
|
+
const initFileReader = (compiler)=>{
|
|
4
|
+
let isInit = false;
|
|
5
|
+
return async (ctx, next)=>{
|
|
6
|
+
if (isInit) return next();
|
|
7
|
+
isInit = true;
|
|
8
|
+
const { res } = ctx.env.node;
|
|
9
|
+
if (!compiler) {
|
|
10
|
+
fileReader.reset();
|
|
11
|
+
return next();
|
|
12
|
+
}
|
|
13
|
+
const resolvedCompiler = 'compilers' in compiler ? compiler.compilers[0] : compiler;
|
|
14
|
+
const outputFileSystem = resolvedCompiler?.outputFileSystem;
|
|
15
|
+
if (outputFileSystem) fileReader.reset(outputFileSystem);
|
|
16
|
+
else fileReader.reset();
|
|
17
|
+
return next();
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export { initFileReader };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import __rslib_shim_module__ from "node:module";
|
|
2
|
+
const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
|
|
3
|
+
import { AGGRED_DIR } from "@modern-js/server-core";
|
|
4
|
+
import { SERVER_BUNDLE_DIRECTORY, SERVER_DIR, logger } from "@modern-js/utils";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import dev_tools_watcher, { mergeWatchOptions } from "../dev-tools/watcher/index.mjs";
|
|
7
|
+
import { initOrUpdateMockMiddlewares } from "./mock.mjs";
|
|
8
|
+
import { debug } from "./utils.mjs";
|
|
9
|
+
export * from "./devOptions.mjs";
|
|
10
|
+
export * from "./fileReader.mjs";
|
|
11
|
+
export * from "./mock.mjs";
|
|
12
|
+
export * from "./repack.mjs";
|
|
13
|
+
async function onServerChange({ pwd, filepath, event, server }) {
|
|
14
|
+
const { mock } = AGGRED_DIR;
|
|
15
|
+
const mockPath = path.normalize(path.join(pwd, mock));
|
|
16
|
+
const { hooks } = server;
|
|
17
|
+
if (filepath.startsWith(mockPath)) {
|
|
18
|
+
await initOrUpdateMockMiddlewares(pwd);
|
|
19
|
+
logger.info('Finish update the mock handlers');
|
|
20
|
+
} else try {
|
|
21
|
+
const fileChangeEvent = {
|
|
22
|
+
type: 'file-change',
|
|
23
|
+
payload: [
|
|
24
|
+
{
|
|
25
|
+
filename: filepath,
|
|
26
|
+
event
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
};
|
|
30
|
+
await hooks.onReset.call({
|
|
31
|
+
event: fileChangeEvent
|
|
32
|
+
});
|
|
33
|
+
debug(`Finish reload server, trigger by ${filepath} ${event}`);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
logger.error(e);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server }) {
|
|
39
|
+
const { mock } = AGGRED_DIR;
|
|
40
|
+
const defaultWatched = [
|
|
41
|
+
`${mock}/**/*`,
|
|
42
|
+
`${SERVER_DIR}/**/*`,
|
|
43
|
+
`${apiDir}/**`,
|
|
44
|
+
`${sharedDir}/**/*`,
|
|
45
|
+
`${distDir}/${SERVER_BUNDLE_DIRECTORY}/*-server-loaders.js`
|
|
46
|
+
];
|
|
47
|
+
const mergedWatchOptions = mergeWatchOptions(watchOptions);
|
|
48
|
+
const defaultWatchedPaths = defaultWatched.map((p)=>{
|
|
49
|
+
const finalPath = path.isAbsolute(p) ? p : path.join(pwd, p);
|
|
50
|
+
return path.normalize(finalPath);
|
|
51
|
+
});
|
|
52
|
+
const watcher = new dev_tools_watcher();
|
|
53
|
+
watcher.createDepTree();
|
|
54
|
+
watcher.listen(defaultWatchedPaths, mergedWatchOptions, (filepath, event)=>{
|
|
55
|
+
if (filepath.includes('-server-loaders.js')) return void delete require.cache[filepath];
|
|
56
|
+
watcher.updateDepTree();
|
|
57
|
+
watcher.cleanDepCache(filepath);
|
|
58
|
+
onServerChange({
|
|
59
|
+
pwd,
|
|
60
|
+
filepath,
|
|
61
|
+
event,
|
|
62
|
+
server
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
return watcher;
|
|
66
|
+
}
|
|
67
|
+
export { startWatcher };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import node_path from "node:path";
|
|
3
|
+
import { AGGRED_DIR } from "@modern-js/server-core";
|
|
4
|
+
import { connectMockMid2HonoMid } from "@modern-js/server-core/node";
|
|
5
|
+
import { fs } from "@modern-js/utils";
|
|
6
|
+
import { match } from "path-to-regexp";
|
|
7
|
+
let mockAPIs = [];
|
|
8
|
+
let mockConfig;
|
|
9
|
+
const parseKey = (key)=>{
|
|
10
|
+
const _blank = ' ';
|
|
11
|
+
const splitted = key.split(_blank).filter(Boolean);
|
|
12
|
+
if (splitted.length > 1) {
|
|
13
|
+
const [method, pathname] = splitted;
|
|
14
|
+
return {
|
|
15
|
+
method: (method ?? 'get').toLowerCase(),
|
|
16
|
+
path: pathname ?? '/'
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
method: 'get',
|
|
21
|
+
path: key
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
const getMockModule = async (pwd)=>{
|
|
25
|
+
const exts = [
|
|
26
|
+
'.ts',
|
|
27
|
+
'.js'
|
|
28
|
+
];
|
|
29
|
+
let mockFilePath = '';
|
|
30
|
+
for (const ext of exts){
|
|
31
|
+
const maybeMatch = node_path.join(pwd, `${AGGRED_DIR.mock}/index${ext}`);
|
|
32
|
+
if (await fs.pathExists(maybeMatch)) {
|
|
33
|
+
mockFilePath = maybeMatch;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!mockFilePath) return;
|
|
38
|
+
const { default: mockHandlers, config } = await import(mockFilePath);
|
|
39
|
+
const enable = config?.enable;
|
|
40
|
+
if (false === enable) return;
|
|
41
|
+
if (!mockHandlers) throw new Error(`Mock file ${mockFilePath} parsed failed!`);
|
|
42
|
+
return {
|
|
43
|
+
mockHandlers,
|
|
44
|
+
config
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const getMatched = (request, mockApis)=>{
|
|
48
|
+
const { path: targetPathname, method: targetMethod } = request;
|
|
49
|
+
const matched = mockApis.find((mockApi)=>{
|
|
50
|
+
const { method, path: pathname } = mockApi;
|
|
51
|
+
if (method.toLowerCase() === targetMethod.toLowerCase()) return match(pathname, {
|
|
52
|
+
decode: decodeURIComponent
|
|
53
|
+
})(targetPathname);
|
|
54
|
+
return false;
|
|
55
|
+
});
|
|
56
|
+
return matched;
|
|
57
|
+
};
|
|
58
|
+
async function initOrUpdateMockMiddlewares(pwd) {
|
|
59
|
+
const mockModule = await getMockModule(pwd);
|
|
60
|
+
mockConfig = mockModule?.config;
|
|
61
|
+
mockAPIs = Object.entries(mockModule?.mockHandlers || {}).map(([key, handler])=>{
|
|
62
|
+
const { method, path } = parseKey(key);
|
|
63
|
+
return {
|
|
64
|
+
method,
|
|
65
|
+
path,
|
|
66
|
+
handler
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function getMockMiddleware(pwd) {
|
|
71
|
+
await initOrUpdateMockMiddlewares(pwd);
|
|
72
|
+
const mockMiddleware = async (c, next)=>{
|
|
73
|
+
if ('function' == typeof mockConfig?.enable) {
|
|
74
|
+
const isEnabled = mockConfig.enable(c.env.node.req, c.env.node.res);
|
|
75
|
+
if (!isEnabled) return next();
|
|
76
|
+
}
|
|
77
|
+
const matchedMockAPI = getMatched(c.req, mockAPIs);
|
|
78
|
+
if (matchedMockAPI) {
|
|
79
|
+
const { handler } = matchedMockAPI;
|
|
80
|
+
if ('function' == typeof handler) return await connectMockMid2HonoMid(handler)(c, next);
|
|
81
|
+
return c.json(handler);
|
|
82
|
+
}
|
|
83
|
+
return next();
|
|
84
|
+
};
|
|
85
|
+
return mockMiddleware;
|
|
86
|
+
}
|
|
87
|
+
export { getMatched, getMockMiddleware, initOrUpdateMockMiddlewares };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import __rslib_shim_module__ from "node:module";
|
|
2
|
+
const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
|
|
3
|
+
import { fileReader } from "@modern-js/runtime-utils/fileReader";
|
|
4
|
+
const cleanSSRCache = (distDir)=>{
|
|
5
|
+
Object.keys(require.cache).forEach((key)=>{
|
|
6
|
+
if (key.startsWith(distDir)) delete require.cache[key];
|
|
7
|
+
});
|
|
8
|
+
};
|
|
9
|
+
const onRepack = (distDir, hooks)=>{
|
|
10
|
+
cleanSSRCache(distDir);
|
|
11
|
+
fileReader.reset();
|
|
12
|
+
hooks.onReset.call({
|
|
13
|
+
event: {
|
|
14
|
+
type: 'repack'
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
export { onRepack };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "node:module";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ApplyPlugins, ModernDevServerOptions } from './types';
|
|
2
|
+
export declare function createDevServer(options: ModernDevServerOptions, applyPlugins: ApplyPlugins): Promise<{
|
|
3
|
+
server: (import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse> | import("node:https").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse> | import("node:http2").Http2SecureServer<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse, typeof import("node:http2").Http2ServerRequest, typeof import("node:http2").Http2ServerResponse>) & {
|
|
4
|
+
getRequestListener: () => ReturnType<(handler: import("@modern-js/server-core/dist/types/types").RequestHandler) => (req: import("@modern-js/types/server").NodeRequest, res: import("@modern-js/types/server").NodeResponse) => Promise<void>>;
|
|
5
|
+
getRequestHandler: () => import("@modern-js/server-core/dist/types/types").RequestHandler;
|
|
6
|
+
};
|
|
7
|
+
afterListen: () => Promise<void>;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const defaultIgnores: string[];
|
|
2
|
+
export interface DependencyTreeOptions {
|
|
3
|
+
root: string;
|
|
4
|
+
ignore?: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface TreeNode {
|
|
7
|
+
module: NodeModule;
|
|
8
|
+
parent: Set<TreeNode>;
|
|
9
|
+
children: Set<TreeNode>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `require.cache` already is a dependency tree, however require cache's
|
|
13
|
+
* `module.parent` is the module that first required. so we have to implement
|
|
14
|
+
* a new tree which revisit the cache tree to find all parent node
|
|
15
|
+
*/
|
|
16
|
+
export declare class DependencyTree {
|
|
17
|
+
private readonly tree;
|
|
18
|
+
private readonly ignore;
|
|
19
|
+
constructor();
|
|
20
|
+
getNode(path: string): TreeNode | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* update dependency tree
|
|
23
|
+
*
|
|
24
|
+
* @param cache
|
|
25
|
+
*/
|
|
26
|
+
update(cache: any): void;
|
|
27
|
+
private shouldIgnore;
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type FSWatcher, type WatchOptions } from '@modern-js/utils';
|
|
2
|
+
export type WatchEvent = 'add' | 'change' | 'unlink';
|
|
3
|
+
export declare const defaultWatchOptions: {
|
|
4
|
+
ignoreInitial: boolean;
|
|
5
|
+
ignored: RegExp;
|
|
6
|
+
};
|
|
7
|
+
export declare const getWatchedFiles: (watcher: FSWatcher) => string[];
|
|
8
|
+
export declare const mergeWatchOptions: (options?: WatchOptions) => WatchOptions;
|
|
9
|
+
export default class Watcher {
|
|
10
|
+
private dependencyTree;
|
|
11
|
+
private watcher;
|
|
12
|
+
listen(files: string[], options: WatchOptions, callback: (changed: string, event: WatchEvent) => void): void;
|
|
13
|
+
createDepTree(): void;
|
|
14
|
+
updateDepTree(): void;
|
|
15
|
+
cleanDepCache(filepath: string): void;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class StatsCache {
|
|
2
|
+
private readonly cachedHash;
|
|
3
|
+
private readonly cachedSize;
|
|
4
|
+
add(files: string[]): void;
|
|
5
|
+
refresh(filename: string): void;
|
|
6
|
+
del(filename: string): void;
|
|
7
|
+
isDiff(filename: string): boolean;
|
|
8
|
+
has(filename: string): boolean;
|
|
9
|
+
private hash;
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BuilderInstance, Rspack } from '@modern-js/builder';
|
|
2
|
+
import type { ServerBaseOptions, ServerPlugin } from '@modern-js/server-core';
|
|
3
|
+
import type { ModernDevServerOptions } from './types';
|
|
4
|
+
type BuilderDevServer = Awaited<ReturnType<BuilderInstance['createDevServer']>>;
|
|
5
|
+
export type DevPluginOptions = ModernDevServerOptions<ServerBaseOptions> & {
|
|
6
|
+
builderDevServer?: BuilderDevServer;
|
|
7
|
+
};
|
|
8
|
+
export declare const devPlugin: (options: DevPluginOptions, compiler: Rspack.Compiler | Rspack.MultiCompiler | null) => ServerPlugin;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BuilderInstance } from '@modern-js/builder';
|
|
2
|
+
import type { DevServerOptions } from '../types';
|
|
3
|
+
export declare const getDevOptions: (devOptions: DevServerOptions) => {
|
|
4
|
+
setupMiddlewares?: Array<(middlewares: {
|
|
5
|
+
unshift: (...handlers: import("@modern-js/types/server").RequestHandler[]) => void;
|
|
6
|
+
push: (...handlers: import("@modern-js/types/server").RequestHandler[]) => void;
|
|
7
|
+
}, server: import("@modern-js/types/server").ExposeServerApis) => void>;
|
|
8
|
+
https?: import("@modern-js/types/server/devServer").DevServerHttpsOptions;
|
|
9
|
+
server?: import("../types").DevServerConfig;
|
|
10
|
+
};
|
|
11
|
+
export declare const getDevAssetPrefix: (builder?: BuilderInstance) => Promise<string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ServerBase } from '@modern-js/server-core';
|
|
2
|
+
import { type WatchOptions } from '@modern-js/utils';
|
|
3
|
+
import Watcher from '../dev-tools/watcher';
|
|
4
|
+
export * from './devOptions';
|
|
5
|
+
export * from './fileReader';
|
|
6
|
+
export * from './mock';
|
|
7
|
+
export * from './repack';
|
|
8
|
+
export declare function startWatcher({ pwd, distDir, apiDir, sharedDir, watchOptions, server, }: {
|
|
9
|
+
pwd: string;
|
|
10
|
+
distDir: string;
|
|
11
|
+
apiDir: string;
|
|
12
|
+
sharedDir: string;
|
|
13
|
+
watchOptions?: WatchOptions;
|
|
14
|
+
server: ServerBase;
|
|
15
|
+
}): Watcher;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type InternalRequest, type Middleware } from '@modern-js/server-core';
|
|
2
|
+
import type { NextFunction } from '@modern-js/types';
|
|
3
|
+
import type { NodeRequest, NodeResponse } from '@modern-js/types/server';
|
|
4
|
+
/** Types: Mock */
|
|
5
|
+
type MockHandler = {
|
|
6
|
+
data: any;
|
|
7
|
+
} | ((req: NodeRequest, res: NodeResponse, next: NextFunction) => Promise<void> | void);
|
|
8
|
+
type MockAPI = {
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
handler: MockHandler;
|
|
12
|
+
};
|
|
13
|
+
export declare const getMatched: (request: InternalRequest, mockApis: MockAPI[]) => MockAPI | undefined;
|
|
14
|
+
export declare function initOrUpdateMockMiddlewares(pwd: string): Promise<void>;
|
|
15
|
+
export declare function getMockMiddleware(pwd: string): Promise<Middleware>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const debug: import("@modern-js/utils/compiled/debug").Debugger;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Server as NodeServer } from 'node:http';
|
|
2
|
+
import type { Http2SecureServer } from 'node:http2';
|
|
3
|
+
import type { BuilderInstance } from '@modern-js/builder';
|
|
4
|
+
import type { ServerBase, ServerBaseOptions, ServerPlugin } from '@modern-js/server-core';
|
|
5
|
+
import type { DevServerHttpsOptions, ExposeServerApis, RequestHandler } from '@modern-js/types';
|
|
6
|
+
export type { DevServerHttpsOptions };
|
|
7
|
+
type StaticOrigin = boolean | string | RegExp | Array<boolean | string | RegExp>;
|
|
8
|
+
type CustomOrigin = (requestOrigin: string | undefined, callback: (err: Error | null, origin?: StaticOrigin) => void) => void;
|
|
9
|
+
export interface CorsOptions {
|
|
10
|
+
/**
|
|
11
|
+
* @default '*''
|
|
12
|
+
*/
|
|
13
|
+
origin?: StaticOrigin | CustomOrigin | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface DevServerConfig {
|
|
16
|
+
/**
|
|
17
|
+
* Configure CORS for the dev server.
|
|
18
|
+
* - object: enable CORS with the specified options.
|
|
19
|
+
* - true: enable CORS with default options (allow all origins, not recommended).
|
|
20
|
+
* - false: disable CORS.
|
|
21
|
+
* @default
|
|
22
|
+
* ```js
|
|
23
|
+
* { origin: defaultAllowedOrigins }
|
|
24
|
+
* ```
|
|
25
|
+
* where `defaultAllowedOrigins` includes:
|
|
26
|
+
* - `localhost`
|
|
27
|
+
* - `127.0.0.1`
|
|
28
|
+
*
|
|
29
|
+
* @link https://github.com/expressjs/cors
|
|
30
|
+
*/
|
|
31
|
+
cors?: boolean | CorsOptions;
|
|
32
|
+
}
|
|
33
|
+
export type DevServerOptions = {
|
|
34
|
+
/** Provides the ability to execute a custom function and apply custom middlewares */
|
|
35
|
+
setupMiddlewares?: Array<(
|
|
36
|
+
/** Order: `devServer.before` => `unshift` => internal middlewares => `push` => `devServer.after` */
|
|
37
|
+
middlewares: {
|
|
38
|
+
/** Use the `unshift` method if you want to run a middleware before all other middlewares */
|
|
39
|
+
unshift: (...handlers: RequestHandler[]) => void;
|
|
40
|
+
/** Use the `push` method if you want to run a middleware after all other middlewares */
|
|
41
|
+
push: (...handlers: RequestHandler[]) => void;
|
|
42
|
+
}, server: ExposeServerApis) => void>;
|
|
43
|
+
/** Whether to enable hot reload. */
|
|
44
|
+
https?: DevServerHttpsOptions;
|
|
45
|
+
/** Dev server specific options. */
|
|
46
|
+
server?: DevServerConfig;
|
|
47
|
+
};
|
|
48
|
+
export type ExtraOptions = {
|
|
49
|
+
dev: DevServerOptions;
|
|
50
|
+
runCompile?: boolean;
|
|
51
|
+
serverConfigPath: string;
|
|
52
|
+
builder?: BuilderInstance;
|
|
53
|
+
plugins?: ServerPlugin[];
|
|
54
|
+
};
|
|
55
|
+
export type ModernDevServerOptions<O extends ServerBaseOptions = ServerBaseOptions> = O & ExtraOptions;
|
|
56
|
+
export type ApplyPlugins<O extends ServerBaseOptions = ServerBaseOptions> = (server: ServerBase, options: ModernDevServerOptions<O>, nodeServer?: NodeServer | Http2SecureServer) => Promise<void>;
|