@modern-js/prod-server 1.21.5 → 2.0.0-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 +91 -10
- package/dist/js/modern/constants.js +0 -2
- package/dist/js/modern/index.js +0 -1
- package/dist/js/modern/libs/context/context.js +10 -56
- package/dist/js/modern/libs/hook-api/index.js +125 -0
- package/dist/js/modern/libs/hook-api/route.js +13 -36
- package/dist/js/modern/libs/hook-api/template.js +38 -15
- package/dist/js/modern/libs/loadConfig.js +3 -10
- package/dist/js/modern/libs/metrics.js +6 -6
- package/dist/js/modern/libs/proxy.js +7 -12
- package/dist/js/modern/libs/render/cache/__tests__/cache.fun.test.js +0 -1
- package/dist/js/modern/libs/render/cache/__tests__/cache.test.js +0 -9
- package/dist/js/modern/libs/render/cache/index.js +37 -28
- package/dist/js/modern/libs/render/cache/page-caches/lru.js +0 -10
- package/dist/js/modern/libs/render/cache/spr.js +12 -62
- package/dist/js/modern/libs/render/cache/util.js +0 -6
- package/dist/js/modern/libs/render/index.js +6 -11
- package/dist/js/modern/libs/render/measure.js +7 -10
- package/dist/js/modern/libs/render/modern/index.js +2 -13
- package/dist/js/modern/libs/render/reader.js +13 -24
- package/dist/js/modern/libs/render/ssr.js +24 -12
- package/dist/js/modern/libs/render/static.js +6 -9
- package/dist/js/modern/libs/render/type.js +0 -1
- package/dist/js/modern/libs/route/index.js +8 -19
- package/dist/js/modern/libs/route/matcher.js +21 -29
- package/dist/js/modern/libs/route/route.js +0 -13
- package/dist/js/modern/libs/serve-file.js +13 -6
- package/dist/js/modern/server/index.js +27 -43
- package/dist/js/modern/server/modern-server-split.js +5 -55
- package/dist/js/modern/server/modern-server.js +179 -250
- package/dist/js/modern/utils.js +2 -21
- package/dist/js/modern/worker-server.js +34 -0
- package/dist/js/node/constants.js +0 -2
- package/dist/js/node/index.js +0 -10
- package/dist/js/node/libs/context/context.js +10 -65
- package/dist/js/node/libs/context/index.js +0 -3
- package/dist/js/node/libs/hook-api/index.js +136 -0
- package/dist/js/node/libs/hook-api/route.js +13 -38
- package/dist/js/node/libs/hook-api/template.js +40 -18
- package/dist/js/node/libs/loadConfig.js +3 -22
- package/dist/js/node/libs/metrics.js +6 -6
- package/dist/js/node/libs/proxy.js +7 -17
- package/dist/js/node/libs/render/cache/__tests__/cache.fun.test.js +0 -5
- package/dist/js/node/libs/render/cache/__tests__/cache.test.js +0 -12
- package/dist/js/node/libs/render/cache/index.js +37 -33
- package/dist/js/node/libs/render/cache/page-caches/index.js +0 -2
- package/dist/js/node/libs/render/cache/page-caches/lru.js +0 -14
- package/dist/js/node/libs/render/cache/spr.js +12 -71
- package/dist/js/node/libs/render/cache/util.js +0 -18
- package/dist/js/node/libs/render/index.js +6 -26
- package/dist/js/node/libs/render/measure.js +5 -15
- package/dist/js/node/libs/render/modern/index.js +2 -20
- package/dist/js/node/libs/render/reader.js +12 -39
- package/dist/js/node/libs/render/ssr.js +23 -22
- package/dist/js/node/libs/render/static.js +6 -18
- package/dist/js/node/libs/render/type.js +0 -1
- package/dist/js/node/libs/route/index.js +8 -22
- package/dist/js/node/libs/route/matcher.js +18 -34
- package/dist/js/node/libs/route/route.js +0 -15
- package/dist/js/node/libs/serve-file.js +15 -12
- package/dist/js/node/server/index.js +26 -62
- package/dist/js/node/server/modern-server-split.js +5 -58
- package/dist/js/node/server/modern-server.js +178 -280
- package/dist/js/node/utils.js +3 -46
- package/dist/js/node/worker-server.js +41 -0
- package/dist/js/treeshaking/constants.js +28 -0
- package/dist/js/treeshaking/index.js +13 -0
- package/dist/js/treeshaking/libs/context/context.js +243 -0
- package/dist/js/treeshaking/libs/context/index.js +5 -0
- package/dist/js/treeshaking/libs/hook-api/index.js +157 -0
- package/dist/js/treeshaking/libs/hook-api/route.js +33 -0
- package/dist/js/treeshaking/libs/hook-api/template.js +91 -0
- package/dist/js/treeshaking/libs/loadConfig.js +39 -0
- package/dist/js/treeshaking/libs/metrics.js +12 -0
- package/dist/js/treeshaking/libs/proxy.js +80 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cache.fun.test.js +124 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cache.test.js +464 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/cacheable.js +53 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/error-configuration.js +35 -0
- package/dist/js/treeshaking/libs/render/cache/__tests__/matched-cache.js +121 -0
- package/dist/js/treeshaking/libs/render/cache/index.js +184 -0
- package/dist/js/treeshaking/libs/render/cache/page-caches/index.js +30 -0
- package/dist/js/treeshaking/libs/render/cache/page-caches/lru.js +46 -0
- package/dist/js/treeshaking/libs/render/cache/spr.js +362 -0
- package/dist/js/treeshaking/libs/render/cache/type.js +1 -0
- package/dist/js/treeshaking/libs/render/cache/util.js +101 -0
- package/dist/js/treeshaking/libs/render/index.js +100 -0
- package/dist/js/treeshaking/libs/render/measure.js +61 -0
- package/dist/js/treeshaking/libs/render/modern/browser-list.js +7 -0
- package/dist/js/treeshaking/libs/render/modern/index.js +39 -0
- package/dist/js/treeshaking/libs/render/reader.js +191 -0
- package/dist/js/treeshaking/libs/render/ssr.js +98 -0
- package/dist/js/treeshaking/libs/render/static.js +84 -0
- package/dist/js/treeshaking/libs/render/type.js +6 -0
- package/dist/js/treeshaking/libs/route/index.js +94 -0
- package/dist/js/treeshaking/libs/route/matcher.js +113 -0
- package/dist/js/treeshaking/libs/route/route.js +26 -0
- package/dist/js/treeshaking/libs/serve-file.js +75 -0
- package/dist/js/treeshaking/server/index.js +343 -0
- package/dist/js/treeshaking/server/modern-server-split.js +152 -0
- package/dist/js/treeshaking/server/modern-server.js +945 -0
- package/dist/js/treeshaking/type.js +1 -0
- package/dist/js/treeshaking/utils.js +87 -0
- package/dist/js/treeshaking/worker-server.js +56 -0
- package/dist/types/index.d.ts +0 -2
- package/dist/types/libs/context/context.d.ts +0 -3
- package/dist/types/libs/hook-api/index.d.ts +5 -0
- package/dist/types/libs/hook-api/route.d.ts +9 -14
- package/dist/types/libs/hook-api/template.d.ts +19 -9
- package/dist/types/libs/loadConfig.d.ts +0 -1
- package/dist/types/libs/render/cache/index.d.ts +4 -4
- package/dist/types/libs/render/cache/spr.d.ts +0 -2
- package/dist/types/libs/render/type.d.ts +3 -1
- package/dist/types/libs/serve-file.d.ts +2 -1
- package/dist/types/server/index.d.ts +2 -3
- package/dist/types/server/modern-server.d.ts +11 -11
- package/dist/types/type.d.ts +8 -10
- package/dist/types/utils.d.ts +0 -1
- package/dist/types/worker-server.d.ts +16 -0
- package/package.json +28 -35
|
@@ -1,9 +1,6 @@
|
|
|
1
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
2
|
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
3
|
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
4
|
import * as path from 'path';
|
|
8
5
|
import { compatRequire, fs, DEFAULT_SERVER_CONFIG } from '@modern-js/utils';
|
|
9
6
|
import mergeDeep from 'merge-deep';
|
|
@@ -15,34 +12,30 @@ export const requireConfig = serverConfigPath => {
|
|
|
15
12
|
if (fs.pathExistsSync(serverConfigPath)) {
|
|
16
13
|
return compatRequire(serverConfigPath);
|
|
17
14
|
}
|
|
18
|
-
|
|
19
15
|
return {};
|
|
20
16
|
};
|
|
17
|
+
|
|
21
18
|
/**
|
|
22
19
|
* 对配置进行合并,开发环境下,cliConfig 与 serverConfig 进行深合并
|
|
23
20
|
* 生产环境下,resolvedConfig 与 serverConfig 进行深合并
|
|
24
21
|
* resolvedConfigPath: 构建序列化后的 modern.config.js 文件路径
|
|
25
22
|
*/
|
|
26
|
-
|
|
27
23
|
export const loadConfig = ({
|
|
28
24
|
cliConfig,
|
|
29
25
|
serverConfig,
|
|
30
26
|
resolvedConfigPath
|
|
31
27
|
}) => {
|
|
32
28
|
let config = null;
|
|
33
|
-
|
|
34
29
|
if (process.env.NODE_ENV === 'production') {
|
|
35
|
-
const resolvedConfig = requireConfig(resolvedConfigPath);
|
|
36
|
-
|
|
30
|
+
const resolvedConfig = requireConfig(resolvedConfigPath);
|
|
31
|
+
// cli config has a higher priority,because it's an argument passed in.
|
|
37
32
|
config = mergeDeep(_objectSpread(_objectSpread({}, resolvedConfig), {}, {
|
|
38
33
|
plugins: [] // filter cli plugins
|
|
39
|
-
|
|
40
34
|
}), serverConfig, cliConfig);
|
|
41
35
|
} else {
|
|
42
36
|
config = mergeDeep(_objectSpread(_objectSpread({}, cliConfig), {}, {
|
|
43
37
|
plugins: []
|
|
44
38
|
}), serverConfig);
|
|
45
39
|
}
|
|
46
|
-
|
|
47
40
|
return config;
|
|
48
41
|
};
|
|
@@ -1,14 +1,10 @@
|
|
|
1
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
2
|
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
3
|
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
4
|
import { createProxyMiddleware } from 'http-proxy-middleware';
|
|
8
5
|
import { debug } from "../utils";
|
|
9
6
|
export function formatProxyOptions(proxyOptions) {
|
|
10
7
|
const formattedProxy = [];
|
|
11
|
-
|
|
12
8
|
if (!Array.isArray(proxyOptions)) {
|
|
13
9
|
if ('target' in proxyOptions) {
|
|
14
10
|
formattedProxy.push(proxyOptions);
|
|
@@ -28,29 +24,29 @@ export function formatProxyOptions(proxyOptions) {
|
|
|
28
24
|
} else {
|
|
29
25
|
formattedProxy.push(...proxyOptions);
|
|
30
26
|
}
|
|
31
|
-
|
|
32
27
|
return formattedProxy;
|
|
33
28
|
}
|
|
34
29
|
export const createProxyHandler = proxyOptions => {
|
|
35
30
|
debug('createProxyHandler', proxyOptions);
|
|
36
|
-
|
|
37
31
|
if (!proxyOptions) {
|
|
38
32
|
return null;
|
|
39
|
-
}
|
|
40
|
-
// or an object in the form of { source: ProxyDetail }
|
|
41
|
-
|
|
33
|
+
}
|
|
42
34
|
|
|
35
|
+
// If it is not an array, it may be an object that uses the context attribute
|
|
36
|
+
// or an object in the form of { source: ProxyDetail }
|
|
43
37
|
const formattedProxy = formatProxyOptions(proxyOptions);
|
|
44
38
|
const middlewares = formattedProxy.map(option => {
|
|
45
|
-
const middleware = createProxyMiddleware(option.context, option);
|
|
39
|
+
const middleware = createProxyMiddleware(option.context, option);
|
|
46
40
|
|
|
41
|
+
// eslint-disable-next-line consistent-return
|
|
47
42
|
return async (ctx, next) => {
|
|
48
43
|
const {
|
|
49
44
|
req,
|
|
50
45
|
res
|
|
51
46
|
} = ctx;
|
|
52
|
-
const bypassUrl = typeof option.bypass === 'function' ? option.bypass(req, res, option) : null;
|
|
47
|
+
const bypassUrl = typeof option.bypass === 'function' ? option.bypass(req, res, option) : null;
|
|
53
48
|
|
|
49
|
+
// only false, no true
|
|
54
50
|
if (typeof bypassUrl === 'boolean') {
|
|
55
51
|
ctx.status = 404;
|
|
56
52
|
return next();
|
|
@@ -58,7 +54,6 @@ export const createProxyHandler = proxyOptions => {
|
|
|
58
54
|
ctx.url = bypassUrl;
|
|
59
55
|
return next();
|
|
60
56
|
}
|
|
61
|
-
|
|
62
57
|
middleware(req, res, next);
|
|
63
58
|
};
|
|
64
59
|
});
|
|
@@ -18,7 +18,6 @@ describe('test spr util functions', () => {
|
|
|
18
18
|
});
|
|
19
19
|
it('should return function correctly', () => {
|
|
20
20
|
const urlParams = (() => new url.URLSearchParams())();
|
|
21
|
-
|
|
22
21
|
urlParams.set('name', 'modern');
|
|
23
22
|
const getParam = valueFactory(urlParams);
|
|
24
23
|
expect(getParam('name')).toBe('modern');
|
|
@@ -1,14 +1,10 @@
|
|
|
1
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
2
|
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
3
|
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
4
|
import { createCache, destroyCache } from "../spr";
|
|
8
5
|
import { errorConfiguration } from "./error-configuration";
|
|
9
6
|
import { cacheabelAry } from "./cacheable";
|
|
10
7
|
import { matchedCacheableAry } from "./matched-cache";
|
|
11
|
-
|
|
12
8
|
const createCacheConfig = (config = {}) => _objectSpread({
|
|
13
9
|
excludes: null,
|
|
14
10
|
includes: null,
|
|
@@ -18,7 +14,6 @@ const createCacheConfig = (config = {}) => _objectSpread({
|
|
|
18
14
|
fallback: false,
|
|
19
15
|
matches: null
|
|
20
16
|
}, config);
|
|
21
|
-
|
|
22
17
|
jest.setTimeout(60000);
|
|
23
18
|
describe('cache', () => {
|
|
24
19
|
it('should cache correctly', async () => {
|
|
@@ -55,7 +50,6 @@ describe('cache', () => {
|
|
|
55
50
|
destroyCache();
|
|
56
51
|
const cache = createCache();
|
|
57
52
|
const content = 'hello';
|
|
58
|
-
|
|
59
53
|
for (const config of errorConfiguration) {
|
|
60
54
|
const cacheConfig = createCacheConfig(config);
|
|
61
55
|
const tmpEntry = Math.random().toString();
|
|
@@ -126,7 +120,6 @@ describe('cache', () => {
|
|
|
126
120
|
it('should get cache correctly', async () => {
|
|
127
121
|
destroyCache();
|
|
128
122
|
const cache = createCache();
|
|
129
|
-
|
|
130
123
|
for (const cacheable of cacheabelAry) {
|
|
131
124
|
const context = {
|
|
132
125
|
entry: '',
|
|
@@ -143,7 +136,6 @@ describe('cache', () => {
|
|
|
143
136
|
it('should match cache correctly', async () => {
|
|
144
137
|
destroyCache();
|
|
145
138
|
const cache = createCache();
|
|
146
|
-
|
|
147
139
|
for (const cacheable of matchedCacheableAry) {
|
|
148
140
|
const [baseCacheable, matchOne, ...other] = cacheable;
|
|
149
141
|
const {
|
|
@@ -166,7 +158,6 @@ describe('cache', () => {
|
|
|
166
158
|
};
|
|
167
159
|
const cacheResult = await cache.get(matchContext);
|
|
168
160
|
expect(cacheResult === null || cacheResult === void 0 ? void 0 : cacheResult.content).toBe(content);
|
|
169
|
-
|
|
170
161
|
for (const notMatch of other) {
|
|
171
162
|
const notMatchContext = {
|
|
172
163
|
entry: '',
|
|
@@ -1,59 +1,70 @@
|
|
|
1
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
2
|
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
3
|
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
|
-
|
|
4
|
+
import { Transform } from 'stream';
|
|
7
5
|
import { ERROR_DIGEST } from "../../../constants";
|
|
8
6
|
import { createCache } from "./spr";
|
|
9
7
|
import { namespaceHash, withCoalescedInvoke } from "./util";
|
|
10
8
|
export default ((renderFn, ctx) => {
|
|
11
9
|
const sprCache = createCache();
|
|
12
|
-
|
|
13
10
|
const doRender = async context => {
|
|
14
11
|
const cacheContext = _objectSpread({
|
|
15
12
|
entry: context.entryName
|
|
16
13
|
}, context.request);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
const cacheFile = await sprCache.get(cacheContext);
|
|
15
|
+
async function afterRender(source, onAfterRender) {
|
|
16
|
+
// e.g. source is undefined when redirects occur during render
|
|
17
|
+
if (!source) {
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
if (typeof source === 'string') {
|
|
21
|
+
await onAfterRender(source);
|
|
22
|
+
return source;
|
|
23
|
+
} else {
|
|
24
|
+
let htmlForStream = '';
|
|
25
|
+
const cacheStream = new Transform({
|
|
26
|
+
write(chunk, _, callback) {
|
|
27
|
+
htmlForStream += chunk.toString();
|
|
28
|
+
this.push(chunk);
|
|
29
|
+
callback();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
cacheStream.on('close', () => onAfterRender(htmlForStream));
|
|
33
|
+
return source(cacheStream);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function saveHtmlIntoCache(html) {
|
|
22
37
|
const {
|
|
23
38
|
cacheConfig
|
|
24
39
|
} = context;
|
|
25
|
-
|
|
26
40
|
if (html && cacheConfig) {
|
|
27
41
|
await sprCache.set(cacheContext, html, cacheConfig);
|
|
28
42
|
}
|
|
29
|
-
|
|
30
|
-
return html;
|
|
31
43
|
}
|
|
32
44
|
|
|
33
|
-
|
|
45
|
+
// no cache, render sync
|
|
46
|
+
if (!cacheFile) {
|
|
47
|
+
const renderResult = await renderFn(context);
|
|
48
|
+
return afterRender(renderResult, saveHtmlIntoCache);
|
|
49
|
+
}
|
|
50
|
+
const cacheHash = cacheFile === null || cacheFile === void 0 ? void 0 : cacheFile.hash;
|
|
34
51
|
|
|
52
|
+
// completely expired
|
|
35
53
|
if (cacheFile.isGarbage) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
cacheConfig
|
|
39
|
-
} = context;
|
|
40
|
-
|
|
41
|
-
if (html && cacheConfig) {
|
|
42
|
-
await sprCache.set(cacheContext, html, cacheConfig);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return html;
|
|
54
|
+
const renderResult = await renderFn(context);
|
|
55
|
+
return afterRender(renderResult, saveHtmlIntoCache);
|
|
46
56
|
} else if (cacheFile.isStale) {
|
|
47
57
|
// if file is stale, request async
|
|
48
58
|
const render = withCoalescedInvoke(() => renderFn(context)).bind(null, namespaceHash('render', cacheFile.hash), []);
|
|
49
|
-
render().then(res => {
|
|
59
|
+
render().then(async res => {
|
|
50
60
|
if (res.value && res.isOrigin) {
|
|
51
61
|
const {
|
|
52
62
|
cacheConfig
|
|
53
63
|
} = context;
|
|
54
|
-
|
|
55
64
|
if (cacheConfig) {
|
|
56
|
-
|
|
65
|
+
afterRender(res.value, async html => {
|
|
66
|
+
sprCache.set(cacheContext, html, cacheConfig);
|
|
67
|
+
});
|
|
57
68
|
} else {
|
|
58
69
|
sprCache.del(cacheContext, cacheHash);
|
|
59
70
|
}
|
|
@@ -63,10 +74,8 @@ export default ((renderFn, ctx) => {
|
|
|
63
74
|
ctx.error(ERROR_DIGEST.ERENDER, e);
|
|
64
75
|
});
|
|
65
76
|
}
|
|
66
|
-
|
|
67
77
|
ctx.res.setHeader('x-modern-spr', '1');
|
|
68
78
|
return cacheFile.content;
|
|
69
79
|
};
|
|
70
|
-
|
|
71
80
|
return doRender;
|
|
72
81
|
});
|
|
@@ -1,39 +1,29 @@
|
|
|
1
1
|
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; }
|
|
2
|
-
|
|
3
2
|
import LRU from 'lru-cache';
|
|
4
3
|
export class LRUCaches {
|
|
5
4
|
constructor(options) {
|
|
6
5
|
_defineProperty(this, "caches", void 0);
|
|
7
|
-
|
|
8
6
|
_defineProperty(this, "max", void 0);
|
|
9
|
-
|
|
10
7
|
this.max = options.max;
|
|
11
8
|
this.caches = new LRU(this.max);
|
|
12
9
|
}
|
|
13
|
-
|
|
14
10
|
init() {
|
|
15
11
|
return Promise.resolve();
|
|
16
12
|
}
|
|
17
|
-
|
|
18
13
|
keys() {
|
|
19
14
|
return this.caches.keys();
|
|
20
15
|
}
|
|
21
|
-
|
|
22
16
|
get(key) {
|
|
23
17
|
return Promise.resolve(this.caches.get(key) || null);
|
|
24
18
|
}
|
|
25
|
-
|
|
26
19
|
peek(key) {
|
|
27
20
|
return this.caches.peek(key) || null;
|
|
28
21
|
}
|
|
29
|
-
|
|
30
22
|
set(key, cache) {
|
|
31
23
|
this.caches.set(key, cache);
|
|
32
24
|
return Promise.resolve();
|
|
33
25
|
}
|
|
34
|
-
|
|
35
26
|
del(key) {
|
|
36
27
|
this.caches.del(key);
|
|
37
28
|
}
|
|
38
|
-
|
|
39
29
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
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; }
|
|
2
|
-
|
|
3
2
|
/* eslint-disable @typescript-eslint/member-ordering */
|
|
4
|
-
|
|
5
3
|
/* eslint-disable no-lone-blocks */
|
|
6
4
|
import crypto from 'crypto';
|
|
7
5
|
import LRUCache from 'lru-cache';
|
|
@@ -14,82 +12,62 @@ const BASE_LEVEL = 0;
|
|
|
14
12
|
const QUERY_LEVEL = 1;
|
|
15
13
|
const HEADER_LEVEL = 2;
|
|
16
14
|
const QUERY_HEADER_LEVEL = 3;
|
|
17
|
-
|
|
18
15
|
class CacheManager {
|
|
19
16
|
constructor(cacheOptions) {
|
|
20
17
|
_defineProperty(this, "cache", void 0);
|
|
21
|
-
|
|
22
18
|
_defineProperty(this, "cacheOptions", void 0);
|
|
23
|
-
|
|
24
19
|
_defineProperty(this, "find", (() => {
|
|
25
20
|
{
|
|
26
21
|
// eslint-disable-next-line consistent-this,@typescript-eslint/no-this-alias
|
|
27
22
|
const _this = this;
|
|
28
|
-
|
|
29
23
|
return {
|
|
30
|
-
[fname(BASE_LEVEL)](context, cacheKey
|
|
24
|
+
[fname(BASE_LEVEL)](context, cacheKey
|
|
25
|
+
// data: CacheContent,
|
|
31
26
|
) {
|
|
32
27
|
return _this.md5(cacheKey);
|
|
33
28
|
},
|
|
34
|
-
|
|
35
29
|
[fname(QUERY_LEVEL)](context, cacheKey, data) {
|
|
36
30
|
const queryFactor = _this.queryFactor(context, data);
|
|
37
|
-
|
|
38
31
|
if (!queryFactor) {
|
|
39
32
|
return null;
|
|
40
33
|
}
|
|
41
|
-
|
|
42
34
|
return _this.md5(connectFactor(cacheKey, queryFactor));
|
|
43
35
|
},
|
|
44
|
-
|
|
45
36
|
[fname(HEADER_LEVEL)](context, cacheKey, data) {
|
|
46
37
|
const headerFactor = _this.headerFactor(context, data);
|
|
47
|
-
|
|
48
38
|
if (!headerFactor) {
|
|
49
39
|
return null;
|
|
50
40
|
}
|
|
51
|
-
|
|
52
41
|
return _this.md5(connectFactor(cacheKey, headerFactor));
|
|
53
42
|
},
|
|
54
|
-
|
|
55
43
|
[fname(QUERY_HEADER_LEVEL)](context, cacheKey, data) {
|
|
56
44
|
const queryFactor = _this.queryFactor(context, data);
|
|
57
|
-
|
|
58
45
|
const headerFactor = _this.headerFactor(context, data);
|
|
59
|
-
|
|
60
46
|
if (!queryFactor || !headerFactor) {
|
|
61
47
|
return null;
|
|
62
48
|
}
|
|
63
|
-
|
|
64
49
|
return _this.md5(connectFactor(cacheKey, headerFactor, queryFactor));
|
|
65
50
|
}
|
|
66
|
-
|
|
67
51
|
};
|
|
68
52
|
}
|
|
69
53
|
})());
|
|
70
|
-
|
|
71
54
|
this.cacheOptions = cacheOptions;
|
|
72
55
|
this.cache = new LRUCache({
|
|
73
56
|
max: Math.min(MAX_SIZE_EACH_CLUSTER, 600) * 1024 * 1024,
|
|
74
|
-
|
|
75
57
|
// 默认存 100M,最大 600M
|
|
76
58
|
length(n) {
|
|
77
59
|
const len = n.caches.keys().reduce((total, cur) => {
|
|
78
60
|
var _n$caches$peek;
|
|
79
|
-
|
|
80
61
|
return total + (((_n$caches$peek = n.caches.peek(cur)) === null || _n$caches$peek === void 0 ? void 0 : _n$caches$peek.size) || 0);
|
|
81
62
|
}, 1);
|
|
82
63
|
return len;
|
|
83
64
|
}
|
|
84
|
-
|
|
85
65
|
});
|
|
86
66
|
}
|
|
87
|
-
|
|
88
67
|
md5(content) {
|
|
89
68
|
const md5 = crypto.createHash('md5');
|
|
90
69
|
return md5.update(content).digest('hex');
|
|
91
70
|
}
|
|
92
|
-
|
|
93
71
|
generateRequestKey(context) {
|
|
94
72
|
const {
|
|
95
73
|
pathname,
|
|
@@ -97,81 +75,63 @@ class CacheManager {
|
|
|
97
75
|
} = context;
|
|
98
76
|
return this.md5(`${pathname}_${entry}`);
|
|
99
77
|
}
|
|
100
|
-
|
|
101
78
|
replaceValue(value, matcher) {
|
|
102
79
|
let final = value;
|
|
103
80
|
Object.keys(matcher).some(replacer => {
|
|
104
81
|
const reg = new RegExp(matcher[replacer]);
|
|
105
|
-
|
|
106
82
|
if (reg.test(value)) {
|
|
107
83
|
final = replacer;
|
|
108
84
|
return true;
|
|
109
85
|
}
|
|
110
|
-
|
|
111
86
|
return false;
|
|
112
87
|
});
|
|
113
88
|
return final;
|
|
114
89
|
}
|
|
115
|
-
|
|
116
90
|
factor(keys, obj, matches = {}) {
|
|
117
91
|
keys.sort();
|
|
118
92
|
const getValue = valueFactory(obj);
|
|
119
93
|
const factorAry = keys.reduce((ary, key) => {
|
|
120
94
|
let value = getValue(key) || '';
|
|
121
95
|
const matcher = matches[key];
|
|
122
|
-
|
|
123
96
|
if (matcher) {
|
|
124
97
|
value = this.replaceValue(value, matcher);
|
|
125
98
|
}
|
|
126
|
-
|
|
127
99
|
return ary.concat([key, value]);
|
|
128
100
|
}, []);
|
|
129
101
|
return factorAry.join(',');
|
|
130
102
|
}
|
|
131
|
-
|
|
132
103
|
queryFactor(context, data) {
|
|
133
104
|
var _data$includes, _data$matches;
|
|
134
|
-
|
|
135
105
|
const queryKeys = (_data$includes = data.includes) === null || _data$includes === void 0 ? void 0 : _data$includes.query;
|
|
136
106
|
const queryMatches = (_data$matches = data.matches) === null || _data$matches === void 0 ? void 0 : _data$matches.query;
|
|
137
|
-
|
|
138
107
|
if (!queryKeys || queryKeys.length === 0) {
|
|
139
108
|
return null;
|
|
140
109
|
}
|
|
141
|
-
|
|
142
110
|
const requestQuery = context.query;
|
|
143
111
|
const queryFactor = this.factor(queryKeys, requestQuery, queryMatches);
|
|
144
112
|
return queryFactor;
|
|
145
113
|
}
|
|
146
|
-
|
|
147
114
|
headerFactor(context, data) {
|
|
148
115
|
var _data$includes2, _data$matches2;
|
|
149
|
-
|
|
150
116
|
const headerKeys = (_data$includes2 = data.includes) === null || _data$includes2 === void 0 ? void 0 : _data$includes2.header;
|
|
151
117
|
const headerMatches = (_data$matches2 = data.matches) === null || _data$matches2 === void 0 ? void 0 : _data$matches2.header;
|
|
152
|
-
|
|
153
118
|
if (!headerKeys || headerKeys.length === 0) {
|
|
154
119
|
return null;
|
|
155
120
|
}
|
|
156
|
-
|
|
157
121
|
const requestHeader = context.headers;
|
|
158
122
|
const headerFactor = this.factor(headerKeys, requestHeader, headerMatches);
|
|
159
123
|
return headerFactor;
|
|
160
124
|
}
|
|
161
|
-
|
|
162
125
|
async best(context, cacheKey, data) {
|
|
163
126
|
const {
|
|
164
127
|
level
|
|
165
128
|
} = data;
|
|
166
129
|
const cacheHash = this.find[fname(level)](context, cacheKey, data);
|
|
167
|
-
|
|
168
130
|
if (!cacheHash) {
|
|
169
131
|
return null;
|
|
170
132
|
}
|
|
171
|
-
|
|
172
133
|
return data.caches.get(cacheHash);
|
|
173
134
|
}
|
|
174
|
-
|
|
175
135
|
createCacheContent(config, caches) {
|
|
176
136
|
return {
|
|
177
137
|
level: config.level,
|
|
@@ -182,21 +142,19 @@ class CacheManager {
|
|
|
182
142
|
caches
|
|
183
143
|
};
|
|
184
144
|
}
|
|
185
|
-
|
|
186
145
|
async get(context) {
|
|
187
146
|
const cacheKey = this.generateRequestKey(context);
|
|
188
|
-
const data = this.cache.get(cacheKey);
|
|
147
|
+
const data = this.cache.get(cacheKey);
|
|
189
148
|
|
|
149
|
+
// no cache key matched
|
|
190
150
|
if (!data) {
|
|
191
151
|
return null;
|
|
192
152
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
153
|
+
const dest = await this.best(context, cacheKey, data);
|
|
154
|
+
// no cache for current page with current config
|
|
196
155
|
if (!dest) {
|
|
197
156
|
return null;
|
|
198
157
|
}
|
|
199
|
-
|
|
200
158
|
const {
|
|
201
159
|
expireTime,
|
|
202
160
|
limitTime,
|
|
@@ -213,27 +171,24 @@ class CacheManager {
|
|
|
213
171
|
hash: cacheHash
|
|
214
172
|
};
|
|
215
173
|
}
|
|
216
|
-
|
|
217
174
|
async set(context, html, cacheConfig, sync = false) {
|
|
218
175
|
if (!cacheConfig) {
|
|
219
176
|
return false;
|
|
220
|
-
}
|
|
221
|
-
|
|
177
|
+
}
|
|
222
178
|
|
|
179
|
+
// each version with route is a separate cache
|
|
223
180
|
const cacheKey = this.generateRequestKey(context);
|
|
224
181
|
let data = this.cache.get(cacheKey);
|
|
225
|
-
|
|
226
182
|
if (!data) {
|
|
227
183
|
const caches = await createPageCaches(MAX_CACHE_EACH_REQ);
|
|
228
184
|
data = this.createCacheContent(cacheConfig, caches);
|
|
229
185
|
}
|
|
186
|
+
const cacheHash = this.find[fname(cacheConfig.level)](context, cacheKey, data);
|
|
230
187
|
|
|
231
|
-
|
|
232
|
-
|
|
188
|
+
// if cacheHash is null, maybe level not match meta key, do not cache
|
|
233
189
|
if (!cacheHash) {
|
|
234
190
|
return false;
|
|
235
191
|
}
|
|
236
|
-
|
|
237
192
|
const cacheSyncOrAsync = async () => {
|
|
238
193
|
const next = data;
|
|
239
194
|
const limit = cacheConfig.staleLimit;
|
|
@@ -248,27 +203,23 @@ class CacheManager {
|
|
|
248
203
|
});
|
|
249
204
|
this.cache.set(cacheKey, next);
|
|
250
205
|
return true;
|
|
251
|
-
};
|
|
252
|
-
|
|
206
|
+
};
|
|
253
207
|
|
|
208
|
+
// cache set is async, each hash is cached only once at the same time
|
|
254
209
|
const doCache = withCoalescedInvoke(cacheSyncOrAsync).bind(null, namespaceHash('stream', cacheHash), []);
|
|
255
210
|
return maybeSync(doCache)(sync);
|
|
256
211
|
}
|
|
257
|
-
|
|
258
212
|
async del(context, cacheHash) {
|
|
259
213
|
const cacheKey = this.generateRequestKey(context);
|
|
260
214
|
const data = this.cache.get(cacheKey);
|
|
261
215
|
data === null || data === void 0 ? void 0 : data.caches.del(cacheHash);
|
|
262
216
|
}
|
|
263
|
-
|
|
264
217
|
}
|
|
265
|
-
|
|
266
218
|
let manager;
|
|
267
219
|
export function createCache() {
|
|
268
220
|
if (manager) {
|
|
269
221
|
return manager;
|
|
270
222
|
}
|
|
271
|
-
|
|
272
223
|
manager = new CacheManager({
|
|
273
224
|
max: 0
|
|
274
225
|
});
|
|
@@ -278,5 +229,4 @@ export function destroyCache() {
|
|
|
278
229
|
manager = null;
|
|
279
230
|
}
|
|
280
231
|
/* eslint-enable no-lone-blocks */
|
|
281
|
-
|
|
282
232
|
/* eslint-enable @typescript-eslint/member-ordering */
|
|
@@ -16,11 +16,9 @@ export function valueFactory(obj) {
|
|
|
16
16
|
} else {
|
|
17
17
|
return function (key) {
|
|
18
18
|
const value = obj[key];
|
|
19
|
-
|
|
20
19
|
if (Array.isArray(value)) {
|
|
21
20
|
return value.join(',');
|
|
22
21
|
}
|
|
23
|
-
|
|
24
22
|
return value;
|
|
25
23
|
};
|
|
26
24
|
}
|
|
@@ -37,18 +35,15 @@ const globalInvokeCache = new Map();
|
|
|
37
35
|
export function withCoalescedInvoke(func) {
|
|
38
36
|
return async function (key, args) {
|
|
39
37
|
const entry = globalInvokeCache.get(key);
|
|
40
|
-
|
|
41
38
|
if (entry) {
|
|
42
39
|
return entry.then(res => ({
|
|
43
40
|
isOrigin: false,
|
|
44
41
|
value: res.value
|
|
45
42
|
}));
|
|
46
43
|
}
|
|
47
|
-
|
|
48
44
|
function __wrapper() {
|
|
49
45
|
return func(...args);
|
|
50
46
|
}
|
|
51
|
-
|
|
52
47
|
const future = __wrapper().then(res => {
|
|
53
48
|
globalInvokeCache.delete(key);
|
|
54
49
|
return {
|
|
@@ -59,7 +54,6 @@ export function withCoalescedInvoke(func) {
|
|
|
59
54
|
globalInvokeCache.delete(key);
|
|
60
55
|
throw err;
|
|
61
56
|
});
|
|
62
|
-
|
|
63
57
|
globalInvokeCache.set(key, future);
|
|
64
58
|
return future;
|
|
65
59
|
};
|