摘要:补充上文中出现的部分函数,直接截取自源码,都相对简单,可以作为参考很多参数,太长省略
入口
这是一个基础demo,由开发者自己提供server,用于渲染
const Koa = require("koa") const Router = require("koa-router") const next = require("next") // 创建实例 const app = next({ dev, conf, dir: "./src" }) app.prepare().then(() => { const server = new Koa() const router = new Router() router.get("/", async ctx => { // 渲染 await app.render(ctx.req, ctx.res) ctx.respond = false }) server.listen(port) })
在自定义服务端中通过const app = next()创建实例并使用app.render(req, res)方法进行渲染
所以直接从app.render这个渲染入口开始着手
了解框架逻辑唯一的方式就是看源码,由于源码过于细节,下面我会简化涉及到的代码,仅保留主要逻辑,附带具体地址,有兴趣深入的同学可以看看app.render
next-server/server/next-server.ts
import { renderToHTML } from "./render.tsx" // app.render入口函数 this.render(req, res){ const html = await this.renderToHTML(req, res) return this.sendHTML(req, res, html) } this.renderToHTML(req, res){ const html = await this.renderToHTMLWithComponents(req, res) return html } this.renderToHTMLWithComponents(req, res) { // render内的renderToHTML return renderToHTML(req, res) }
可以看到上面都是简单的调用关系,虽然删除了大部分代码,但我们只需要知道,最终它调用了render.tsx内的renderToHTML
这是一个相当长的函数,也就是本篇文章的主要内容,通过renderToHTML能够了解到大部分内容,和上面相同,删除了大部分逻辑,仅保留核心代码
renderToHTML// next-server/server/render.tsx function renderToHTML(req, res) { // 参考下文#补充 loadGetInitialProps,非常简单的函数,就是调用了_app.getInitialProps // _app.getInitialProps函数内部会先调用pages.Component的getInitialProps // 也就是在这里,我们编写的组件内的getInitialProps同样会被调用,获取部分初始数据 let props = await loadGetInitialProps(App, { Component, router, ctx }); // 定义渲染函数,返回html和head const renderPage = () => { // 参考下文#补充 render return render( renderToStaticMarkup, //渲染_app,以及其内部的pages.Component也就是我们编写的代码,详情参考next/pages/_app.tsx小结); }; // _document.getInitialProps会调用renderPage,渲染_app也就是我们的正常开发时编写的组件代码,详情参考next/pages/_app.tsx const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage }); // 参考下文#补充 renderDocument let html = renderDocument(Document, { props, docProps, }); return html; }
req=> render(req, res) renderToHTML(req, res) renderToHTMLWithComponents(req, res) renderToHTML(req,res) _app.initialProps = loadGetInitialProps(App, { Component, router, ctx }) _document.initialProps = loadGetInitialProps(Document, { ...ctx, renderPage }) renderDocument(Document, _app.initialProps, _document.initialProps) <=res
对应
req=> _app.getInitialProps() Component.getInitialProps() _document.getInitialProps() _app.render() Component.render() _document.render() <=res
这篇文章简要描述next服务端的渲染过程,从中我们也能清楚_document、_app、以及pages内自己编写的组件之间的关系...
要是还没明白,请重新阅读一遍renderToHTML函数内的注释内容
需要注意的一些点,随缘补充
_document只在服务端被执行,浏览器端是不会执行的
react提供的renderToString函数只产出html,也就是纯粹的string,所有数据必须在调用renderToString之前注入
在浏览器端渲染时,存在isInitialRender用于标示是否第一次渲染,如果是第一次渲染,会调用ReactDOM.hydrate(reactEl, domEl)来执行绑定事件,所以部分生命周期(componentWillMount之后)以及事件会在浏览器端执行。
补充上文中出现的部分函数,直接截取自源码,都相对简单,可以作为参考
renderfunction render( renderElementToString: (element: React.ReactElementloadGetInitialProps) => string, element: React.ReactElement , ampMode: any, ): { html: string; head: React.ReactElement[] } { let html let head try { html = renderElementToString(element) } finally { head = Head.rewind() || defaultHead(undefined, isAmp(ampMode)) } return { html, head } }
export async function loadGetInitialPropsrenderDocument(Component: NextComponentType , ctx: C): Promise { if (process.env.NODE_ENV !== "production") { if (Component.prototype && Component.prototype.getInitialProps) { const message = `"${getDisplayName(Component)}.getInitialProps()" is defined as an instance method - visit https://err.sh/zeit/next.js/get-initial-props-as-an-instance-method for more information.` throw new Error(message) } } // when called from _app `ctx` is nested in `ctx` const res = ctx.res || (ctx.ctx && ctx.ctx.res) if (!Component.getInitialProps) { return null } const props = await Component.getInitialProps(ctx) if (res && isResSent(res)) { return props }
function renderDocument( Document: DocumentType, {...很多参数,太长省略} ): string { return ( "" + renderToStaticMarkup(, ) ) }
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/109451.html
摘要:中文站点中文站当前翻译版本为。注意将不能使用在子组件中。只能使用在页面中。替换路由组件默认将新推入路由栈中。以防服务端渲染发生错误,建议事件写在生命周期里。禁止文件路由默认情况,将会把下的所有文件匹配路由如渲染为如果你的项目使用 Next.js 是一个轻量级的 React 服务端渲染应用框架。 Next.js中文站点 http://nextjs.frontendx.cn Next.j...
摘要:原作者原链接基于多入口生成模板用于服务端渲染的方案及实战法律声明警告本作品遵循署名非商业性使用禁止演绎未本地化版本协议发布。这是什么背景现代化的前端项目中很多都使用了客户端渲染的单页面应用。 原作者:@LinuxerPHL原链接:基于 Webpack 4 多入口生成模板用于服务端渲染的方案及实战 法律声明 警告:本作品遵循 署名-非商业性使用-禁止演绎3.0 未本地化版本(CC BY-...
摘要:原作者原博文地址基于多入口生成模板用于服务端渲染的方案及实战法律声明警告本作品遵循署名非商业性使用禁止演绎未本地化版本协议发布。这是什么背景现代化的前端项目中很多都使用了客户端渲染的单页面应用。 原作者:@LinuxerPHL原博文地址: 基于 Webpack 4 多入口生成模板用于服务端渲染的方案及实战 法律声明 警告:本作品遵循 署名-非商业性使用-禁止演绎3.0 未本地化版本(...
摘要:不过这时的控制台会抛出这样一则警告提醒我们在服务端渲染时用来取代,并警告我们在时将不能用去混合服务端渲染出来的标签。综上所述,服务端和客户端都是需要路由体现的。我们画一下重点,意思很明确,就是为了服务端渲染而打造的。 抛砖引玉 在早几年前,jquery算是一个前端工程师必备的技能。当时很多公司采用的是java结合像velocity或者freemarker这种模板引擎的开发模式,页面渲染...
阅读 1310·2023-04-26 03:05
阅读 759·2021-10-19 11:43
阅读 3205·2021-09-26 09:55
阅读 823·2019-08-30 15:56
阅读 978·2019-08-30 15:44
阅读 1227·2019-08-30 15:44
阅读 2713·2019-08-30 14:23
阅读 3232·2019-08-30 13:13