自定义 Exports/Hooks
pageContext.exports
包含以下的 export
值:
- 当前页面的
.page.js
/.page.server.js
/.page.client.js
文件
_default.page.*
文件
例如:
// /pages/countries.page.js
// Environment: Node.js & Browser
export const title = "Earth Countries";
// /pages/countries.page.server.js
// Environment: Node.js
export const dataUrl = "https://restcountries.com/v3.1/all";
// /renderer/_default.page.server.js
// Environment: Node.js
export { onBeforeRender };
import fetch from "node-fetch";
async function onBeforeRender(pageContext) {
const response = await fetch(pageContext.exports.dataUrl);
// ...
}
function render(pageContext) {
const titleTag = `<title>${pageContext.exports.title}</title>`;
// ...
}
// /renderer/_default.page.client.js
// Environment: Browser
export const clientRouting = true;
export { render };
function render(pageContext) {
if (!pageContext.isHydration) {
// 页面导航时更新网站标题
document.title = pageContext.exports.title;
}
// ...
}
注意 pageContext.exports.title
在 Node.js 和浏览器中都可以使用:因为 export { title }
定义在 .page.js
文件中,该文件在 Node.js 和浏览器中都会加载
而 pageContext.exports.dataUrl
在浏览器中不可用: .page.server.js
文件仅在 Node.js 中加载
我们称这项技术为 Custom Exports / Custom Hooks
Example: Page Layout
一种常见的用法是使用自定义 export pageContext.exports.Layout
来定义页面的 layout 布局
// /pages/product.page.js
// Environment: Browser & Node.js
export { Layout } from "../layouts/Responsive";
export function Page() {
/* ... */
}
// /pages/admin.page.js
// Environment: Browser & Node.js
export { Layout } from "../layouts/Dashboard";
export function Page() {
/* ... */
}
// /renderer/_default.page.server.js
// Environment: Node.js
import { renderToHtml } from "some-ui-framework";
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
export function render(pageContext) {
const { Page, Layout } = pageContext.exports;
const pageHtml = renderToHtml(
<Layout>
<Page />
</Layout>
);
return escapeInject`<!DOCTYPE html>
<html>
<body>
<div id="root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`;
}
// /renderer/_default.page.client.js
// Environment: Browser
import { renderDom } from "some-ui-framework";
export function render(pageContext) {
// `.page.js` 文件在浏览器中加载:`Layout` 和 `Page` 也可以在这里使用
const { Page, Layout } = pageContext.exports;
renderDom(
<Layout>
<Page />
</Layout>,
document.getElementById("root")
);
}
注意我们使用 pageContext.exports.Page
而不是 pageContext.Page
:因为 pageContext.Page
实际上只是 pageContext.exports.Page ?? pageContext.exports.default
的别名
Example: 数据查询
另一个常见的例子是使用自定义 export pageContext.exports.query
来定义页面的数据查询
// /pages/product.page.js
export const query = { modelName: "Product", select: ["name", "price"] };
// /pages/user.page.js
export const query = { modelName: "User", select: ["firstName", "lastName"] };
// /renderer/_default.page.server.js
// Environment: Node.js
export { onBeforeRender };
export { render };
export const passToClient = ["pageProps"];
import { renderToHtml } from "some-ui-framework";
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
import { runQuery } from "some-sql-engine";
async function onBeforeRender(pageContext) {
const { query } = pageContext.exports;
const data = await runQuery(query);
const pageProps = { data };
return { pageContext: { pageProps } };
}
function render(pageContext) {
const { Page, pageProps } = pageContext;
const pageHtml = renderToHtml(<Page {...pageProps} />);
return escapeInject`<!DOCTYPE html>
<html>
<body>
<div id="root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`;
}
// /renderer/_default.page.client.js
// Environment: Browser
export { render };
import { renderDom } from "some-ui-framework";
function render(pageContext) {
const { Page, pageProps } = pageContext;
renderDom(<Page {...pageProps} />, document.getElementById("root"));
}
我们还可以使用自定义 export pageContext.export.meta
来定义页面的 meta 数据
// /pages/product.page.js
// Environment: Node.js
export const title = "Product";
export const getDescription = (pageProps) =>
`Product: ${pageProps.productName}`;
// /pages/user.page.js
// Environment: Node.js
export const title = "User";
export const getDescription = (pageProps) =>
`User: ${pageProps.firstName} ${pageProps.lastName}`;
// /renderer/_default.page.server.js
// Environment: Node.js
export { render };
import { renderToHtml } from "some-ui-framework";
import { escapeInject, dangerouslySkipEscape } from "vite-plugin-ssr";
function render(pageContext) {
const { Page, pageProps } = pageContext;
const { title, getDescription } = pageContext.exports;
const description = getDescription(pageProps);
const pageHtml = renderToHtml(<Page {...pageProps} />);
return escapeInject`<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
<meta name="description" content="${description}" />
</head>
<body>
<div id="root">${dangerouslySkipEscape(pageHtml)}</div>
</body>
</html>`;
}