@shuvi/platform-web 0.0.1-rc.34 → 1.0.0-rc.2
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/esm/shared/appTypes.d.ts +15 -0
- package/esm/shared/appTypes.js +1 -0
- package/esm/shared/configTypes.d.ts +14 -0
- package/esm/shared/configTypes.js +1 -0
- package/esm/shared/index.d.ts +5 -0
- package/esm/shared/index.js +5 -0
- package/esm/shared/renderTypes.d.ts +44 -0
- package/esm/shared/renderTypes.js +1 -0
- package/esm/shared/routeTypes.d.ts +47 -0
- package/esm/shared/routeTypes.js +1 -0
- package/esm/shared/serverTypes.d.ts +6 -0
- package/esm/shared/serverTypes.js +1 -0
- package/esm/shuvi-app/app/client.d.ts +2 -0
- package/esm/shuvi-app/app/client.js +125 -0
- package/esm/shuvi-app/app/server.d.ts +2 -0
- package/esm/shuvi-app/app/server.js +67 -0
- package/{shuvi-app → esm/shuvi-app}/dev/webpackHotDevClient.d.ts +0 -0
- package/{shuvi-app → esm/shuvi-app}/dev/webpackHotDevClient.js +2 -1
- package/esm/shuvi-app/entry/client/app.d.ts +2 -0
- package/esm/shuvi-app/entry/client/app.js +57 -0
- package/esm/shuvi-app/entry/client/index.d.ts +2 -0
- package/esm/shuvi-app/entry/client/index.js +12 -0
- package/{shuvi-app → esm/shuvi-app}/entry/client/run.dev.d.ts +0 -0
- package/{shuvi-app → esm/shuvi-app}/entry/client/run.dev.js +2 -2
- package/{shuvi-app → esm/shuvi-app}/entry/client/run.prod.d.ts +0 -0
- package/esm/shuvi-app/entry/client/run.prod.js +3 -0
- package/{shuvi-app → esm/shuvi-app}/entry/client/setup-env.d.ts +1 -1
- package/esm/shuvi-app/entry/client/setup-env.js +17 -0
- package/esm/shuvi-app/entry/server/index.d.ts +6 -0
- package/esm/shuvi-app/entry/server/index.js +7 -0
- package/esm/shuvi-app/react/AppComponent.d.ts +4 -0
- package/esm/shuvi-app/react/AppComponent.jsx +6 -0
- package/esm/shuvi-app/react/AppContainer.d.ts +6 -0
- package/esm/shuvi-app/react/AppContainer.jsx +23 -0
- package/esm/shuvi-app/react/Error.d.ts +5 -0
- package/esm/shuvi-app/react/Error.jsx +38 -0
- package/esm/shuvi-app/react/ErrorBoundary.d.ts +16 -0
- package/esm/shuvi-app/react/ErrorBoundary.jsx +25 -0
- package/esm/shuvi-app/react/ErrorPage.d.ts +5 -0
- package/esm/shuvi-app/react/ErrorPage.jsx +7 -0
- package/esm/shuvi-app/react/Link.d.ts +7 -0
- package/esm/shuvi-app/react/Link.jsx +115 -0
- package/esm/shuvi-app/react/applicationContext.d.ts +7 -0
- package/esm/shuvi-app/react/applicationContext.jsx +10 -0
- package/esm/shuvi-app/react/dynamic.d.ts +31 -0
- package/esm/shuvi-app/react/dynamic.jsx +62 -0
- package/esm/shuvi-app/react/getRoutes.d.ts +2 -0
- package/esm/shuvi-app/react/getRoutes.js +31 -0
- package/esm/shuvi-app/react/head/head-manager-context.d.ts +2 -0
- package/esm/shuvi-app/react/head/head-manager-context.js +2 -0
- package/esm/shuvi-app/react/head/head-manager.d.ts +10 -0
- package/esm/shuvi-app/react/head/head-manager.js +93 -0
- package/esm/shuvi-app/react/head/head.d.ts +33 -0
- package/esm/shuvi-app/react/head/head.jsx +178 -0
- package/esm/shuvi-app/react/head/index.d.ts +4 -0
- package/esm/shuvi-app/react/head/index.js +4 -0
- package/esm/shuvi-app/react/head/side-effect.d.ts +30 -0
- package/esm/shuvi-app/react/head/side-effect.jsx +44 -0
- package/esm/shuvi-app/react/head/types.d.ts +15 -0
- package/esm/shuvi-app/react/head/types.js +1 -0
- package/esm/shuvi-app/react/index.d.ts +4 -0
- package/esm/shuvi-app/react/index.js +4 -0
- package/esm/shuvi-app/react/loadRouteComponent.d.ts +4 -0
- package/esm/shuvi-app/react/loadRouteComponent.jsx +9 -0
- package/esm/shuvi-app/react/loadable/index.d.ts +2 -0
- package/esm/shuvi-app/react/loadable/index.js +2 -0
- package/esm/shuvi-app/react/loadable/loadable-context.d.ts +4 -0
- package/esm/shuvi-app/react/loadable/loadable-context.js +3 -0
- package/esm/shuvi-app/react/loadable/loadable.d.ts +30 -0
- package/esm/shuvi-app/react/loadable/loadable.js +277 -0
- package/esm/shuvi-app/react/redox-react/RedoxWrapper.d.ts +8 -0
- package/esm/shuvi-app/react/redox-react/RedoxWrapper.jsx +11 -0
- package/esm/shuvi-app/react/redox-react/runtime.d.ts +2 -0
- package/esm/shuvi-app/react/redox-react/runtime.js +16 -0
- package/esm/shuvi-app/react/shuvi-runtime-api.d.ts +5 -0
- package/esm/shuvi-app/react/shuvi-runtime-api.js +5 -0
- package/esm/shuvi-app/react/types.d.ts +14 -0
- package/esm/shuvi-app/react/types.js +1 -0
- package/esm/shuvi-app/react/useLoaderData.d.ts +2 -0
- package/esm/shuvi-app/react/useLoaderData.js +27 -0
- package/esm/shuvi-app/react/utils/getDisplayName.d.ts +2 -0
- package/esm/shuvi-app/react/utils/getDisplayName.js +3 -0
- package/esm/shuvi-app/react/utils/requestIdleCallback.d.ts +2 -0
- package/esm/shuvi-app/react/utils/requestIdleCallback.js +20 -0
- package/esm/shuvi-app/react/utils/useIntersection.d.ts +8 -0
- package/esm/shuvi-app/react/utils/useIntersection.jsx +91 -0
- package/esm/shuvi-app/react/view/ReactView.client.d.ts +5 -0
- package/esm/shuvi-app/react/view/ReactView.client.jsx +64 -0
- package/esm/shuvi-app/react/view/ReactView.server.d.ts +4 -0
- package/esm/shuvi-app/react/view/ReactView.server.jsx +109 -0
- package/esm/shuvi-app/react/view/clientView.d.ts +3 -0
- package/esm/shuvi-app/react/view/clientView.js +2 -0
- package/esm/shuvi-app/react/view/index.d.ts +2 -0
- package/esm/shuvi-app/react/view/index.js +7 -0
- package/esm/shuvi-app/react/view/render-action.d.ts +10 -0
- package/esm/shuvi-app/react/view/render-action.js +29 -0
- package/esm/shuvi-app/react/view/serverView.d.ts +3 -0
- package/esm/shuvi-app/react/view/serverView.js +2 -0
- package/esm/shuvi-app/react/view/transformRoutes.d.ts +2 -0
- package/esm/shuvi-app/react/view/transformRoutes.js +3 -0
- package/esm/shuvi-app/shuvi-runtime-index.d.ts +4 -0
- package/esm/shuvi-app/shuvi-runtime-index.js +2 -0
- package/esm/shuvi-app/shuvi-runtime-server.d.ts +6 -0
- package/esm/shuvi-app/shuvi-runtime-server.js +1 -0
- package/lib/node/features/custom-server/index.d.ts +4 -0
- package/lib/node/features/custom-server/index.js +9 -0
- package/lib/node/features/custom-server/server.d.ts +2 -0
- package/lib/node/features/custom-server/server.js +28 -0
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.d.ts +51 -0
- package/lib/node/features/filesystem-routes/api/apiRouteHandler.js +237 -0
- package/lib/node/features/filesystem-routes/api/apiRoutes.d.ts +7 -0
- package/lib/node/features/filesystem-routes/api/apiRoutes.js +35 -0
- package/lib/node/features/filesystem-routes/api/index.d.ts +3 -0
- package/lib/node/features/filesystem-routes/api/index.js +7 -0
- package/lib/node/features/filesystem-routes/api/middleware.d.ts +2 -0
- package/lib/node/features/filesystem-routes/api/middleware.js +44 -0
- package/lib/node/features/filesystem-routes/hooks.d.ts +3 -0
- package/lib/node/features/filesystem-routes/hooks.js +6 -0
- package/lib/node/features/filesystem-routes/index.d.ts +20 -0
- package/lib/node/features/filesystem-routes/index.js +180 -0
- package/lib/node/features/filesystem-routes/middleware/index.d.ts +2 -0
- package/lib/node/features/filesystem-routes/middleware/index.js +7 -0
- package/lib/node/features/filesystem-routes/middleware/middleware.d.ts +2 -0
- package/lib/node/features/filesystem-routes/middleware/middleware.js +42 -0
- package/lib/node/features/filesystem-routes/middleware/routes.d.ts +9 -0
- package/lib/node/features/filesystem-routes/middleware/routes.js +34 -0
- package/lib/node/features/filesystem-routes/page/index.d.ts +2 -0
- package/lib/node/features/filesystem-routes/page/index.js +21 -0
- package/lib/node/features/filesystem-routes/page/routes.d.ts +8 -0
- package/lib/node/features/filesystem-routes/page/routes.js +83 -0
- package/lib/node/features/filesystem-routes/page/store.d.ts +3 -0
- package/lib/node/features/filesystem-routes/page/store.js +10 -0
- package/lib/node/features/html-render/index.d.ts +19 -0
- package/lib/node/features/html-render/index.js +28 -0
- package/lib/node/features/html-render/lib/generateFilesByRoutId.d.ts +3 -0
- package/lib/node/features/html-render/lib/generateFilesByRoutId.js +13 -0
- package/lib/node/features/html-render/lib/getPageMiddleware.d.ts +2 -0
- package/lib/node/features/html-render/lib/getPageMiddleware.js +56 -0
- package/lib/node/features/html-render/lib/index.d.ts +4 -0
- package/lib/node/features/html-render/lib/index.js +23 -0
- package/lib/node/features/html-render/lib/pageLoader.d.ts +1 -0
- package/lib/node/features/html-render/lib/pageLoader.js +42 -0
- package/lib/node/features/html-render/lib/renderToHTML.d.ts +6 -0
- package/lib/node/features/html-render/lib/renderToHTML.js +81 -0
- package/lib/node/features/html-render/lib/renderer/base.d.ts +17 -0
- package/lib/node/features/html-render/lib/renderer/base.js +70 -0
- package/lib/node/features/html-render/lib/renderer/htmlTag.d.ts +4 -0
- package/lib/node/features/html-render/lib/renderer/htmlTag.js +70 -0
- package/lib/node/features/html-render/lib/renderer/index.d.ts +15 -0
- package/lib/node/features/html-render/lib/renderer/index.js +48 -0
- package/lib/node/features/html-render/lib/renderer/spa.d.ts +5 -0
- package/lib/node/features/html-render/lib/renderer/spa.js +26 -0
- package/lib/node/features/html-render/lib/renderer/ssr.d.ts +5 -0
- package/lib/node/features/html-render/lib/renderer/ssr.js +70 -0
- package/lib/node/features/html-render/lib/renderer/types.d.ts +20 -0
- package/lib/node/features/html-render/lib/renderer/types.js +2 -0
- package/lib/node/features/html-render/lib/viewTemplate.d.ts +5 -0
- package/lib/node/features/html-render/lib/viewTemplate.js +37 -0
- package/lib/node/features/html-render/server.d.ts +2 -0
- package/lib/node/features/html-render/server.js +9 -0
- package/lib/node/features/html-render/serverHooks.d.ts +10 -0
- package/lib/node/features/html-render/serverHooks.js +13 -0
- package/lib/node/features/html-render/shuvi-app.d.ts +6 -0
- package/lib/node/features/html-render/shuvi-app.js +2 -0
- package/lib/node/features/index.d.ts +32 -0
- package/lib/node/features/index.js +25 -0
- package/lib/node/features/main/buildHtml.d.ts +8 -0
- package/lib/node/features/main/buildHtml.js +64 -0
- package/lib/node/features/main/generateResource.d.ts +3 -0
- package/lib/node/features/main/generateResource.js +56 -0
- package/lib/node/features/main/index.d.ts +3 -0
- package/lib/node/features/main/index.js +82 -0
- package/lib/node/features/middlewares.d.ts +4 -0
- package/lib/node/features/middlewares.js +23 -0
- package/lib/node/features/model/index.d.ts +21 -0
- package/lib/node/features/model/index.js +54 -0
- package/lib/node/features/model/runtime.d.ts +13 -0
- package/lib/node/features/model/runtime.js +47 -0
- package/lib/node/features/model/server.d.ts +3 -0
- package/lib/node/features/model/server.js +12 -0
- package/lib/node/features/model/shuvi-app.d.ts +6 -0
- package/lib/node/features/model/shuvi-app.js +2 -0
- package/lib/node/features/on-demand-compile-page/emptyComponent.d.ts +1 -0
- package/lib/node/features/on-demand-compile-page/emptyComponent.js +7 -0
- package/lib/node/features/on-demand-compile-page/index.d.ts +15 -0
- package/lib/node/features/on-demand-compile-page/index.js +36 -0
- package/lib/node/features/on-demand-compile-page/onDemandRouteManager.d.ts +11 -0
- package/lib/node/features/on-demand-compile-page/onDemandRouteManager.js +104 -0
- package/lib/node/index.d.ts +6 -0
- package/lib/node/index.js +38 -0
- package/lib/{paths.d.ts → node/paths.d.ts} +1 -2
- package/lib/node/paths.js +36 -0
- package/lib/node/shuvi-type-extensions-node.d.ts +42 -0
- package/lib/node/shuvi-type-extensions-node.js +3 -0
- package/lib/node/targets/react/bundler/index.d.ts +16 -0
- package/lib/node/targets/react/bundler/index.js +102 -0
- package/lib/node/targets/react/index.d.ts +32 -0
- package/lib/node/targets/react/index.js +28 -0
- package/lib/node/targets/react/redox-react/index.d.ts +18 -0
- package/lib/node/targets/react/redox-react/index.js +50 -0
- package/lib/shared/appTypes.d.ts +15 -0
- package/lib/shared/appTypes.js +2 -0
- package/lib/shared/configTypes.d.ts +14 -0
- package/lib/shared/configTypes.js +2 -0
- package/lib/shared/index.d.ts +5 -0
- package/lib/shared/index.js +21 -0
- package/lib/shared/renderTypes.d.ts +44 -0
- package/lib/shared/renderTypes.js +2 -0
- package/lib/shared/routeTypes.d.ts +47 -0
- package/lib/shared/routeTypes.js +2 -0
- package/lib/shared/serverTypes.d.ts +6 -0
- package/lib/shared/serverTypes.js +2 -0
- package/package.json +78 -15
- package/shuvi-type-extensions-node.d.ts +2 -0
- package/shuvi-type-extensions-runtime.d.ts +36 -0
- package/lib/index.d.ts +0 -3
- package/lib/index.js +0 -44
- package/lib/paths.js +0 -7
- package/shuvi-app/application/client/create-application-factory.d.ts +0 -3
- package/shuvi-app/application/client/create-application-factory.js +0 -70
- package/shuvi-app/application/client/create-application-history-browser.d.ts +0 -1
- package/shuvi-app/application/client/create-application-history-browser.js +0 -3
- package/shuvi-app/application/client/create-application-history-hash.d.ts +0 -1
- package/shuvi-app/application/client/create-application-history-hash.js +0 -3
- package/shuvi-app/application/client/create-application-history-memory.d.ts +0 -1
- package/shuvi-app/application/client/create-application-history-memory.js +0 -3
- package/shuvi-app/application/server/create-application-spa.d.ts +0 -2
- package/shuvi-app/application/server/create-application-spa.js +0 -8
- package/shuvi-app/application/server/create-application.d.ts +0 -2
- package/shuvi-app/application/server/create-application.js +0 -25
- package/shuvi-app/entry/client/index.d.ts +0 -1
- package/shuvi-app/entry/client/index.js +0 -11
- package/shuvi-app/entry/client/run.prod.js +0 -3
- package/shuvi-app/entry/client/setup-app.d.ts +0 -3
- package/shuvi-app/entry/client/setup-app.js +0 -38
- package/shuvi-app/entry/client/setup-env.js +0 -27
- package/shuvi-app/entry/server/index.d.ts +0 -6
- package/shuvi-app/entry/server/index.js +0 -7
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { SHUVI_ERROR } from '@shuvi/shared/lib/constants';
|
|
3
|
+
import ErrorPage from './ErrorPage';
|
|
4
|
+
class ErrorBoundary extends React.PureComponent {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.state = { error: null };
|
|
8
|
+
}
|
|
9
|
+
componentDidCatch(error,
|
|
10
|
+
// Loosely typed because it depends on the React version and was
|
|
11
|
+
// accidentally excluded in some versions.
|
|
12
|
+
errorInfo) {
|
|
13
|
+
this.setState({ error });
|
|
14
|
+
console.error('the error is below: \n', error);
|
|
15
|
+
if (errorInfo && errorInfo.componentStack) {
|
|
16
|
+
console.error('the componentStack is below: \n', errorInfo.componentStack);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
render() {
|
|
20
|
+
return this.state.error ? (
|
|
21
|
+
// The component has to be unmounted or else it would continue to error
|
|
22
|
+
<ErrorPage code={SHUVI_ERROR.APP_ERROR.code} message={SHUVI_ERROR.APP_ERROR.message}/>) : this.props.children;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export { ErrorBoundary };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { LinkProps } from '@shuvi/router-react';
|
|
3
|
+
export declare const Link: ({ prefetch, onMouseEnter, to, ref, ...rest }: LinkWrapperProps) => JSX.Element;
|
|
4
|
+
interface LinkWrapperProps extends LinkProps {
|
|
5
|
+
ref?: any;
|
|
6
|
+
}
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
11
|
+
var t = {};
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
15
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
16
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
17
|
+
t[p[i]] = s[p[i]];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
21
|
+
import * as React from 'react';
|
|
22
|
+
import { Link as LinkFromRouterReact, RouterContext } from '@shuvi/router-react';
|
|
23
|
+
import { getFilesOfRoute } from '@shuvi/platform-shared/shared';
|
|
24
|
+
import useIntersection from './utils/useIntersection';
|
|
25
|
+
const ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\d+\-.]*?:/;
|
|
26
|
+
const prefetched = {};
|
|
27
|
+
function hasSupportPrefetch() {
|
|
28
|
+
try {
|
|
29
|
+
const link = document.createElement('link');
|
|
30
|
+
return link.relList.supports('prefetch');
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function prefetchViaDom(href, id, as) {
|
|
37
|
+
return new Promise((res, rej) => {
|
|
38
|
+
const selector = `
|
|
39
|
+
link[rel="prefetch"][href^="${href}"],
|
|
40
|
+
script[src^="${href}"]`;
|
|
41
|
+
if (document.querySelector(selector)) {
|
|
42
|
+
return res();
|
|
43
|
+
}
|
|
44
|
+
const link = document.createElement('link');
|
|
45
|
+
// The order of property assignment here is intentional:
|
|
46
|
+
if (as)
|
|
47
|
+
link.as = as;
|
|
48
|
+
link.rel = `prefetch`;
|
|
49
|
+
link.onload = res;
|
|
50
|
+
link.onerror = rej;
|
|
51
|
+
link.dataset.id = id;
|
|
52
|
+
// `href` should always be last:
|
|
53
|
+
link.href = href;
|
|
54
|
+
document.head.appendChild(link);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function prefetchFn(router, to) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
const files = getFilesOfRoute(router, to);
|
|
60
|
+
if (process.env.NODE_ENV !== 'production')
|
|
61
|
+
return;
|
|
62
|
+
if (typeof window === 'undefined')
|
|
63
|
+
return;
|
|
64
|
+
const canPrefetch = hasSupportPrefetch();
|
|
65
|
+
yield Promise.all(canPrefetch
|
|
66
|
+
? files.js.map(({ url, id }) => prefetchViaDom(url, id, 'script'))
|
|
67
|
+
: []);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const isAbsoluteUrl = (url) => {
|
|
71
|
+
return ABSOLUTE_URL_REGEX.test(url);
|
|
72
|
+
};
|
|
73
|
+
export const Link = function LinkWithPrefetch(_a) {
|
|
74
|
+
var { prefetch, onMouseEnter, to, ref } = _a, rest = __rest(_a, ["prefetch", "onMouseEnter", "to", "ref"]);
|
|
75
|
+
const isHrefValid = typeof to === 'string' && !isAbsoluteUrl(to);
|
|
76
|
+
const previousHref = React.useRef(to);
|
|
77
|
+
const [setIntersectionRef, isVisible, resetVisible] = useIntersection({});
|
|
78
|
+
const { router } = React.useContext(RouterContext);
|
|
79
|
+
const setRef = React.useCallback((el) => {
|
|
80
|
+
// Before the link getting observed, check if visible state need to be reset
|
|
81
|
+
if (isHrefValid && previousHref.current !== to) {
|
|
82
|
+
resetVisible();
|
|
83
|
+
previousHref.current = to;
|
|
84
|
+
}
|
|
85
|
+
if (isHrefValid && prefetch !== false)
|
|
86
|
+
setIntersectionRef(el);
|
|
87
|
+
if (ref) {
|
|
88
|
+
if (typeof ref === 'function')
|
|
89
|
+
ref(el);
|
|
90
|
+
else if (typeof ref === 'object') {
|
|
91
|
+
ref.current = el;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}, [to, isHrefValid, prefetch, resetVisible, setIntersectionRef, ref]);
|
|
95
|
+
React.useEffect(() => {
|
|
96
|
+
const shouldPrefetch = isHrefValid && prefetch !== false && isVisible;
|
|
97
|
+
if (shouldPrefetch && !prefetched[to]) {
|
|
98
|
+
prefetchFn(router, to);
|
|
99
|
+
prefetched[to] = true;
|
|
100
|
+
}
|
|
101
|
+
}, [to, prefetch, isVisible]);
|
|
102
|
+
const childProps = {
|
|
103
|
+
ref: setRef,
|
|
104
|
+
onMouseEnter: (e) => {
|
|
105
|
+
if (typeof onMouseEnter === 'function') {
|
|
106
|
+
onMouseEnter(e);
|
|
107
|
+
}
|
|
108
|
+
if (isHrefValid && !prefetched[to]) {
|
|
109
|
+
prefetchFn(router, to);
|
|
110
|
+
prefetched[to] = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
return <LinkFromRouterReact to={to} {...rest} {...childProps}/>;
|
|
115
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { IApplication } from '@shuvi/platform-shared/shared';
|
|
3
|
+
export declare const ApplicationContext: React.Context<IApplication>;
|
|
4
|
+
export declare function AppProvider({ app, children }: React.PropsWithChildren<{
|
|
5
|
+
app: IApplication;
|
|
6
|
+
}>): JSX.Element;
|
|
7
|
+
export declare function useApp(): IApplication;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export const ApplicationContext = React.createContext(null);
|
|
3
|
+
export function AppProvider({ app, children }) {
|
|
4
|
+
return (<ApplicationContext.Provider value={app}>
|
|
5
|
+
{children}
|
|
6
|
+
</ApplicationContext.Provider>);
|
|
7
|
+
}
|
|
8
|
+
export function useApp() {
|
|
9
|
+
return React.useContext(ApplicationContext);
|
|
10
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export declare type LoaderComponent<P = {}> = Promise<React.ComponentType<P> | {
|
|
3
|
+
default: React.ComponentType<P>;
|
|
4
|
+
}>;
|
|
5
|
+
export declare type Loader<P = {}> = () => LoaderComponent<P>;
|
|
6
|
+
export declare type LoadableGeneratedOptions = {
|
|
7
|
+
webpack?(): string[];
|
|
8
|
+
modules?: string[];
|
|
9
|
+
};
|
|
10
|
+
export declare type LoadableBaseOptions<P = {}> = LoadableGeneratedOptions & {
|
|
11
|
+
loading?: ({ error, isLoading, pastDelay }: {
|
|
12
|
+
error?: Error | null;
|
|
13
|
+
isLoading?: boolean;
|
|
14
|
+
pastDelay?: boolean;
|
|
15
|
+
timedOut?: boolean;
|
|
16
|
+
}) => JSX.Element | null;
|
|
17
|
+
loader?: Loader<P>;
|
|
18
|
+
ssr?: boolean;
|
|
19
|
+
};
|
|
20
|
+
export declare type DynamicOptions<P = {}> = LoadableBaseOptions<P>;
|
|
21
|
+
export declare type LoaderFn<P = {}> = (opts: DynamicOptions<P>) => React.ComponentType<P>;
|
|
22
|
+
export declare type LoadableComponent<P = {}> = React.ComponentType<P>;
|
|
23
|
+
export declare function noSSR<P = {}>(LoadableInitializer: LoaderFn<P>, dynamicOptions: DynamicOptions<P>): React.ComponentType<P> | (() => JSX.Element);
|
|
24
|
+
/**
|
|
25
|
+
* ES2020 [dynamic import()](https://github.com/tc39/proposal-dynamic-import) for JavaScript
|
|
26
|
+
*
|
|
27
|
+
* @param dynamicOptions {@link DynamicOptions} | {@link Loader}
|
|
28
|
+
* @param options {@link DynamicOptions}
|
|
29
|
+
* @returns React.ComponentType
|
|
30
|
+
*/
|
|
31
|
+
export default function dynamic<P = {}>(dynamicOptions: DynamicOptions<P> | Loader<P>, options?: DynamicOptions<P>): React.ComponentType<P>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Loadable from './loadable';
|
|
3
|
+
const isServerSide = typeof window === 'undefined';
|
|
4
|
+
export function noSSR(LoadableInitializer, dynamicOptions) {
|
|
5
|
+
// Removing webpack and modules means react-loadable won't try preloading
|
|
6
|
+
delete dynamicOptions.webpack;
|
|
7
|
+
delete dynamicOptions.modules;
|
|
8
|
+
// This check is neccesary to prevent react-loadable from initializing on the server
|
|
9
|
+
if (!isServerSide) {
|
|
10
|
+
return LoadableInitializer(dynamicOptions);
|
|
11
|
+
}
|
|
12
|
+
const Loading = dynamicOptions.loading;
|
|
13
|
+
// This will only be rendered on the server side
|
|
14
|
+
return () => (<Loading error={null} isLoading pastDelay={false} timedOut={false}/>);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ES2020 [dynamic import()](https://github.com/tc39/proposal-dynamic-import) for JavaScript
|
|
18
|
+
*
|
|
19
|
+
* @param dynamicOptions {@link DynamicOptions} | {@link Loader}
|
|
20
|
+
* @param options {@link DynamicOptions}
|
|
21
|
+
* @returns React.ComponentType
|
|
22
|
+
*/
|
|
23
|
+
export default function dynamic(dynamicOptions, options) {
|
|
24
|
+
let loadableFn = Loadable;
|
|
25
|
+
let loadableOptions = {
|
|
26
|
+
// A loading component is not required, so we default it
|
|
27
|
+
loading: ({ error, isLoading, pastDelay }) => {
|
|
28
|
+
if (!pastDelay)
|
|
29
|
+
return null;
|
|
30
|
+
if (process.env.NODE_ENV === 'development') {
|
|
31
|
+
if (isLoading) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (error) {
|
|
35
|
+
return (<p>
|
|
36
|
+
{error.message}
|
|
37
|
+
<br />
|
|
38
|
+
{error.stack}
|
|
39
|
+
</p>);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
if (typeof dynamicOptions === 'function') {
|
|
46
|
+
loadableOptions.loader = dynamicOptions;
|
|
47
|
+
// Support for having first argument being options, eg: dynamic({loader: import('../hello-world')})
|
|
48
|
+
}
|
|
49
|
+
else if (typeof dynamicOptions === 'object') {
|
|
50
|
+
loadableOptions = Object.assign(Object.assign({}, loadableOptions), dynamicOptions);
|
|
51
|
+
}
|
|
52
|
+
// Support for passing options, eg: dynamic(import('../hello-world'), {loading: () => <p>Loading something</p>})
|
|
53
|
+
loadableOptions = Object.assign(Object.assign({}, loadableOptions), options);
|
|
54
|
+
if (typeof loadableOptions.ssr === 'boolean') {
|
|
55
|
+
if (!loadableOptions.ssr) {
|
|
56
|
+
delete loadableOptions.ssr;
|
|
57
|
+
return noSSR(loadableFn, loadableOptions);
|
|
58
|
+
}
|
|
59
|
+
delete loadableOptions.ssr;
|
|
60
|
+
}
|
|
61
|
+
return loadableFn(loadableOptions);
|
|
62
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { loadRouteComponent } from './loadRouteComponent';
|
|
13
|
+
export default function getRoutes(routes) {
|
|
14
|
+
const getRoutesWithRequire = (routes) => routes.map(x => {
|
|
15
|
+
const originalRoute = Object.assign({}, x);
|
|
16
|
+
const { __componentSource__, __componentSourceWithAffix__, __import__, __resolveWeak__, children } = originalRoute, rest = __rest(originalRoute, ["__componentSource__", "__componentSourceWithAffix__", "__import__", "__resolveWeak__", "children"]);
|
|
17
|
+
const route = Object.assign({}, rest);
|
|
18
|
+
if (children) {
|
|
19
|
+
route.children = getRoutesWithRequire(children);
|
|
20
|
+
}
|
|
21
|
+
if (__componentSourceWithAffix__ && __import__) {
|
|
22
|
+
route.component = loadRouteComponent(__import__, {
|
|
23
|
+
webpack: __resolveWeak__,
|
|
24
|
+
modules: [__componentSourceWithAffix__]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return Object.assign({ __componentSourceWithAffix__, __resolveWeak__ }, route);
|
|
28
|
+
});
|
|
29
|
+
const routesWithRequire = getRoutesWithRequire(routes || []);
|
|
30
|
+
return routesWithRequire;
|
|
31
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Based on https://github.com/zeit/next.js
|
|
2
|
+
// License: https://github.com/zeit/next.js/blob/977bf8d9ebd2845241b8689317f36e4e487f39d0/license.md
|
|
3
|
+
import { SHUVI_HEAD_ATTRIBUTE } from './head';
|
|
4
|
+
export default class HeadManager {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._pedningPromise = null;
|
|
7
|
+
this.updateHead = this.updateHead.bind(this);
|
|
8
|
+
}
|
|
9
|
+
updateHead(head) {
|
|
10
|
+
this._head = head;
|
|
11
|
+
if (this._pedningPromise) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
this._pedningPromise = Promise.resolve().then(() => {
|
|
15
|
+
this._pedningPromise = null;
|
|
16
|
+
this._doUpdateHead();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
_doUpdateHead() {
|
|
20
|
+
const tags = {};
|
|
21
|
+
this._head.forEach(h => {
|
|
22
|
+
(tags[h.tagName] || (tags[h.tagName] = [])).push(h);
|
|
23
|
+
});
|
|
24
|
+
if (tags.title) {
|
|
25
|
+
this._updateTitle(tags.title[0]);
|
|
26
|
+
}
|
|
27
|
+
const types = ['meta', 'base', 'link', 'style', 'script'];
|
|
28
|
+
types.forEach(type => {
|
|
29
|
+
this._updateElements(type, tags[type] || []);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
_updateTitle({ attrs }) {
|
|
33
|
+
const title = attrs.textContent || '';
|
|
34
|
+
if (title !== document.title)
|
|
35
|
+
document.title = title;
|
|
36
|
+
const titleEle = document.getElementsByTagName('title')[0];
|
|
37
|
+
if (titleEle) {
|
|
38
|
+
assignAttributes(titleEle, attrs);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
_updateElements(type, tags) {
|
|
42
|
+
const headEl = document.getElementsByTagName('head')[0];
|
|
43
|
+
const oldNodes = headEl.querySelectorAll(`${type}[${SHUVI_HEAD_ATTRIBUTE}='true']`);
|
|
44
|
+
const oldTags = Array.prototype.slice.call(oldNodes);
|
|
45
|
+
let divideElement = null;
|
|
46
|
+
if (oldTags.length) {
|
|
47
|
+
divideElement = oldTags[oldTags.length - 1].nextElementSibling;
|
|
48
|
+
}
|
|
49
|
+
const newTags = tags.map(tagToDOM).filter(newTag => {
|
|
50
|
+
for (let k = 0, len = oldTags.length; k < len; k++) {
|
|
51
|
+
const oldTag = oldTags[k];
|
|
52
|
+
if (oldTag.isEqualNode(newTag)) {
|
|
53
|
+
oldTags.splice(k, 1);
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
oldTags.forEach(t => t.parentNode.removeChild(t));
|
|
60
|
+
newTags.forEach(t => {
|
|
61
|
+
if (divideElement) {
|
|
62
|
+
headEl.insertBefore(t, divideElement);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
headEl.appendChild(t);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function assignAttributes(el, attrs) {
|
|
71
|
+
for (const a in attrs) {
|
|
72
|
+
if (!Object.prototype.hasOwnProperty.call(attrs, a))
|
|
73
|
+
continue;
|
|
74
|
+
if (a === 'textContent')
|
|
75
|
+
continue;
|
|
76
|
+
// we don't render undefined props to the DOM
|
|
77
|
+
if (attrs[a] === undefined)
|
|
78
|
+
continue;
|
|
79
|
+
el.setAttribute(a.toLowerCase(), attrs[a]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function tagToDOM({ tagName, attrs, innerHTML }) {
|
|
83
|
+
const el = document.createElement(tagName);
|
|
84
|
+
assignAttributes(el, attrs);
|
|
85
|
+
const { textContent } = attrs;
|
|
86
|
+
if (innerHTML) {
|
|
87
|
+
el.innerHTML = innerHTML;
|
|
88
|
+
}
|
|
89
|
+
else if (textContent) {
|
|
90
|
+
el.textContent = textContent;
|
|
91
|
+
}
|
|
92
|
+
return el;
|
|
93
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { HeadState } from './types';
|
|
3
|
+
export declare const SHUVI_HEAD_ATTRIBUTE = "data-shuvi-head";
|
|
4
|
+
/**
|
|
5
|
+
* This component injects elements to `<head>` of your page.
|
|
6
|
+
* To avoid duplicated `tags` in `<head>` you can use the `key` property, which will make sure every tag is only rendered once.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { Head } from "@shuvi/runtime";
|
|
10
|
+
*
|
|
11
|
+
* function IndexPage() {
|
|
12
|
+
* return (
|
|
13
|
+
* <div>
|
|
14
|
+
* <Head>
|
|
15
|
+
* <title>My page title</title>
|
|
16
|
+
* <meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
|
17
|
+
* </Head>
|
|
18
|
+
* <p>Hello world!</p>
|
|
19
|
+
* </div>
|
|
20
|
+
* );
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* export default IndexPage;
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
declare function Head({ children }: {
|
|
28
|
+
children?: React.ReactNode;
|
|
29
|
+
}): JSX.Element;
|
|
30
|
+
declare namespace Head {
|
|
31
|
+
var rewind: () => HeadState | undefined;
|
|
32
|
+
}
|
|
33
|
+
export default Head;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Based on https://github.com/zeit/next.js
|
|
2
|
+
// License: https://github.com/zeit/next.js/blob/977bf8d9ebd2845241b8689317f36e4e487f39d0/license.md
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import withSideEffect from './side-effect';
|
|
5
|
+
import { HeadManagerContext } from './head-manager-context';
|
|
6
|
+
export const SHUVI_HEAD_ATTRIBUTE = 'data-shuvi-head';
|
|
7
|
+
const DOMAttributeNames = {
|
|
8
|
+
acceptCharset: 'accept-charset',
|
|
9
|
+
className: 'class',
|
|
10
|
+
htmlFor: 'for',
|
|
11
|
+
httpEquiv: 'http-equiv'
|
|
12
|
+
};
|
|
13
|
+
function reactElementToTag({ type, props }) {
|
|
14
|
+
const tag = {
|
|
15
|
+
tagName: type,
|
|
16
|
+
attrs: {}
|
|
17
|
+
};
|
|
18
|
+
for (const p in props) {
|
|
19
|
+
if (!props.hasOwnProperty(p))
|
|
20
|
+
continue;
|
|
21
|
+
if (p === 'children' || p === 'dangerouslySetInnerHTML')
|
|
22
|
+
continue;
|
|
23
|
+
// we don't render undefined props to the DOM
|
|
24
|
+
if (props[p] === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
const attr = DOMAttributeNames[p] || p.toLowerCase();
|
|
27
|
+
tag.attrs[attr] = props[p];
|
|
28
|
+
}
|
|
29
|
+
const { children, dangerouslySetInnerHTML } = props;
|
|
30
|
+
if (dangerouslySetInnerHTML) {
|
|
31
|
+
tag.innerHTML = dangerouslySetInnerHTML.__html || '';
|
|
32
|
+
}
|
|
33
|
+
else if (children) {
|
|
34
|
+
tag.attrs.textContent =
|
|
35
|
+
typeof children === 'string' ? children : children.join('');
|
|
36
|
+
}
|
|
37
|
+
return tag;
|
|
38
|
+
}
|
|
39
|
+
function onlyReactElement(list, child) {
|
|
40
|
+
// React children can be "string" or "number" in this case we ignore them for backwards compat
|
|
41
|
+
if (typeof child === 'string' || typeof child === 'number') {
|
|
42
|
+
return list;
|
|
43
|
+
}
|
|
44
|
+
// Adds support for React.Fragment
|
|
45
|
+
if (child.type === React.Fragment) {
|
|
46
|
+
return list.concat(React.Children.toArray(child.props.children).reduce((fragmentList, fragmentChild) => {
|
|
47
|
+
if (typeof fragmentChild === 'string' ||
|
|
48
|
+
typeof fragmentChild === 'number') {
|
|
49
|
+
return fragmentList;
|
|
50
|
+
}
|
|
51
|
+
return fragmentList.concat(fragmentChild);
|
|
52
|
+
}, []));
|
|
53
|
+
}
|
|
54
|
+
return list.concat(child);
|
|
55
|
+
}
|
|
56
|
+
const METATYPES = ['name', 'httpEquiv', 'charSet', 'itemProp'];
|
|
57
|
+
/*
|
|
58
|
+
returns a function for filtering head child elements
|
|
59
|
+
which shouldn't be duplicated, like <title/>
|
|
60
|
+
Also adds support for deduplicated `key` properties
|
|
61
|
+
*/
|
|
62
|
+
function unique() {
|
|
63
|
+
const keys = new Set();
|
|
64
|
+
const tags = new Set();
|
|
65
|
+
const metaTypes = new Set();
|
|
66
|
+
const metaCategories = {};
|
|
67
|
+
return (h) => {
|
|
68
|
+
let unique = true;
|
|
69
|
+
if (h.key && typeof h.key !== 'number' && h.key.indexOf('$') > 0) {
|
|
70
|
+
const key = h.key.slice(h.key.indexOf('$') + 1);
|
|
71
|
+
if (keys.has(key)) {
|
|
72
|
+
unique = false;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
keys.add(key);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// eslint-disable-next-line default-case
|
|
79
|
+
switch (h.type) {
|
|
80
|
+
case 'title':
|
|
81
|
+
case 'base':
|
|
82
|
+
if (tags.has(h.type)) {
|
|
83
|
+
unique = false;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
tags.add(h.type);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case 'meta':
|
|
90
|
+
for (let i = 0, len = METATYPES.length; i < len; i++) {
|
|
91
|
+
const metatype = METATYPES[i];
|
|
92
|
+
if (!h.props.hasOwnProperty(metatype))
|
|
93
|
+
continue;
|
|
94
|
+
if (metatype === 'charSet') {
|
|
95
|
+
if (metaTypes.has(metatype)) {
|
|
96
|
+
unique = false;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
metaTypes.add(metatype);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const category = h.props[metatype];
|
|
104
|
+
const categories = metaCategories[metatype] || new Set();
|
|
105
|
+
if (categories.has(category)) {
|
|
106
|
+
unique = false;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
categories.add(category);
|
|
110
|
+
metaCategories[metatype] = categories;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
return unique;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function onlyHeadElement(element) {
|
|
120
|
+
return typeof element.type === 'string';
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
*
|
|
124
|
+
* @param headElement List of multiple <Head> instances
|
|
125
|
+
*/
|
|
126
|
+
function reduceComponents(headElements) {
|
|
127
|
+
return headElements
|
|
128
|
+
.reduce((list, headElement) => {
|
|
129
|
+
const headElementChildren = React.Children.toArray(headElement.props.children);
|
|
130
|
+
return list.concat(headElementChildren);
|
|
131
|
+
}, [])
|
|
132
|
+
.reduce(onlyReactElement, [])
|
|
133
|
+
.filter(onlyHeadElement)
|
|
134
|
+
.reverse()
|
|
135
|
+
.filter(unique())
|
|
136
|
+
.reverse()
|
|
137
|
+
.map(e => {
|
|
138
|
+
const { type, props } = e;
|
|
139
|
+
const headElement = {
|
|
140
|
+
type,
|
|
141
|
+
props: Object.assign(Object.assign({}, props), { [SHUVI_HEAD_ATTRIBUTE]: 'true' })
|
|
142
|
+
};
|
|
143
|
+
return reactElementToTag(headElement);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const Effect = withSideEffect();
|
|
147
|
+
/**
|
|
148
|
+
* This component injects elements to `<head>` of your page.
|
|
149
|
+
* To avoid duplicated `tags` in `<head>` you can use the `key` property, which will make sure every tag is only rendered once.
|
|
150
|
+
*
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { Head } from "@shuvi/runtime";
|
|
153
|
+
*
|
|
154
|
+
* function IndexPage() {
|
|
155
|
+
* return (
|
|
156
|
+
* <div>
|
|
157
|
+
* <Head>
|
|
158
|
+
* <title>My page title</title>
|
|
159
|
+
* <meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
|
160
|
+
* </Head>
|
|
161
|
+
* <p>Hello world!</p>
|
|
162
|
+
* </div>
|
|
163
|
+
* );
|
|
164
|
+
* }
|
|
165
|
+
*
|
|
166
|
+
* export default IndexPage;
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
*/
|
|
170
|
+
function Head({ children }) {
|
|
171
|
+
return (<HeadManagerContext.Consumer>
|
|
172
|
+
{updateHead => (<Effect reduceComponentsToState={reduceComponents} handleStateChange={updateHead}>
|
|
173
|
+
{children}
|
|
174
|
+
</Effect>)}
|
|
175
|
+
</HeadManagerContext.Consumer>);
|
|
176
|
+
}
|
|
177
|
+
Head.rewind = Effect.rewind;
|
|
178
|
+
export default Head;
|