@modern-js/server 1.1.5-beta.0 → 1.2.1-beta.1
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 +20 -0
- package/dist/js/modern/index.js +1 -7
- package/dist/js/modern/libs/context/context.js +3 -6
- package/dist/js/modern/libs/context/index.js +1 -7
- package/dist/js/modern/libs/hook-api/template.js +4 -4
- package/dist/js/modern/libs/proxy.js +1 -1
- package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +1 -2
- package/dist/js/modern/libs/render/reader.js +8 -11
- package/dist/js/modern/libs/route/index.js +2 -1
- package/dist/js/modern/server/index.js +5 -3
- package/dist/js/modern/server/modern-server.js +16 -10
- package/dist/js/modern/utils.js +1 -9
- package/dist/js/node/index.js +1 -49
- package/dist/js/node/libs/context/context.js +3 -6
- package/dist/js/node/libs/context/index.js +1 -7
- package/dist/js/node/libs/hook-api/template.js +4 -4
- package/dist/js/node/libs/proxy.js +1 -1
- package/dist/js/node/libs/render/cache/__tests__/cache.test.js +1 -2
- package/dist/js/node/libs/render/reader.js +8 -11
- package/dist/js/node/libs/route/index.js +6 -0
- package/dist/js/node/server/index.js +5 -3
- package/dist/js/node/server/modern-server.js +16 -10
- package/dist/js/node/utils.js +2 -12
- package/dist/types/index.d.ts +1 -3
- package/dist/types/libs/context/context.d.ts +7 -7
- package/dist/types/libs/context/index.d.ts +1 -8
- package/dist/types/libs/hook-api/template.d.ts +4 -4
- package/dist/types/libs/route/index.d.ts +2 -1
- package/dist/types/server/index.d.ts +1 -1
- package/dist/types/server/modern-server.d.ts +1 -1
- package/dist/types/type.d.ts +6 -0
- package/dist/types/utils.d.ts +1 -2
- package/package.json +22 -21
- package/src/index.ts +2 -8
- package/src/libs/context/context.ts +8 -7
- package/src/libs/context/index.ts +2 -6
- package/src/libs/hook-api/template.ts +4 -4
- package/src/libs/proxy.ts +1 -1
- package/src/libs/render/cache/__tests__/cache.test.ts +2 -2
- package/src/libs/render/reader.ts +8 -8
- package/src/libs/render/type.ts +0 -2
- package/src/libs/route/index.ts +2 -1
- package/src/server/index.ts +3 -3
- package/src/server/modern-server.ts +15 -11
- package/src/type.ts +7 -0
- package/src/utils.ts +0 -14
- package/tests/.eslintrc.js +6 -0
- package/tests/context.test.ts +41 -0
- package/tests/fixtures/hosting-files/static/index.js +1 -0
- package/tests/fixtures/pure/modern.config.js +5 -0
- package/tests/fixtures/pure/package.json +21 -0
- package/tests/fixtures/pure/src/App.css +119 -0
- package/tests/fixtures/pure/src/App.tsx +43 -0
- package/tests/fixtures/pure/tsconfig.json +13 -0
- package/tests/fixtures/route-spec/index.json +29 -0
- package/tests/helper.ts +8 -0
- package/tests/hook.test.ts +44 -0
- package/tests/middleware.test.ts +178 -0
- package/tests/route.test.ts +54 -0
- package/tests/server.test.ts +89 -0
- package/tests/tsconfig.json +14 -0
- package/tests/utils.test.ts +40 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
html,
|
|
2
|
+
body {
|
|
3
|
+
padding: 0;
|
|
4
|
+
margin: 0;
|
|
5
|
+
font-family: nunito_for_arco, Helvetica Neue, Helvetica, PingFang SC,
|
|
6
|
+
Hiragino Sans GB, Microsoft YaHei, 微软雅黑, Arial, sans-serif;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
* {
|
|
10
|
+
-webkit-font-smoothing: antialiased;
|
|
11
|
+
-moz-osx-font-smoothing: grayscale;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.container {
|
|
16
|
+
min-height: 100vh;
|
|
17
|
+
max-width: 100%;
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
align-items: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
main {
|
|
25
|
+
padding: 5rem 0;
|
|
26
|
+
flex: 1;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
align-items: center;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.footer {
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 80px;
|
|
36
|
+
border-top: 1px solid #eaeaea;
|
|
37
|
+
display: flex;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
align-items: center;
|
|
40
|
+
background-color: #470000;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.footer a {
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
align-items: center;
|
|
47
|
+
flex-grow: 1;
|
|
48
|
+
color: #f4f4f4;
|
|
49
|
+
text-decoration: none;
|
|
50
|
+
font-size: 1.1rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.logo {
|
|
54
|
+
margin-bottom: 2rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.logo svg {
|
|
58
|
+
width: 450px;
|
|
59
|
+
height: 132px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.description {
|
|
63
|
+
text-align: center;
|
|
64
|
+
line-height: 1.5;
|
|
65
|
+
font-size: 1.5rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.code {
|
|
69
|
+
background: #fafafa;
|
|
70
|
+
border-radius: 5px;
|
|
71
|
+
padding: 0.75rem;
|
|
72
|
+
font-size: 1.1rem;
|
|
73
|
+
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
|
|
74
|
+
Bitstream Vera Sans Mono, Courier New, monospace;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (max-width: 600px) {
|
|
78
|
+
.grid {
|
|
79
|
+
width: 100%;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.grid {
|
|
85
|
+
display: flex;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
width: 800px;
|
|
90
|
+
margin-top: 3rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.card {
|
|
94
|
+
margin: 1rem;
|
|
95
|
+
padding: 1.5rem;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
height: 100px;
|
|
100
|
+
color: inherit;
|
|
101
|
+
text-decoration: none;
|
|
102
|
+
border: 1px solid #470000;
|
|
103
|
+
color: #470000;
|
|
104
|
+
transition: color 0.15s ease, border-color 0.15s ease;
|
|
105
|
+
width: 45%;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.card:hover,
|
|
109
|
+
.card:focus,
|
|
110
|
+
.card:active {
|
|
111
|
+
transform: scale(1.05);
|
|
112
|
+
transition: 0.1s ease-in-out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.card h2 {
|
|
116
|
+
font-size: 1.5rem;
|
|
117
|
+
margin: 0;
|
|
118
|
+
padding: 0;
|
|
119
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import './App.css';
|
|
2
|
+
|
|
3
|
+
const App = () => (
|
|
4
|
+
<div className="container">
|
|
5
|
+
<main>
|
|
6
|
+
<div className="logo">
|
|
7
|
+
<img
|
|
8
|
+
src="https://lf3-static.bytednsdoc.com/obj/eden-cn/ylaelkeh7nuhfnuhf/modernjs-cover.png"
|
|
9
|
+
width="300"
|
|
10
|
+
alt="Modern.js Logo"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
<p className="description">
|
|
14
|
+
Get started by editing <code className="code">src/home/App.tsx</code>
|
|
15
|
+
</p>
|
|
16
|
+
<div className="grid">
|
|
17
|
+
<a href="https://modernjs.dev/docs/start" className="card">
|
|
18
|
+
<h2>Quick Start Tencent</h2>
|
|
19
|
+
</a>
|
|
20
|
+
<a href="https://modernjs.dev/docs/guides" className="card">
|
|
21
|
+
<h2>Handbook</h2>
|
|
22
|
+
</a>
|
|
23
|
+
<a href="https://modernjs.dev/docs/apis" className="card">
|
|
24
|
+
<h2>API Reference </h2>
|
|
25
|
+
</a>
|
|
26
|
+
<a
|
|
27
|
+
href="https://modernjs.dev/coming-soon"
|
|
28
|
+
target="_blank"
|
|
29
|
+
rel="noopener noreferrer"
|
|
30
|
+
className="card">
|
|
31
|
+
<h2>Community </h2>
|
|
32
|
+
</a>
|
|
33
|
+
</div>
|
|
34
|
+
</main>
|
|
35
|
+
<footer className="footer">
|
|
36
|
+
<a href="https://modernjs.dev" target="_blank" rel="noopener noreferrer">
|
|
37
|
+
Powered by Modern.js
|
|
38
|
+
</a>
|
|
39
|
+
</footer>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export default App;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"routes": [
|
|
3
|
+
{
|
|
4
|
+
"urlPath": "/entry",
|
|
5
|
+
"entryName": "entry",
|
|
6
|
+
"entryPath": "html/entry/index.html",
|
|
7
|
+
"isSPA": true,
|
|
8
|
+
"isSSR": true,
|
|
9
|
+
"enableModernMode": false,
|
|
10
|
+
"bundle": "bundles/entry.js"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"urlPath": "/home",
|
|
14
|
+
"entryName": "home",
|
|
15
|
+
"entryPath": "html/home/index.html",
|
|
16
|
+
"isSPA": true,
|
|
17
|
+
"isSSR": true,
|
|
18
|
+
"enableModernMode": false,
|
|
19
|
+
"bundle": "bundles/home.js"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"urlPath": "/api",
|
|
23
|
+
"isApi": true,
|
|
24
|
+
"entryPath": "",
|
|
25
|
+
"isSPA": false,
|
|
26
|
+
"isSSR": false
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
package/tests/helper.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createRouteAPI } from '../src/libs/hook-api/route';
|
|
2
|
+
import { createTemplateAPI } from '../src/libs/hook-api/template';
|
|
3
|
+
import { RouteMatchManager } from '../src/libs/route';
|
|
4
|
+
import { createDoc } from './helper';
|
|
5
|
+
import spec from './fixtures/route-spec/index.json';
|
|
6
|
+
|
|
7
|
+
describe('test hook api', () => {
|
|
8
|
+
test('should route api work correctly', () => {
|
|
9
|
+
const manager = new RouteMatchManager();
|
|
10
|
+
manager.reset(spec.routes);
|
|
11
|
+
const matcher = manager.match('/home');
|
|
12
|
+
|
|
13
|
+
const routeAPI = createRouteAPI(matcher!, manager);
|
|
14
|
+
expect(routeAPI.cur().entryName).toBe('home');
|
|
15
|
+
expect(routeAPI.get('entry')?.entryPath).toBe('html/entry/index.html');
|
|
16
|
+
|
|
17
|
+
expect(routeAPI.use('home')).toBeTruthy();
|
|
18
|
+
expect(routeAPI.cur().entryName).toBe('home');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('should template api work correctly', () => {
|
|
22
|
+
const content = createDoc();
|
|
23
|
+
const templateAPI = createTemplateAPI(content);
|
|
24
|
+
|
|
25
|
+
expect(templateAPI.get()).toMatch(content);
|
|
26
|
+
|
|
27
|
+
templateAPI.replace('mock', 'replace');
|
|
28
|
+
expect(templateAPI.get()).toMatch('replace');
|
|
29
|
+
|
|
30
|
+
templateAPI.appendBody('after body');
|
|
31
|
+
templateAPI.prependBody('before body');
|
|
32
|
+
templateAPI.appendHead('after head');
|
|
33
|
+
templateAPI.prependHead('before head');
|
|
34
|
+
|
|
35
|
+
const newContent = templateAPI.get();
|
|
36
|
+
expect(newContent).toMatch('<head>before head');
|
|
37
|
+
expect(newContent).toMatch('<body>before body');
|
|
38
|
+
expect(newContent).toMatch('after head</head>');
|
|
39
|
+
expect(newContent).toMatch('after body</body>');
|
|
40
|
+
|
|
41
|
+
templateAPI.set('<div>empty</div>');
|
|
42
|
+
expect(templateAPI.get()).toBe('<div>empty</div>');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/* eslint-disable max-nested-callbacks */
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import EventEmitter from 'events';
|
|
4
|
+
import { Readable } from 'stream';
|
|
5
|
+
import { createServer, Server } from 'http';
|
|
6
|
+
import httpMocks from 'node-mocks-http';
|
|
7
|
+
import portfinder from 'portfinder';
|
|
8
|
+
import axios from 'axios';
|
|
9
|
+
import { createContext } from '../src/libs/context';
|
|
10
|
+
import { createStaticFileHandler } from '../src/libs/serve-file';
|
|
11
|
+
import { createProxyHandler } from '../src/libs/proxy';
|
|
12
|
+
|
|
13
|
+
describe('test middleware create factory', () => {
|
|
14
|
+
describe('should create static-file handler correctly', () => {
|
|
15
|
+
const middleware = createStaticFileHandler([
|
|
16
|
+
{
|
|
17
|
+
path: /static\/|upload\//,
|
|
18
|
+
target: path.join(__dirname, './fixtures/hosting-files'),
|
|
19
|
+
},
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
test('should get static file correctly', resolve => {
|
|
23
|
+
const req = httpMocks.createRequest({
|
|
24
|
+
path: '/static/index.js',
|
|
25
|
+
eventEmitter: Readable,
|
|
26
|
+
});
|
|
27
|
+
const res = httpMocks.createResponse({ eventEmitter: EventEmitter });
|
|
28
|
+
const mockContext = createContext(req, res);
|
|
29
|
+
res.on('finish', () => {
|
|
30
|
+
expect(res._getBuffer().toString().trim()).toBe(
|
|
31
|
+
"console.info('index.js');",
|
|
32
|
+
);
|
|
33
|
+
resolve();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
middleware(mockContext, () => {
|
|
37
|
+
throw new Error('should not happened');
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should miss static file correctly', resolve => {
|
|
42
|
+
const req = httpMocks.createRequest({
|
|
43
|
+
path: '/static/index.css',
|
|
44
|
+
eventEmitter: Readable,
|
|
45
|
+
});
|
|
46
|
+
const res = httpMocks.createResponse({ eventEmitter: EventEmitter });
|
|
47
|
+
const mockContext = createContext(req, res);
|
|
48
|
+
res.on('finish', () => {
|
|
49
|
+
throw new Error('should not happened');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
middleware(mockContext, () => {
|
|
53
|
+
req.destroy();
|
|
54
|
+
expect(true).toBeTruthy();
|
|
55
|
+
resolve();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
jest.setTimeout(1000 * 10);
|
|
61
|
+
describe('should create proxy handler correctly', () => {
|
|
62
|
+
test('should return null if no options', () => {
|
|
63
|
+
expect(createProxyHandler(null as any)).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
let sourceServerPort = 8080;
|
|
67
|
+
let sourceServer: Server | null = null;
|
|
68
|
+
beforeAll(async () => {
|
|
69
|
+
sourceServerPort = await portfinder.getPortPromise();
|
|
70
|
+
sourceServer = createServer((req, res) => {
|
|
71
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
72
|
+
res.write(req.url?.slice(1));
|
|
73
|
+
res.end();
|
|
74
|
+
}).listen(sourceServerPort);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
afterAll(() => {
|
|
78
|
+
if (sourceServer) {
|
|
79
|
+
sourceServer.close();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('should proxy correctly use simply options', async () => {
|
|
84
|
+
const port = await portfinder.getPortPromise();
|
|
85
|
+
const middlewares = createProxyHandler({
|
|
86
|
+
'/simple': `http://127.0.0.1:${sourceServerPort}`,
|
|
87
|
+
});
|
|
88
|
+
const proxyHandler = middlewares![0];
|
|
89
|
+
|
|
90
|
+
const server = createServer((req, res) => {
|
|
91
|
+
const context = createContext(req, res);
|
|
92
|
+
proxyHandler(context, () => {
|
|
93
|
+
throw new Error('should not happened');
|
|
94
|
+
});
|
|
95
|
+
}).listen(port);
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const { data } = await axios.get(`http://127.0.0.1:${port}/simple`);
|
|
99
|
+
expect(data).toBe('simple');
|
|
100
|
+
} finally {
|
|
101
|
+
server.close();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should proxy correctly use simply obj options', async () => {
|
|
106
|
+
const port = await portfinder.getPortPromise();
|
|
107
|
+
const middlewares = createProxyHandler({
|
|
108
|
+
'/simple-obj': {
|
|
109
|
+
target: `http://127.0.0.1:${sourceServerPort}`,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
const proxyHandler = middlewares![0];
|
|
113
|
+
|
|
114
|
+
const server = createServer((req, res) => {
|
|
115
|
+
const context = createContext(req, res);
|
|
116
|
+
proxyHandler(context, () => {
|
|
117
|
+
throw new Error('should not happened');
|
|
118
|
+
});
|
|
119
|
+
}).listen(port);
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const { data } = await axios.get(`http://127.0.0.1:${port}/simple-obj`);
|
|
123
|
+
expect(data).toBe('simple-obj');
|
|
124
|
+
} finally {
|
|
125
|
+
server.close();
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should proxy correctly use context options', async () => {
|
|
130
|
+
const port = await portfinder.getPortPromise();
|
|
131
|
+
const middlewares = createProxyHandler({
|
|
132
|
+
context: '/context',
|
|
133
|
+
target: `http://127.0.0.1:${sourceServerPort}`,
|
|
134
|
+
});
|
|
135
|
+
const proxyHandler = middlewares![0];
|
|
136
|
+
|
|
137
|
+
const server = createServer((req, res) => {
|
|
138
|
+
const context = createContext(req, res);
|
|
139
|
+
proxyHandler(context, () => {
|
|
140
|
+
throw new Error('should not happened');
|
|
141
|
+
});
|
|
142
|
+
}).listen(port);
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const { data } = await axios.get(`http://127.0.0.1:${port}/context`);
|
|
146
|
+
expect(data).toBe('context');
|
|
147
|
+
} finally {
|
|
148
|
+
server.close();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('should proxy correctly use array options', async () => {
|
|
153
|
+
const port = await portfinder.getPortPromise();
|
|
154
|
+
const middlewares = createProxyHandler([
|
|
155
|
+
{
|
|
156
|
+
context: '/array',
|
|
157
|
+
target: `http://127.0.0.1:${sourceServerPort}`,
|
|
158
|
+
},
|
|
159
|
+
]);
|
|
160
|
+
const proxyHandler = middlewares![0];
|
|
161
|
+
|
|
162
|
+
const server = createServer((req, res) => {
|
|
163
|
+
const context = createContext(req, res);
|
|
164
|
+
proxyHandler(context, () => {
|
|
165
|
+
throw new Error('should not happened');
|
|
166
|
+
});
|
|
167
|
+
}).listen(port);
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
const { data } = await axios.get(`http://127.0.0.1:${port}/array`);
|
|
171
|
+
expect(data).toBe('array');
|
|
172
|
+
} finally {
|
|
173
|
+
server.close();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
/* eslint-enable max-nested-callbacks */
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { RouteMatchManager, RouteMatcher } from '../src/libs/route';
|
|
2
|
+
import spec from './fixtures/route-spec/index.json';
|
|
3
|
+
|
|
4
|
+
describe('test route', () => {
|
|
5
|
+
describe('test route matcher', () => {
|
|
6
|
+
test('should matcher work correctyl with simple spec', () => {
|
|
7
|
+
const routeSpec = spec.routes[0];
|
|
8
|
+
const matcher = new RouteMatcher(routeSpec);
|
|
9
|
+
expect(matcher.spec).toBe(routeSpec);
|
|
10
|
+
expect(matcher.urlPath).toBe(routeSpec.urlPath);
|
|
11
|
+
expect(matcher.urlReg).toBeUndefined();
|
|
12
|
+
expect(matcher.urlMatcher).toBeUndefined();
|
|
13
|
+
|
|
14
|
+
const { isSSR, isApi, isSPA, urlPath, entryName, entryPath } =
|
|
15
|
+
matcher.generate();
|
|
16
|
+
|
|
17
|
+
expect(isSSR).toBeTruthy();
|
|
18
|
+
expect(isApi).toBeFalsy();
|
|
19
|
+
expect(isSPA).toBeTruthy();
|
|
20
|
+
expect(urlPath).toBe(routeSpec.urlPath);
|
|
21
|
+
expect(entryName).toBe(routeSpec.entryName);
|
|
22
|
+
expect(entryPath).toBe(routeSpec.entryPath);
|
|
23
|
+
|
|
24
|
+
expect(matcher.matchEntry('entry')).toBeTruthy();
|
|
25
|
+
expect(matcher.matchEntry('home')).toBeFalsy();
|
|
26
|
+
expect(matcher.matchLength('/entry')).toBe(6);
|
|
27
|
+
expect(matcher.matchUrlPath('/entry')).toBeTruthy();
|
|
28
|
+
expect(matcher.matchUrlPath('/home')).toBeFalsy();
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('test route manager', () => {
|
|
33
|
+
test('should manager work correctly with simple spec', async () => {
|
|
34
|
+
const manager = new RouteMatchManager();
|
|
35
|
+
expect(manager.matchers.length).toBe(0);
|
|
36
|
+
manager.reset(spec.routes);
|
|
37
|
+
expect(manager.matchers.length).toBe(3);
|
|
38
|
+
|
|
39
|
+
const matchedByEntry = manager.matchEntry('home');
|
|
40
|
+
expect(matchedByEntry).toBeDefined();
|
|
41
|
+
expect(matchedByEntry?.generate().entryName).toBe('home');
|
|
42
|
+
|
|
43
|
+
const matchedByUrl = manager.match('/entry');
|
|
44
|
+
expect(matchedByUrl).toBeDefined();
|
|
45
|
+
expect(matchedByUrl?.generate().entryName).toBe('entry');
|
|
46
|
+
|
|
47
|
+
const SSRUrlBundles = manager.getBundles();
|
|
48
|
+
expect(SSRUrlBundles).toEqual(['bundles/entry.js', 'bundles/home.js']);
|
|
49
|
+
|
|
50
|
+
manager.reset([]);
|
|
51
|
+
expect(manager.matchers.length).toBe(0);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { defaultsConfig, NormalizedConfig } from '@modern-js/core';
|
|
3
|
+
import { ModernServerContext, NextFunction } from '@modern-js/types';
|
|
4
|
+
import createServer, { Server } from '../src';
|
|
5
|
+
|
|
6
|
+
describe('test server', () => {
|
|
7
|
+
test('should throw error when ', resolve => {
|
|
8
|
+
try {
|
|
9
|
+
createServer(null as any);
|
|
10
|
+
} catch (e: any) {
|
|
11
|
+
expect((e as Error).message).toBe(
|
|
12
|
+
'can not start mserver without options',
|
|
13
|
+
);
|
|
14
|
+
resolve();
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('shoule get modern server instance', async () => {
|
|
19
|
+
const server = await createServer({
|
|
20
|
+
config: defaultsConfig as NormalizedConfig,
|
|
21
|
+
pwd: path.join(__dirname, './fixtures/pure'),
|
|
22
|
+
});
|
|
23
|
+
expect(server instanceof Server).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('shoule get production modern server instance', () => {
|
|
27
|
+
const appDirectory = path.join(__dirname, './fixtures/pure');
|
|
28
|
+
|
|
29
|
+
test('should init server correctly', async () => {
|
|
30
|
+
const server = await createServer({
|
|
31
|
+
config: defaultsConfig as NormalizedConfig,
|
|
32
|
+
pwd: appDirectory,
|
|
33
|
+
});
|
|
34
|
+
const modernServer = (server as any).server;
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
pwd,
|
|
38
|
+
distDir,
|
|
39
|
+
workDir,
|
|
40
|
+
conf,
|
|
41
|
+
handlers,
|
|
42
|
+
isDev,
|
|
43
|
+
staticGenerate,
|
|
44
|
+
presetRoutes,
|
|
45
|
+
} = modernServer;
|
|
46
|
+
expect(pwd).toBe(appDirectory);
|
|
47
|
+
expect(distDir).toBe(path.join(appDirectory, 'dist'));
|
|
48
|
+
expect(workDir).toBe(distDir);
|
|
49
|
+
expect(conf).toBe(defaultsConfig);
|
|
50
|
+
expect(handlers).toBeDefined();
|
|
51
|
+
expect(isDev).toBeFalsy();
|
|
52
|
+
expect(staticGenerate).toBeFalsy();
|
|
53
|
+
expect(presetRoutes).toBeUndefined();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('should add handler correctly', async () => {
|
|
57
|
+
const server = await createServer({
|
|
58
|
+
config: defaultsConfig as NormalizedConfig,
|
|
59
|
+
pwd: appDirectory,
|
|
60
|
+
});
|
|
61
|
+
const modernServer = server.server as any;
|
|
62
|
+
|
|
63
|
+
const len = modernServer.handlers.length;
|
|
64
|
+
|
|
65
|
+
const syncHandler = (ctx: ModernServerContext, next: NextFunction) => {
|
|
66
|
+
console.info(ctx.url);
|
|
67
|
+
next();
|
|
68
|
+
};
|
|
69
|
+
modernServer.addHandler(syncHandler);
|
|
70
|
+
|
|
71
|
+
const newLen = modernServer.handlers.length;
|
|
72
|
+
expect(len + 1).toBe(newLen);
|
|
73
|
+
expect(modernServer.handlers[newLen - 1]).not.toBe(syncHandler);
|
|
74
|
+
|
|
75
|
+
const asyncHandler = async (
|
|
76
|
+
ctx: ModernServerContext,
|
|
77
|
+
next: NextFunction,
|
|
78
|
+
) => {
|
|
79
|
+
console.info(ctx.url);
|
|
80
|
+
next();
|
|
81
|
+
};
|
|
82
|
+
modernServer.addHandler(asyncHandler);
|
|
83
|
+
const nextLen = modernServer.handlers.length;
|
|
84
|
+
|
|
85
|
+
expect(newLen + 1).toBe(nextLen);
|
|
86
|
+
expect(modernServer.handlers[nextLen - 1]).toBe(asyncHandler);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@modern-js/tsconfig/base",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"declaration": false,
|
|
5
|
+
"jsx": "preserve",
|
|
6
|
+
"baseUrl": "./",
|
|
7
|
+
"isolatedModules": true,
|
|
8
|
+
"sourceMap": true
|
|
9
|
+
},
|
|
10
|
+
"paths": {
|
|
11
|
+
"@/*": ["../src/*"]
|
|
12
|
+
},
|
|
13
|
+
"exclude": ["src/__test__/fixtures/**"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
noop,
|
|
3
|
+
mergeExtension,
|
|
4
|
+
toMessage,
|
|
5
|
+
createErrorDocument,
|
|
6
|
+
} from '../src/utils';
|
|
7
|
+
|
|
8
|
+
describe('test server utils', () => {
|
|
9
|
+
test('should get nothing from noop', async () => {
|
|
10
|
+
const rtn = noop();
|
|
11
|
+
expect(rtn).toBeUndefined();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('should merge extension', () => {
|
|
15
|
+
const middleware = ['foo', 'baz'];
|
|
16
|
+
const extension = mergeExtension(middleware);
|
|
17
|
+
expect(extension.middleware).toEqual(middleware);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('test some case by toMessage func', () => {
|
|
21
|
+
test('should get message from error like object', () => {
|
|
22
|
+
const error = new Error('some error happened');
|
|
23
|
+
const message = toMessage('error info', error);
|
|
24
|
+
expect(message).toBe('error info: some error happened');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should get message from error message', () => {
|
|
28
|
+
const errorMsg = 'some error happened';
|
|
29
|
+
const message = toMessage('error info', errorMsg);
|
|
30
|
+
expect(message).toBe('error info: some error happened');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should return document text', () => {
|
|
35
|
+
const doc = createErrorDocument(302, 'redirect');
|
|
36
|
+
expect(doc).toMatch('302');
|
|
37
|
+
expect(doc).toMatch('redirect');
|
|
38
|
+
expect(doc).toMatch('302: redirect');
|
|
39
|
+
});
|
|
40
|
+
});
|