@modern-js/runtime 1.3.4-alpha.0 → 1.4.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/CHANGELOG.md +77 -19
- package/dist/js/modern/cli/index.js +4 -4
- package/dist/js/modern/common.js +1 -0
- package/dist/js/modern/exports/model.js +2 -1
- package/dist/js/modern/exports/router.js +2 -1
- package/dist/js/modern/exports/server.js +0 -1
- package/dist/js/modern/exports/ssr.js +2 -1
- package/dist/js/modern/router/cli/index.js +106 -0
- package/dist/js/modern/router/index.js +2 -0
- package/dist/js/modern/router/runtime/DefaultNotFound.js +13 -0
- package/dist/js/modern/router/runtime/index.js +4 -0
- package/dist/js/modern/router/runtime/plugin.js +88 -0
- package/dist/js/modern/router/runtime/utils.js +108 -0
- package/dist/js/modern/ssr/cli/index.js +120 -0
- package/dist/js/modern/ssr/index.js +109 -0
- package/dist/js/modern/ssr/index.node.js +78 -0
- package/dist/js/modern/ssr/prefetch.js +58 -0
- package/dist/js/modern/ssr/react/index.js +2 -0
- package/dist/js/modern/ssr/react/nossr/index.js +13 -0
- package/dist/js/modern/ssr/react/prerender/index.js +104 -0
- package/dist/js/modern/ssr/react/prerender/type.js +0 -0
- package/dist/js/modern/ssr/react/prerender/util.js +99 -0
- package/dist/js/modern/ssr/serverRender/entry.js +179 -0
- package/dist/js/modern/ssr/serverRender/helmet.js +46 -0
- package/dist/js/modern/ssr/serverRender/index.js +29 -0
- package/dist/js/modern/ssr/serverRender/loadable.js +48 -0
- package/dist/js/modern/ssr/serverRender/measure.js +11 -0
- package/dist/js/modern/ssr/serverRender/reduce.js +7 -0
- package/dist/js/modern/ssr/serverRender/styledComponent.js +8 -0
- package/dist/js/modern/ssr/serverRender/template.js +90 -0
- package/dist/js/modern/ssr/serverRender/type.js +8 -0
- package/dist/js/modern/ssr/utils.js +51 -0
- package/dist/js/modern/state/cli/index.js +110 -0
- package/dist/js/modern/state/index.js +2 -0
- package/dist/js/modern/state/plugins.js +7 -0
- package/dist/js/modern/state/runtime/index.js +4 -0
- package/dist/js/modern/state/runtime/plugin.js +71 -0
- package/dist/js/modern/state/types.js +1 -0
- package/dist/js/node/cli/index.js +5 -5
- package/dist/js/node/common.js +10 -0
- package/dist/js/node/exports/model.js +19 -5
- package/dist/js/node/exports/router.js +19 -5
- package/dist/js/node/exports/server.js +0 -17
- package/dist/js/node/exports/ssr.js +19 -5
- package/dist/js/node/router/cli/index.js +122 -0
- package/dist/js/node/router/index.js +30 -0
- package/dist/js/node/router/runtime/DefaultNotFound.js +26 -0
- package/dist/js/node/router/runtime/index.js +39 -0
- package/dist/js/node/router/runtime/plugin.js +111 -0
- package/dist/js/node/router/runtime/utils.js +128 -0
- package/dist/js/node/ssr/cli/index.js +136 -0
- package/dist/js/node/ssr/index.js +138 -0
- package/dist/js/node/ssr/index.node.js +105 -0
- package/dist/js/node/ssr/prefetch.js +75 -0
- package/dist/js/node/ssr/react/index.js +21 -0
- package/dist/js/node/ssr/react/nossr/index.js +28 -0
- package/dist/js/node/ssr/react/prerender/index.js +121 -0
- package/dist/js/node/ssr/react/prerender/type.js +0 -0
- package/dist/js/node/ssr/react/prerender/util.js +119 -0
- package/dist/js/node/ssr/serverRender/entry.js +208 -0
- package/dist/js/node/ssr/serverRender/helmet.js +52 -0
- package/dist/js/node/ssr/serverRender/index.js +46 -0
- package/dist/js/node/ssr/serverRender/loadable.js +60 -0
- package/dist/js/node/ssr/serverRender/measure.js +20 -0
- package/dist/js/node/ssr/serverRender/reduce.js +14 -0
- package/dist/js/node/ssr/serverRender/styledComponent.js +18 -0
- package/dist/js/node/ssr/serverRender/template.js +103 -0
- package/dist/js/node/ssr/serverRender/type.js +15 -0
- package/dist/js/node/ssr/utils.js +65 -0
- package/dist/js/node/state/cli/index.js +127 -0
- package/dist/js/node/state/index.js +30 -0
- package/dist/js/node/state/plugins.js +35 -0
- package/dist/js/node/state/runtime/index.js +61 -0
- package/dist/js/node/state/runtime/plugin.js +101 -0
- package/dist/js/node/state/types.js +5 -0
- package/dist/js/treeshaking/cli/index.js +4 -4
- package/dist/js/treeshaking/common.js +3 -0
- package/dist/js/treeshaking/exports/model.js +2 -1
- package/dist/js/treeshaking/exports/router.js +2 -1
- package/dist/js/treeshaking/exports/server.js +0 -1
- package/dist/js/treeshaking/exports/ssr.js +2 -1
- package/dist/js/treeshaking/router/cli/index.js +100 -0
- package/dist/js/treeshaking/router/index.js +2 -0
- package/dist/js/treeshaking/router/runtime/DefaultNotFound.js +15 -0
- package/dist/js/treeshaking/router/runtime/index.js +4 -0
- package/dist/js/treeshaking/router/runtime/plugin.js +89 -0
- package/dist/js/treeshaking/router/runtime/utils.js +106 -0
- package/dist/js/treeshaking/ssr/cli/index.js +113 -0
- package/dist/js/treeshaking/ssr/index.js +129 -0
- package/dist/js/treeshaking/ssr/index.node.js +100 -0
- package/dist/js/treeshaking/ssr/prefetch.js +97 -0
- package/dist/js/treeshaking/ssr/react/index.js +2 -0
- package/dist/js/treeshaking/ssr/react/nossr/index.js +16 -0
- package/dist/js/treeshaking/ssr/react/prerender/index.js +119 -0
- package/dist/js/treeshaking/ssr/react/prerender/type.js +0 -0
- package/dist/js/treeshaking/ssr/react/prerender/util.js +115 -0
- package/dist/js/treeshaking/ssr/serverRender/entry.js +267 -0
- package/dist/js/treeshaking/ssr/serverRender/helmet.js +37 -0
- package/dist/js/treeshaking/ssr/serverRender/index.js +69 -0
- package/dist/js/treeshaking/ssr/serverRender/loadable.js +59 -0
- package/dist/js/treeshaking/ssr/serverRender/measure.js +17 -0
- package/dist/js/treeshaking/ssr/serverRender/reduce.js +11 -0
- package/dist/js/treeshaking/ssr/serverRender/styledComponent.js +8 -0
- package/dist/js/treeshaking/ssr/serverRender/template.js +111 -0
- package/dist/js/treeshaking/ssr/serverRender/type.js +8 -0
- package/dist/js/treeshaking/ssr/utils.js +53 -0
- package/dist/js/treeshaking/state/cli/index.js +100 -0
- package/dist/js/treeshaking/state/index.js +2 -0
- package/dist/js/treeshaking/state/plugins.js +13 -0
- package/dist/js/treeshaking/state/runtime/index.js +4 -0
- package/dist/js/treeshaking/state/runtime/plugin.js +63 -0
- package/dist/js/treeshaking/state/types.js +1 -0
- package/dist/types/common.d.ts +1 -0
- package/dist/types/exports/model.d.ts +2 -1
- package/dist/types/exports/router.d.ts +2 -1
- package/dist/types/exports/server.d.ts +0 -1
- package/dist/types/exports/ssr.d.ts +2 -1
- package/dist/types/index.d.ts +8 -2
- package/dist/types/router/cli/index.d.ts +5 -0
- package/dist/types/router/index.d.ts +2 -0
- package/dist/types/router/runtime/DefaultNotFound.d.ts +2 -0
- package/dist/types/router/runtime/index.d.ts +6 -0
- package/dist/types/router/runtime/plugin.d.ts +51 -0
- package/dist/types/router/runtime/utils.d.ts +6 -0
- package/dist/types/ssr/cli/index.d.ts +5 -0
- package/dist/types/ssr/index.d.ts +18 -0
- package/dist/types/ssr/index.node.d.ts +4 -0
- package/dist/types/ssr/prefetch.d.ts +13 -0
- package/dist/types/ssr/react/index.d.ts +2 -0
- package/dist/types/ssr/react/nossr/index.d.ts +2 -0
- package/dist/types/ssr/react/prerender/index.d.ts +1 -0
- package/dist/types/ssr/react/prerender/type.d.ts +29 -0
- package/dist/types/ssr/react/prerender/util.d.ts +6 -0
- package/dist/types/ssr/serverRender/entry.d.ts +20 -0
- package/dist/types/ssr/serverRender/helmet.d.ts +2 -0
- package/dist/types/ssr/serverRender/index.d.ts +8 -0
- package/dist/types/ssr/serverRender/loadable.d.ts +2 -0
- package/dist/types/ssr/serverRender/measure.d.ts +1 -0
- package/dist/types/ssr/serverRender/reduce.d.ts +3 -0
- package/dist/types/ssr/serverRender/styledComponent.d.ts +2 -0
- package/dist/types/ssr/serverRender/template.d.ts +14 -0
- package/dist/types/ssr/serverRender/type.d.ts +32 -0
- package/dist/types/ssr/utils.d.ts +8 -0
- package/dist/types/state/cli/index.d.ts +5 -0
- package/dist/types/state/index.d.ts +2 -0
- package/dist/types/state/plugins.d.ts +4 -0
- package/dist/types/state/runtime/index.d.ts +4 -0
- package/dist/types/state/runtime/plugin.d.ts +17 -0
- package/dist/types/state/types.d.ts +17 -0
- package/package.json +37 -20
- package/types/model.d.ts +1 -1
- package/types/state.d.ts +4 -0
- package/dist/js/modern/exports/request.js +0 -1
- package/dist/js/node/exports/request.js +0 -13
- package/dist/js/treeshaking/exports/request.js +0 -1
- package/dist/types/exports/request.d.ts +0 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
+
|
|
3
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
+
|
|
5
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
|
|
7
|
+
import ReactDOM from 'react-dom';
|
|
8
|
+
import { loadableReady } from '@loadable/component';
|
|
9
|
+
import { RenderLevel } from "./serverRender/type";
|
|
10
|
+
import { formatClient, mockResponse } from "./utils";
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
|
|
13
|
+
const ssr = () => ({
|
|
14
|
+
name: '@modern-js/plugin-ssr',
|
|
15
|
+
setup: () => {
|
|
16
|
+
const mockResp = mockResponse();
|
|
17
|
+
return {
|
|
18
|
+
client: async ({
|
|
19
|
+
App,
|
|
20
|
+
context,
|
|
21
|
+
rootElement
|
|
22
|
+
}) => {
|
|
23
|
+
var _window, _window$_SSR_DATA;
|
|
24
|
+
|
|
25
|
+
const renderLevel = (_window = window) === null || _window === void 0 ? void 0 : (_window$_SSR_DATA = _window._SSR_DATA) === null || _window$_SSR_DATA === void 0 ? void 0 : _window$_SSR_DATA.renderLevel;
|
|
26
|
+
|
|
27
|
+
if (renderLevel === RenderLevel.CLIENT_RENDER) {
|
|
28
|
+
var _prefetch, _ref;
|
|
29
|
+
|
|
30
|
+
await (App === null || App === void 0 ? void 0 : (_prefetch = (_ref = App).prefetch) === null || _prefetch === void 0 ? void 0 : _prefetch.call(_ref, context));
|
|
31
|
+
ReactDOM.render( /*#__PURE__*/_jsx(App, {
|
|
32
|
+
context: context
|
|
33
|
+
}), rootElement);
|
|
34
|
+
} else if (renderLevel === RenderLevel.SERVER_RENDER) {
|
|
35
|
+
loadableReady(() => {
|
|
36
|
+
const hydrateContext = _objectSpread(_objectSpread({}, context), {}, {
|
|
37
|
+
_hydration: true
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
ReactDOM.hydrate( /*#__PURE__*/_jsx(App, {
|
|
41
|
+
context: hydrateContext
|
|
42
|
+
}), rootElement, () => {
|
|
43
|
+
// won't cause component re-render because context's reference identity doesn't change
|
|
44
|
+
delete hydrateContext._hydration;
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
// unknown renderlevel or renderlevel is server prefetch.
|
|
49
|
+
ReactDOM.render( /*#__PURE__*/_jsx(App, {
|
|
50
|
+
context: context
|
|
51
|
+
}), rootElement);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
init({
|
|
56
|
+
context
|
|
57
|
+
}, next) {
|
|
58
|
+
var _window2, _window2$_SSR_DATA, _window2$_SSR_DATA$co;
|
|
59
|
+
|
|
60
|
+
const request = (_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$_SSR_DATA = _window2._SSR_DATA) === null || _window2$_SSR_DATA === void 0 ? void 0 : (_window2$_SSR_DATA$co = _window2$_SSR_DATA.context) === null || _window2$_SSR_DATA$co === void 0 ? void 0 : _window2$_SSR_DATA$co.request;
|
|
61
|
+
|
|
62
|
+
if (!request) {
|
|
63
|
+
return next({
|
|
64
|
+
context
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
context.ssrContext.response = mockResp;
|
|
69
|
+
context.ssrContext.request = formatClient(request);
|
|
70
|
+
return next({
|
|
71
|
+
context
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
pickContext: ({
|
|
76
|
+
context,
|
|
77
|
+
pickedContext
|
|
78
|
+
}, next) => {
|
|
79
|
+
var _window3, _window3$_SSR_DATA, _window3$_SSR_DATA$co;
|
|
80
|
+
|
|
81
|
+
const request = (_window3 = window) === null || _window3 === void 0 ? void 0 : (_window3$_SSR_DATA = _window3._SSR_DATA) === null || _window3$_SSR_DATA === void 0 ? void 0 : (_window3$_SSR_DATA$co = _window3$_SSR_DATA.context) === null || _window3$_SSR_DATA$co === void 0 ? void 0 : _window3$_SSR_DATA$co.request;
|
|
82
|
+
const {
|
|
83
|
+
initialData
|
|
84
|
+
} = context;
|
|
85
|
+
|
|
86
|
+
if (!request) {
|
|
87
|
+
return next({
|
|
88
|
+
context,
|
|
89
|
+
pickedContext: _objectSpread(_objectSpread({}, pickedContext), {}, {
|
|
90
|
+
initialData
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return next({
|
|
96
|
+
context,
|
|
97
|
+
pickedContext: _objectSpread(_objectSpread({}, pickedContext), {}, {
|
|
98
|
+
initialData,
|
|
99
|
+
request,
|
|
100
|
+
response: mockResp
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export default ssr;
|
|
109
|
+
export * from "./react";
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
+
|
|
3
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
+
|
|
5
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
|
|
7
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
8
|
+
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { registerPrefetch } from '@modern-js/runtime-core';
|
|
12
|
+
import { isBrowser } from "../common";
|
|
13
|
+
import prefetch from "./prefetch";
|
|
14
|
+
import { formatServer } from "./utils";
|
|
15
|
+
const registeredApps = new WeakSet();
|
|
16
|
+
|
|
17
|
+
const plugin = () => ({
|
|
18
|
+
name: '@modern-js/plugin-ssr',
|
|
19
|
+
setup: () => {
|
|
20
|
+
return {
|
|
21
|
+
server: async ({
|
|
22
|
+
App,
|
|
23
|
+
context
|
|
24
|
+
}) => {
|
|
25
|
+
if (!registeredApps.has(App)) {
|
|
26
|
+
registerPrefetch(App, _context => prefetch(App, _context));
|
|
27
|
+
registeredApps.add(App);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!isBrowser()) {
|
|
31
|
+
const html = await require("./serverRender").render(context, (context === null || context === void 0 ? void 0 : context.ssrContext.distDir) || path.join(process.cwd(), 'dist'), App);
|
|
32
|
+
return html;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
init({
|
|
39
|
+
context
|
|
40
|
+
}, next) {
|
|
41
|
+
const {
|
|
42
|
+
request
|
|
43
|
+
} = context.ssrContext;
|
|
44
|
+
context.ssrContext.request = formatServer(request);
|
|
45
|
+
return next({
|
|
46
|
+
context
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
pickContext: ({
|
|
51
|
+
context,
|
|
52
|
+
pickedContext
|
|
53
|
+
}, next) => {
|
|
54
|
+
const {
|
|
55
|
+
request,
|
|
56
|
+
response
|
|
57
|
+
} = context === null || context === void 0 ? void 0 : context.ssrContext;
|
|
58
|
+
const {
|
|
59
|
+
initialData
|
|
60
|
+
} = context;
|
|
61
|
+
return next({
|
|
62
|
+
context,
|
|
63
|
+
pickedContext: _objectSpread(_objectSpread({}, pickedContext), {}, {
|
|
64
|
+
initialData,
|
|
65
|
+
request,
|
|
66
|
+
response
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export default plugin;
|
|
75
|
+
export * from "./react";
|
|
76
|
+
/* eslint-enable @typescript-eslint/no-require-imports */
|
|
77
|
+
|
|
78
|
+
/* eslint-enable @typescript-eslint/no-var-requires */
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
4
|
+
import { run } from '@modern-js/utils/ssr';
|
|
5
|
+
import { LOADABLE_STATS_FILE } from '@modern-js/utils/constants';
|
|
6
|
+
import { ChunkExtractor } from '@loadable/server'; // todo: SSRContext
|
|
7
|
+
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
|
|
10
|
+
const prefetch = async (App, context) => run(context.ssrContext.request.headers, async () => {
|
|
11
|
+
var _context$store;
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
ssrContext
|
|
15
|
+
} = context;
|
|
16
|
+
const loadablefile = path.resolve(ssrContext.distDir, LOADABLE_STATS_FILE);
|
|
17
|
+
|
|
18
|
+
if (fs.existsSync(loadablefile)) {
|
|
19
|
+
const extractor = new ChunkExtractor({
|
|
20
|
+
statsFile: path.resolve(ssrContext.distDir, LOADABLE_STATS_FILE),
|
|
21
|
+
entrypoints: [ssrContext.entryName].filter(Boolean)
|
|
22
|
+
});
|
|
23
|
+
renderToStaticMarkup(extractor.collectChunks( /*#__PURE__*/_jsx(App, {
|
|
24
|
+
context: context
|
|
25
|
+
})));
|
|
26
|
+
} else {
|
|
27
|
+
renderToStaticMarkup( /*#__PURE__*/_jsx(App, {
|
|
28
|
+
context: context
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!context.loaderManager.hasPendingLoaders()) {
|
|
33
|
+
return {
|
|
34
|
+
initialData: context.initialData,
|
|
35
|
+
i18nData: context.__i18nData__
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const loadersData = await context.loaderManager.awaitPendingLoaders();
|
|
40
|
+
Object.keys(loadersData).forEach(id => {
|
|
41
|
+
const data = loadersData[id];
|
|
42
|
+
|
|
43
|
+
if (data._error) {
|
|
44
|
+
ssrContext.logger.error('App Prefetch Loader', data._error);
|
|
45
|
+
ssrContext.metrics.emitCounter('app.prefetch.loader.error', 1);
|
|
46
|
+
delete data._error;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return {
|
|
50
|
+
loadersData,
|
|
51
|
+
initialData: context.initialData,
|
|
52
|
+
i18nData: context.__i18nData__,
|
|
53
|
+
// todo: move to plugin state
|
|
54
|
+
storeState: context === null || context === void 0 ? void 0 : (_context$store = context.store) === null || _context$store === void 0 ? void 0 : _context$store.getState()
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export default prefetch;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
let csr = false;
|
|
3
|
+
export const NoSSR = props => {
|
|
4
|
+
const [isMounted, setMounted] = useState(csr);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
csr = true;
|
|
7
|
+
setMounted(true);
|
|
8
|
+
});
|
|
9
|
+
const {
|
|
10
|
+
children
|
|
11
|
+
} = props;
|
|
12
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, isMounted ? children : null);
|
|
13
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
2
|
+
|
|
3
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
4
|
+
|
|
5
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
6
|
+
|
|
7
|
+
import withSideEffect from 'react-side-effect';
|
|
8
|
+
import React, { createElement } from 'react';
|
|
9
|
+
import { getOutermostProperty, aggKeysFromPropsList, exist, aggMatchesFromPropsList } from "./util";
|
|
10
|
+
const PROP_NAMES = {
|
|
11
|
+
INTERVAL: 'interval',
|
|
12
|
+
STALE_LIMIT: 'staleLimit',
|
|
13
|
+
LEVEL: 'level',
|
|
14
|
+
INCLUDES: 'includes',
|
|
15
|
+
EXCLUDES: 'excludes',
|
|
16
|
+
FALLBACK: 'fallback',
|
|
17
|
+
MATCHES: 'matches'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const handleClientStateChange = () => {// not used
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const mapStateOnServer = reduceProps => {
|
|
24
|
+
const defaultProps = {
|
|
25
|
+
interval: 10,
|
|
26
|
+
staleLimit: false,
|
|
27
|
+
level: 0,
|
|
28
|
+
includes: null,
|
|
29
|
+
excludes: null,
|
|
30
|
+
fallback: false,
|
|
31
|
+
matches: null
|
|
32
|
+
};
|
|
33
|
+
return Object.keys(defaultProps).reduce((props, key) => {
|
|
34
|
+
const propKey = key;
|
|
35
|
+
const reduceProp = reduceProps[propKey];
|
|
36
|
+
let nextProps = props;
|
|
37
|
+
|
|
38
|
+
if (exist(reduceProp)) {
|
|
39
|
+
nextProps = _objectSpread(_objectSpread({}, props), {}, {
|
|
40
|
+
[propKey]: reduceProp
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return nextProps;
|
|
45
|
+
}, defaultProps);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const reducePropsToState = propsList => {
|
|
49
|
+
const reduceProps = {
|
|
50
|
+
interval: getOutermostProperty(propsList, PROP_NAMES.INTERVAL),
|
|
51
|
+
staleLimit: getOutermostProperty(propsList, PROP_NAMES.STALE_LIMIT),
|
|
52
|
+
level: getOutermostProperty(propsList, PROP_NAMES.LEVEL),
|
|
53
|
+
includes: aggKeysFromPropsList(propsList, PROP_NAMES.INCLUDES),
|
|
54
|
+
excludes: aggKeysFromPropsList(propsList, PROP_NAMES.EXCLUDES),
|
|
55
|
+
fallback: getOutermostProperty(propsList, PROP_NAMES.FALLBACK),
|
|
56
|
+
matches: aggMatchesFromPropsList(propsList, PROP_NAMES.MATCHES)
|
|
57
|
+
};
|
|
58
|
+
return reduceProps;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function factory(Component) {
|
|
62
|
+
class Spr extends React.Component {
|
|
63
|
+
static set canUseDOM(canUseDOM) {
|
|
64
|
+
Component.canUseDOM = canUseDOM;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static get canUseDOM() {
|
|
68
|
+
return Component.canUseDOM;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
verify() {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
render() {
|
|
76
|
+
const newProps = _objectSpread({}, this.props);
|
|
77
|
+
|
|
78
|
+
const validate = this.verify();
|
|
79
|
+
|
|
80
|
+
if (!validate) {
|
|
81
|
+
throw new Error('invalid props, check usage');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return /*#__PURE__*/createElement(Component, _objectSpread({}, newProps));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
_defineProperty(Spr, "peek", Component.peek);
|
|
90
|
+
|
|
91
|
+
_defineProperty(Spr, "rewind", Component.rewind);
|
|
92
|
+
|
|
93
|
+
_defineProperty(Spr, "config", () => {
|
|
94
|
+
const mappedState = Component.rewind();
|
|
95
|
+
return mappedState;
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return Spr;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const NullComponent = () => null;
|
|
102
|
+
|
|
103
|
+
const SprSideEffects = withSideEffect(reducePropsToState, handleClientStateChange, mapStateOnServer)(NullComponent);
|
|
104
|
+
export const PreRender = factory(SprSideEffects);
|
|
File without changes
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const REQUEST_META = ['header', 'query'];
|
|
2
|
+
export const getInnermostProperty = function getInnermostProperty(propsList, propName) {
|
|
3
|
+
for (let i = propsList.length - 1; i >= 0; i--) {
|
|
4
|
+
const props = propsList[i];
|
|
5
|
+
|
|
6
|
+
if (props.hasOwnProperty(propName)) {
|
|
7
|
+
return props[propName];
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return null;
|
|
12
|
+
};
|
|
13
|
+
export const getOutermostProperty = function getOutermostProperty(propsList, propName) {
|
|
14
|
+
for (const props of propsList) {
|
|
15
|
+
if (props.hasOwnProperty(propName)) {
|
|
16
|
+
return props[propName];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
export const aggKeysFromPropsList = function aggKeysFromPropsList(propsList, propName) {
|
|
23
|
+
const initResult = REQUEST_META.reduce((result, next) => {
|
|
24
|
+
const key = next;
|
|
25
|
+
result[key] = [];
|
|
26
|
+
return result;
|
|
27
|
+
}, {});
|
|
28
|
+
const res = propsList.filter(props => usefulObject(props[propName])).reduce((result, next) => {
|
|
29
|
+
REQUEST_META.forEach(key => {
|
|
30
|
+
const prop = next[propName];
|
|
31
|
+
|
|
32
|
+
if (prop !== null && prop !== void 0 && prop.hasOwnProperty(key) && usefulArray(prop[key])) {
|
|
33
|
+
result[key] = unique(result[key].concat(prop[key]));
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return result;
|
|
37
|
+
}, initResult);
|
|
38
|
+
return REQUEST_META.reduce((result, next) => {
|
|
39
|
+
var _result$key;
|
|
40
|
+
|
|
41
|
+
const key = next;
|
|
42
|
+
|
|
43
|
+
if (result[key] && ((_result$key = result[key]) === null || _result$key === void 0 ? void 0 : _result$key.length) === 0) {
|
|
44
|
+
delete result[key];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result;
|
|
48
|
+
}, res);
|
|
49
|
+
};
|
|
50
|
+
export const aggMatchesFromPropsList = function aggMatchesFromPropsList(propsList, propName) {
|
|
51
|
+
const initResult = REQUEST_META.reduce((result, next) => {
|
|
52
|
+
const key = next;
|
|
53
|
+
result[key] = {};
|
|
54
|
+
return result;
|
|
55
|
+
}, {});
|
|
56
|
+
const res = propsList.filter(props => usefulObject(props[propName])).reduce((result, next) => {
|
|
57
|
+
REQUEST_META.forEach(key => {
|
|
58
|
+
const prop = next[propName]; // 这边目前是浅拷贝,越后渲染优先级越高
|
|
59
|
+
|
|
60
|
+
if (prop !== null && prop !== void 0 && prop.hasOwnProperty(key) && usefulObject(prop[key])) {
|
|
61
|
+
result[key] = Object.assign(result[key], prop[key]);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
}, initResult);
|
|
66
|
+
return REQUEST_META.reduce((result, next) => {
|
|
67
|
+
const key = next;
|
|
68
|
+
|
|
69
|
+
if (result[key] && Object.keys(result[key]).length === 0) {
|
|
70
|
+
delete result[key];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result;
|
|
74
|
+
}, res);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
function unique(arr) {
|
|
78
|
+
return Array.from(new Set(arr));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function usefulObject(target) {
|
|
82
|
+
if (!exist(target)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return target.constructor === Object && Object.keys(target).length > 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function usefulArray(target) {
|
|
90
|
+
if (!exist(target)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return Array.isArray(target) && target.length > 0;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function exist(target) {
|
|
98
|
+
return target != null;
|
|
99
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
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
|
+
import path from 'path';
|
|
4
|
+
import { LOADABLE_STATS_FILE } from '@modern-js/utils/constants';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import ReactDomServer from 'react-dom/server';
|
|
7
|
+
import serialize from 'serialize-javascript';
|
|
8
|
+
import ReactHelmet from 'react-helmet';
|
|
9
|
+
import { toFragments } from "./template";
|
|
10
|
+
import { RenderLevel } from "./type";
|
|
11
|
+
import helmetReplace from "./helmet";
|
|
12
|
+
import { reduce } from "./reduce";
|
|
13
|
+
import * as loadableRenderer from "./loadable";
|
|
14
|
+
import * as styledComponentRenderer from "./styledComponent";
|
|
15
|
+
import { time } from "./measure";
|
|
16
|
+
|
|
17
|
+
const buildTemplateData = (context, data, renderLevel) => {
|
|
18
|
+
const {
|
|
19
|
+
request
|
|
20
|
+
} = context;
|
|
21
|
+
return {
|
|
22
|
+
data,
|
|
23
|
+
context: {
|
|
24
|
+
request: {
|
|
25
|
+
params: request.params,
|
|
26
|
+
query: request.query,
|
|
27
|
+
pathname: request.pathname,
|
|
28
|
+
host: request.host,
|
|
29
|
+
url: request.url,
|
|
30
|
+
headers: request.headers,
|
|
31
|
+
cookieMap: request.cookieMap
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
renderLevel
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default class Entry {
|
|
39
|
+
constructor(options) {
|
|
40
|
+
_defineProperty(this, "entryName", void 0);
|
|
41
|
+
|
|
42
|
+
_defineProperty(this, "result", void 0);
|
|
43
|
+
|
|
44
|
+
_defineProperty(this, "metrics", void 0);
|
|
45
|
+
|
|
46
|
+
_defineProperty(this, "logger", void 0);
|
|
47
|
+
|
|
48
|
+
_defineProperty(this, "App", void 0);
|
|
49
|
+
|
|
50
|
+
_defineProperty(this, "fragments", void 0);
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
ctx
|
|
54
|
+
} = options;
|
|
55
|
+
const {
|
|
56
|
+
entryName,
|
|
57
|
+
template: templateHTML
|
|
58
|
+
} = ctx;
|
|
59
|
+
this.fragments = toFragments(templateHTML);
|
|
60
|
+
this.entryName = entryName;
|
|
61
|
+
this.App = options.App;
|
|
62
|
+
this.metrics = ctx.metrics;
|
|
63
|
+
this.logger = ctx.logger;
|
|
64
|
+
this.result = {
|
|
65
|
+
renderLevel: RenderLevel.CLIENT_RENDER,
|
|
66
|
+
html: '',
|
|
67
|
+
chunksMap: {
|
|
68
|
+
js: '',
|
|
69
|
+
css: ''
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async renderToHtml(context) {
|
|
75
|
+
const {
|
|
76
|
+
ssrContext
|
|
77
|
+
} = context;
|
|
78
|
+
|
|
79
|
+
if (ssrContext.redirection.url) {
|
|
80
|
+
return '';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const prefetchData = await this.prefetch(context);
|
|
84
|
+
|
|
85
|
+
if (ssrContext.redirection.url) {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (this.result.renderLevel >= RenderLevel.SERVER_PREFETCH) {
|
|
90
|
+
this.result.html = this.renderToString(context);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (ssrContext.redirection.url) {
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let html = '';
|
|
98
|
+
const templateData = buildTemplateData(ssrContext, prefetchData, this.result.renderLevel);
|
|
99
|
+
const SSRData = this.getSSRDataScript(templateData);
|
|
100
|
+
|
|
101
|
+
for (const fragment of this.fragments) {
|
|
102
|
+
if (fragment.isVariable && fragment.content === 'SSRDataScript') {
|
|
103
|
+
html += fragment.getValue(SSRData);
|
|
104
|
+
} else {
|
|
105
|
+
html += fragment.getValue(this.result);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const helmetData = ReactHelmet.renderStatic();
|
|
110
|
+
return helmetData ? helmetReplace(html, helmetData) : html;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async prefetch(context) {
|
|
114
|
+
const {
|
|
115
|
+
App: {
|
|
116
|
+
prefetch
|
|
117
|
+
}
|
|
118
|
+
} = this;
|
|
119
|
+
let prefetchData;
|
|
120
|
+
const end = time();
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
prefetchData = prefetch ? await prefetch(context) : null;
|
|
124
|
+
this.result.renderLevel = RenderLevel.SERVER_PREFETCH;
|
|
125
|
+
const prefetchCost = end();
|
|
126
|
+
this.logger.debug(`App Prefetch cost = %d ms`, prefetchCost);
|
|
127
|
+
this.metrics.emitTimer('app.prefetch.cost', prefetchCost);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
this.result.renderLevel = RenderLevel.CLIENT_RENDER;
|
|
130
|
+
this.logger.error('App Prefetch Render', e);
|
|
131
|
+
this.metrics.emitCounter('app.prefetch.render.error', 1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return prefetchData || {};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
renderToString(context) {
|
|
138
|
+
let html = '';
|
|
139
|
+
const end = time();
|
|
140
|
+
const {
|
|
141
|
+
ssrContext
|
|
142
|
+
} = context;
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
const App = /*#__PURE__*/React.createElement(this.App, {
|
|
146
|
+
context: Object.assign(context, {
|
|
147
|
+
ssr: true
|
|
148
|
+
})
|
|
149
|
+
}); // Todo render Hook
|
|
150
|
+
|
|
151
|
+
const renderContext = {
|
|
152
|
+
loadableManifest: path.resolve(ssrContext.distDir, LOADABLE_STATS_FILE),
|
|
153
|
+
result: this.result,
|
|
154
|
+
entryName: this.entryName
|
|
155
|
+
};
|
|
156
|
+
html = reduce(App, renderContext, [styledComponentRenderer.toHtml, loadableRenderer.toHtml, jsx => ReactDomServer.renderToString(jsx)]);
|
|
157
|
+
const cost = end();
|
|
158
|
+
this.logger.debug('App Render To HTML cost = %d ms', cost);
|
|
159
|
+
this.metrics.emitTimer('app.render.html.cost', cost);
|
|
160
|
+
this.result.renderLevel = RenderLevel.SERVER_RENDER;
|
|
161
|
+
} catch (e) {
|
|
162
|
+
this.logger.error('App Render To HTML', e);
|
|
163
|
+
this.metrics.emitCounter('app.render.html.error', 1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return html;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
getSSRDataScript(templateData) {
|
|
170
|
+
return {
|
|
171
|
+
SSRDataScript: `
|
|
172
|
+
<script>window._SSR_DATA = ${serialize(templateData, {
|
|
173
|
+
isJSON: true
|
|
174
|
+
})}</script>
|
|
175
|
+
`
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// 用于 react-helmet 正则替换
|
|
2
|
+
const RE_HTML_ATTR = /<html[^>]*>/;
|
|
3
|
+
const RE_BODY_ATTR = /<body[^>]*>/;
|
|
4
|
+
const RE_LAST_IN_HEAD = /<\/head>/;
|
|
5
|
+
const RE_TITLE = /<title[^>]*>([\s\S\n\r]*?)<\/title>/g;
|
|
6
|
+
const TEST_TITLE_CONTENT = /(?<=<title[^>]*>)([\s\S\n\r]*?)([.|\S])([\s\S\n\r]*?)(?=<\/title>)/g; // 通过 react-helmet 修改模板
|
|
7
|
+
|
|
8
|
+
export default function helmet(content, helmetData) {
|
|
9
|
+
let result = content;
|
|
10
|
+
const bodyAttributes = helmetData.bodyAttributes.toString();
|
|
11
|
+
|
|
12
|
+
if (bodyAttributes) {
|
|
13
|
+
result = result.replace(RE_BODY_ATTR, `<body ${bodyAttributes}>`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const htmlAttributes = helmetData.htmlAttributes.toString();
|
|
17
|
+
|
|
18
|
+
if (htmlAttributes) {
|
|
19
|
+
result = result.replace(RE_HTML_ATTR, `<html ${htmlAttributes}>`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const base = helmetData.base.toString();
|
|
23
|
+
const link = helmetData.link.toString();
|
|
24
|
+
const meta = helmetData.meta.toString();
|
|
25
|
+
const noscript = helmetData.noscript.toString();
|
|
26
|
+
const script = helmetData.script.toString();
|
|
27
|
+
const style = helmetData.style.toString();
|
|
28
|
+
const title = helmetData.title.toString(); // 如果模板中存在 title,且 helmetData title 有内容则做替换
|
|
29
|
+
|
|
30
|
+
const existTitle = RE_TITLE.test(content);
|
|
31
|
+
|
|
32
|
+
if (TEST_TITLE_CONTENT.test(title.trim()) && existTitle) {
|
|
33
|
+
result = result.replace(RE_TITLE, title);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result.replace(RE_LAST_IN_HEAD, `
|
|
37
|
+
${base}
|
|
38
|
+
${link}
|
|
39
|
+
${meta}
|
|
40
|
+
${noscript}
|
|
41
|
+
${script}
|
|
42
|
+
${style}
|
|
43
|
+
${existTitle ? '' : title}
|
|
44
|
+
</head>
|
|
45
|
+
`);
|
|
46
|
+
}
|