下面是关于“vuecli项目构建SSR服务端渲染的实现”的完整攻略:
1. 什么是SSR?
SSR全称Server Side Rendering(服务端渲染),意思是将页面在服务器端进行渲染,然后再将已渲染的页面传输给客户端展示出来。
SSR的好处:
- 更快的页面渲染速度,减少白屏时间
- 更好的SEO(搜索引擎优化)
- 更好的用户体验
2. Vue CLI 3 如何构建 SSR 服务端渲染应用?
Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供了项目的创建、编译、运行、构建等一系列功能的工具。
如果你想要构建一个 SSR 应用,可以使用Vue CLI脚手架提供的插件和配置进行构建。
2.1 安装 Vue CLI 3
首先,你需要安装 Vue CLI 3。在命令行中输入:
npm install -g @vue/cli
安装成功后,可以通过输入 vue --version
命令查看版本号,确保安装成功。
2.2 创建一个 SSR 应用
使用 Vue CLI 创建一个 SSR 应用非常简单,只需要在命令行中输入以下命令:
vue create my-ssr-app
其中,my-ssr-app
为创建的项目名称,你可以根据自己的需要进行修改。
在创建项目时,会有一个提示让你选择“需要预安装一些特性吗?”。这里我们选择 Manually select features
,然后按下回车键。
在下一步中,除了选择 Babel
和 Router
这两个基础选项外,我们还需要选择 Server-Side Rendering (SSR)
和 Vuex
这两个选项。
最后,按照提示完成项目的创建。
2.3 配置 SSR
项目创建完成后,需要进一步配置才能使其支持 SSR。
2.3.1 添加服务器文件
首先,在项目的根目录下创建一个 server.js
文件,并添加以下代码:
const fs = require('fs')
const path = require('path')
const express = require('express')
const server = express()
const resolve = file => path.resolve(__dirname, file)
const bundleRenderer = require('vue-server-renderer').createBundleRenderer(
resolve('./dist/server-bundle/vue-ssr-server-bundle.json'), {
runInNewContext: false,
template: fs.readFileSync(resolve('./public/index.html'), 'utf-8')
}
)
server.use('/dist', express.static(resolve('./dist')))
server.get('*', (req, res) => {
const context = {
title: 'Vue SSR Demo',
url: req.url
}
bundleRenderer.renderToString(context, (err, html) => {
if (err) {
console.error(err)
res.status(500).end('Internal Server Error')
return
}
res.end(html)
})
})
const port = process.env.NODE_ENV === 'production' ? 80 : 8080
server.listen(port, () => {
console.log(`Server started at http://localhost:${port}`)
})
其中,server.js
文件定义了一个节点服务器,并使用 vue-server-renderer
提供的 createBundleRenderer
创建了一个渲染器实例。在 server.get
里面,通过 vue-server-renderer
提供的 renderToString
进行服务端渲染。
2.3.2 添加打包配置
为了使打包生成的文件可以在服务器上运行,我们需要添加一些打包配置。
打开根目录下的 vue.config.js
文件,添加以下配置:
const path = require('path')
module.exports = {
configureWebpack: {
entry: {
app: './src/entry-server.js'
},
output: {
libraryTarget: 'commonjs2'
},
target: 'node',
resolve: {
alias: {
'@': path.join(__dirname, './src')
}
}
},
chainWebpack: config => {
config.plugins.delete('html')
config.plugins.delete('preload')
config.plugins.delete('prefetch')
config
.entry('app')
.clear()
.add('./src/entry-client.js')
.end()
config.output.filename('assets/js/[name].js')
config.output.chunkFilename('assets/js/[name].js')
config.optimization.splitChunks(false)
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.optimizeSSR = false
return options
})
}
}
其中,configureWebpack
中的配置项用于配置 Webpack,chainWebpack
是链式操作,可以修改 Webpack 中的默认配置。配置项的具体含义可以查看 Vue SSR 文档。
2.3.3 修改入口文件
在 src
目录下分别创建 entry-client.js
和 entry-server.js
文件,其中 entry-client.js
的内容默认已经生成,不需要修改。而 entry-server.js
需要添加以下内容:
import { createApp } from './main'
export default context => {
const app = createApp()
// 设置服务器端 router 的位置
const router = app.$router
router.push(context.url)
context.meta = app.$meta()
return new Promise((resolve, reject) => {
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
if (!matchedComponents.length) {
return reject({ code: 404 })
}
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({
store: app.$store,
route: router.currentRoute
})
}
})).then(() => {
context.state = app.$store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
3. 示例说明
接下来给出两个示例说明:
3.1 实例1
假设你需要从服务器获取一些数据,然后在页面中进行展示。你可以在组件生命周期函数中通过 axios
库发起请求,获取数据,然后在渲染函数中使用该数据。
在服务器端渲染中,由于没有浏览器环境,页面组件不会像在浏览器中一样被实例化和挂载到页面中,所以在服务器端需要在渲染函数执行之前先获取数据,并将这些数据提供给组件。
// Home.vue
<script>
export default {
name: 'Home',
asyncData ({ store }) {
return store.dispatch('fetchData') // 从服务器获取数据
},
computed: {
items () {
return this.$store.state.items // 获取数据
}
},
template: `<div>{{ items }}</div>`
}
</script>
其中,asyncData
是一个静态方法,它会在组件被实例化之前调用,从服务器获取数据后,将数据存储到 Vuex store 中,然后在组件的 computed
中以数据的形式注入到组件中。
3.2 实例2
假设你需要在服务器端进行一些路由控制,比如根据用户的权限判断是否能够访问某个页面。你可以在渲染函数执行之前先验证路由信息,然后再渲染页面。
// Auth.vue
<script>
export default {
name: 'Auth',
asyncData ({ store, route }) {
if (route.path === '/admin' && !store.state.isAuthenticated) { // 判断用户是否已登录
return Promise.reject({ code: 401, message: 'Unauthorized' }) // 如果用户未登录,跳转到401页面
}
},
template: `<div>Welcome, Admin!</div>`
}
</script>
在 asyncData
函数中,获取用户的登录状态,并根据登录状态判断用户是否有权限访问此页面。如果用户未登录,我们可以返回一个 promise,然后在渲染函数执行之后,将 promise.reject
返回的错误对象交给错误处理程序处理,最终跳转到相应的错误页面。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vuecli项目构建SSR服务端渲染的实现 - Python技术站