在现代 web 应用中,越来越多的应用选择采用单页面应用(SPA)的架构,SPA 应用是指通过 AJAX 等技术实现在一个页面中展示多个内容/页面的应用。相较于传统的多页面应用,SPA 应用能够带来更好的用户体验和性能。
但 SPA 应用也有一个缺点,就是需要在客户端进行渲染,只有在 SPA 应用首次加载时才能获取到全部所需的数据和资源,因此需要先加载页面骨架并等待 JavaScript 完全加载和运行,在这个过程中,用户可能会面临白屏或者长时间的加载等待,从而影响用户体验。
为了解决 SPA 应用的性能瓶颈问题,同构渲染技术应运而生。同构渲染技术是指在服务端生成 HTML 页面,并且在客户端保留 SPA 动态化效果的技术方案,也被称之为服务器端渲染(Server Side Rendering,SSR)。
实现同构渲染的方式
1. 基于 Node.js 的后端渲染
在 SPA 应用中,我们可以通过将路由映射到客户端的路由和服务端的路由来实现同构渲染,即客户端和服务端可以共享相同的路由配置和渲染逻辑。
在服务端渲染中,我们可以使用 Node.js 等服务端 JavaScript 脚本引擎来解释和执行 JavaScript 代码,以此达到完全渲染 HTML 的目的。Node.js 提供了多个服务器端渲染框架,包括 Next.js、Nuxt.js 等,这些框架可以帮助我们在后端进行同构渲染,提高了网站的 SEO 优化以及性能。
2. 基于静态页面生成器的渲染
另一种在前端实现同构渲染的方式是基于静态页面生成器,这种方式相对于基于 Node.js 的后端渲染的方案更加简洁和灵活。
我们可以使用 Gatsby、Hugo、Jekyll 等静态页面生成器,在项目打包阶段部署到服务端时生成静态 HTML 页面。这些页面可以完全包含 SPA 的内容,用户可以在页面初次加载时看到完整内容,并且不受 SPA 应用加载的限制。
实现同构渲染的步骤
为了在 SPA 应用中实现同构渲染,我们需要经过以下几个步骤:
1. 创建一个基于路由的服务端代码
在服务端代码中,我们需要创建一个基于路由的应用程序,该应用程序用来处理各种路由情况下的页面渲染逻辑。如果需要将所有页面都进行服务端渲染,可以创建一个基于路由的通用路由,该路由会根据请求的路由和路径来确定服务端渲染所需的页面和数据。
2. 在服务端运行代码
在服务端运行创建的服务端代码,生成 HTML 页面,并将其发送到浏览器端。
3. 客户端进行二次渲染
一旦 HTML 页面被浏览器接收,客户端 JavaScript 代码将被下载和执行。这时,React、Vue 或 Angular 等框架会检测 DOM 对象并将其转化为虚拟 DOM 对象,并进行二次渲染。在渲染完成后,SPA 应用会具有所有交互功能,并且继续处理其他路由。
示例代码
基于 React 实现同构渲染
React 技术栈提供了完整的同构渲染解决方案,下面是一个基于 React 和 Express 开发的同构渲染示例。
服务端代码样例:index.js
// javascriptcn.com 代码示例 import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import App from './src/App'; const app = express(); app.get('/', (req, res) => { const html = renderToString(<App />); res.send( ` <!DOCTYPE html> <html> <head> <title>React SSR</title> </head> <body> <div id="root">${html}</div> <script src="/client.js"></script> </body> </html> ` ); }); app.get('/api/data', (req, res) => { res.json({ message: 'Hello World!' }); }); app.listen(3000, () => { console.log('Server running at http://localhost:3000/'); });
客户端代码样例:index.js
import React from 'react'; import { hydrate } from 'react-dom'; import App from './src/App'; hydrate(<App />, document.getElementById('root'));
基于 Vue 实现同构渲染
Vue 技术栈也提供了类似的同构渲染解决方案,下面是一个基于 Express 和 Vue.js 的同构渲染示例。
服务端代码样例:index.js
// javascriptcn.com 代码示例 const express = require('express'); const fs = require('fs'); const path = require('path'); const vueServerRenderer = require('vue-server-renderer'); const app = express(); const renderer = vueServerRenderer.createRenderer({ template: fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf-8') }); const createApp = require('./src/app'); app.get('/api/data', (req, res) => { res.json({ message: 'Hello World!' }); }); app.get('*', (req, res) => { const context = { url: req.url }; const app = createApp(context); renderer.renderToString(app, (err, html) => { if (err) { console.error(err); res.status(500).end('Internal Server Error'); return; } res.end(html); }); }); app.listen(3000, () => { console.log('Server running at http://localhost:3000/'); });
客户端代码样例:entry-client.js
import Vue from 'vue'; import createApp from './app'; const { app, router } = createApp(); router.onReady(() => { app.$mount('#app'); });
总结
同构渲染技术在 SPA 应用中可以提供更好的用户体验和性能,过去几年中它已经成为了一种流行的前端技术。无论你选择什么样的实现方式,同构渲染都是一种需要深入掌握的前端技能,它可以在很大程度上提高 SPA 应用的渲染性能和 SEO 等方面的优化工作。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6538e97e7d4982a6eb213bc4