随着互联网技术的发展,单页应用程序(SPA)成为了越来越流行的一种前端开发方式。但是,SPA 也存在一些问题,比如 SEO 不友好、首屏渲染时间长等。Vue.js 提供了一种解决方案:服务端渲染(Server-Side Rendering,SSR)。本文将介绍 Vue.js SSR 在 SPA 中的技术实现,并提供示例代码。
什么是服务端渲染?
服务端渲染指的是在服务器端将 Vue.js 组件渲染成 HTML 字符串,然后将该字符串发送给客户端,客户端接收到字符串后直接渲染。这种方式可以提高首屏渲染时间,也有利于 SEO。
Vue.js SSR 在 SPA 中的技术实现
Vue.js SSR 在 SPA 中的技术实现可以分为以下几个步骤:
- 创建 Vue.js 组件
- 创建服务器端入口文件
- 配置服务器端路由
- 配置 Webpack
- 创建客户端入口文件
- 在客户端入口文件中挂载组件
- 配置客户端路由
下面我们将逐一介绍这些步骤。
创建 Vue.js 组件
首先,我们需要创建一个 Vue.js 组件。这个组件可以是一个单文件组件(.vue),也可以是一个 JavaScript 文件。组件的内容可以根据实际需求进行编写。
示例代码:
// javascriptcn.com 代码示例 <template> <div> <h1>{{ title }}</h1> <p>{{ content }}</p> </div> </template> <script> export default { data() { return { title: 'Hello, Vue.js SSR!', content: 'This is an example of Vue.js SSR in SPA.', }; }, }; </script>
创建服务器端入口文件
接着,我们需要创建一个服务器端入口文件。这个文件将会导出一个函数,用于创建一个 Vue.js 应用实例。在这个函数中,我们需要将组件渲染成 HTML 字符串,并将该字符串发送给客户端。
示例代码:
// javascriptcn.com 代码示例 import Vue from 'vue'; import App from './App'; export default (context) => { const app = new Vue({ render: (h) => h(App), }); return new Promise((resolve, reject) => { const { url } = context; app.$router.push(url); app.$router.onReady(() => { const matchedComponents = app.$router.getMatchedComponents(); if (!matchedComponents.length) { return reject({ code: 404 }); } Promise.all( matchedComponents.map((component) => { if (component.asyncData) { return component.asyncData({ store: app.$store, route: app.$route, }); } }) ) .then(() => { context.state = app.$store.state; resolve(app); }) .catch(reject); }, reject); }) .then((app) => { const html = renderToString(app); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Vue.js SSR in SPA</title> </head> <body> <div id="app">${html}</div> <script> window.__INITIAL_STATE__ = ${JSON.stringify(context.state)}; </script> <script src="/static/js/app.js"></script> </body> </html>`; }) .catch((err) => { if (err && err.code === 404) { return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>404 Not Found</title> </head> <body> <h1>404 Not Found</h1> <p>The requested URL ${context.url} was not found on this server.</p> </body> </html>`; } console.error(err); return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Internal Server Error</title> </head> <body> <h1>500 Internal Server Error</h1> <p>Sorry, the server encountered an unexpected error.</p> </body> </html>`; }); };
配置服务器端路由
我们需要在服务器端为 Vue.js 应用配置路由。这个路由和客户端路由是不同的,因为服务器端路由需要根据 URL 路径来匹配组件。
示例代码:
// javascriptcn.com 代码示例 import Vue from 'vue'; import Router from 'vue-router'; import Home from './components/Home'; import About from './components/About'; import NotFound from './components/NotFound'; Vue.use(Router); export default () => { return new Router({ mode: 'history', routes: [ { path: '/', component: Home, }, { path: '/about', component: About, }, { path: '*', component: NotFound, }, ], }); };
配置 Webpack
我们需要使用 Webpack 来打包我们的应用。需要注意的是,在服务器端和客户端分别需要配置不同的 Webpack 配置文件。
服务器端 Webpack 配置文件示例代码:
// javascriptcn.com 代码示例 const path = require('path'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { target: 'node', entry: './src/server/index.js', output: { path: path.resolve(__dirname, '../dist/server'), filename: 'index.js', }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/, }, ], }, plugins: [new VueLoaderPlugin()], };
客户端 Webpack 配置文件示例代码:
// javascriptcn.com 代码示例 const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const VueLoaderPlugin = require('vue-loader/lib/plugin'); module.exports = { target: 'web', entry: './src/client/index.js', output: { path: path.resolve(__dirname, '../dist/client'), filename: 'js/app.js', publicPath: '/', }, module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/, }, ], }, plugins: [ new VueLoaderPlugin(), new HtmlWebpackPlugin({ template: './public/index.html', filename: 'index.html', inject: true, }), ], };
创建客户端入口文件
接着,我们需要创建一个客户端入口文件。这个文件将会创建一个 Vue.js 应用实例,并将其挂载到 HTML 页面中的某个元素上。
示例代码:
import Vue from 'vue'; import App from './App'; const app = new Vue({ render: (h) => h(App), }); app.$mount('#app');
在客户端入口文件中挂载组件
我们需要在客户端入口文件中为 Vue.js 应用实例添加一些额外的代码,以便它能够在客户端渲染时与服务器端渲染的 HTML 字符串进行协调。
示例代码:
// javascriptcn.com 代码示例 import Vue from 'vue'; import App from './App'; import createRouter from './router'; const router = createRouter(); const app = new Vue({ router, render: (h) => h(App), }); if (window.__INITIAL_STATE__) { app.$store.replaceState(window.__INITIAL_STATE__); } app.$mount('#app');
配置客户端路由
我们需要在客户端为 Vue.js 应用配置路由,并将其与服务器端路由保持同步。
示例代码:
// javascriptcn.com 代码示例 import Vue from 'vue'; import Router from 'vue-router'; import Home from './components/Home'; import About from './components/About'; import NotFound from './components/NotFound'; Vue.use(Router); export default () => { return new Router({ mode: 'history', routes: [ { path: '/', component: Home, }, { path: '/about', component: About, }, { path: '*', component: NotFound, }, ], }); };
总结
本文介绍了 Vue.js SSR 在 SPA 中的技术实现,并提供了示例代码。通过使用 SSR,我们可以提高 SPA 的首屏渲染速度,也可以让搜索引擎更好地索引我们的页面。如果你想要深入了解 SSR 的实现原理,可以进一步学习 Vue.js 官方文档中的相关内容。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/660f0005d10417a222f70b8d