什么是服务器端渲染 (SSR)

Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。

服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。

为什么使用服务器端渲染

1.更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面
2.更快的内容到达时间 (time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备
3.在对你的应用程序使用服务器端渲染 (SSR) 之前,你应该问的第一个问题是,是否真的需要它。这主要取决于内容到达时间 (time-to-content) 对应用程序的重要程度。例如,如果你正在构建一个内部仪表盘,初始加载时的额外几百毫秒并不重要,这种情况下去使用服务器端渲染 (SSR) 将是一个小题大作之举。然而,内容到达时间 (time-to-content) 要求是绝对关键的指标,在这种情况下,服务器端渲染 (SSR) 可以帮助你实现最佳的初始加载性能。

准备工作

1.搭建一个vue项目
2.安装的插件

cnpm install vue vue-server-renderer --save
cnpm install express --save
cnpm install cross-env -D

参考来源 https://ssr.vuejs.org/zh/guide/
参考文章链接https://blog.csdn.net/weixin_30732487/article/details/98167965

首先是main.js

我们为每个请求创建一个新的根 Vue 实例。这与每个用户在自己的浏览器中使用新应用程序的实例类似。如果我们在多个请求之间使用一个共享的实例,很容易导致交叉请求状态污染 (cross-request state pollution)
因此,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例:

// main.js
import Vue from 'vue'
import App from './App.vue'
import {createRouter} from './router'
import {createStore} from './store'
import { sync } from 'vuex-router-sync'Vue.config.productionTip = falseexport default function createApp () {// 创建 router 和 store 实例const router = createRouter()const store = createStore()// 同步路由状态(route state)到 storesync(store, router)const app = new Vue({router,store,render: h => h(App)})return {app, router, store}
}

entry-client.js客户端配置

客户端 entry 只需创建应用程序,并且将其挂载到 DOM 中:

// entry-client.js
import createApp from './main'const {app, router, store} = createApp()if (window.__INITIAL_STATE__) {store.replaceState(window.__INITIAL_STATE__)
}router.onReady(() => {// 添加路由钩子函数,用于处理 asyncData.// 在初始路由 resolve 后执行,// 以便我们不会二次预取(double-fetch)已有的数据。// 使用 `router.beforeResolve()`,以便确保所有异步组件都 resolve。router.beforeResolve((to, from, next) => {const matched = router.getMatchedComponents(to)const prevMatched = router.getMatchedComponents(from)// 我们只关心非预渲染的组件// 所以我们对比它们,找出两个匹配列表的差异组件let diffed = falseconst activated = matched.filter((c, i) => {return diffed || (diffed = (prevMatched[i] !== c))})if (!activated.length) {return next()}// 这里如果有加载指示器 (loading indicator),就触发Promise.all(activated.map(c => {if (c.asyncData) {return c.asyncData({ store, route: to })}})).then(() => {// 停止加载指示器(loading indicator)next()}).catch(next)})app.$mount('#app')
})

entry-server.js服务端配置

在 entry-server.js 中,我们可以通过路由获得与 router.getMatchedComponents() 相匹配的组件,如果组件暴露出 asyncData,我们就调用这个方法。然后我们需要将解析完成的状态,附加到渲染上下文(render context)中。

// entry-server.js
import createApp from './main'export default context => {return new Promise((resolve, reject) => {const { app, router, store } = createApp()router.push(context.url)router.onReady(() => {const matchedComponents = router.getMatchedComponents()if (!matchedComponents.length) {return reject({ code: 404 })}// 对所有匹配的路由组件调用 `asyncData()`Promise.all(matchedComponents.map(Component => {if (Component.asyncData) {return Component.asyncData({store,route: router.currentRoute})}})).then(() => {// 在所有预取钩子(preFetch hook) resolve 后,// 我们的 store 现在已经填充入渲染应用程序所需的状态。// 当我们将状态附加到上下文,// 并且 `template` 选项用于 renderer 时,// 状态将自动序列化为 `window.__INITIAL_STATE__`,并注入 HTML。context.state = store.stateresolve(app)}).catch(err => {throw err})}, reject)})
}

router.js路由配置

你可能已经注意到,我们的服务器代码使用了一个 * 处理程序,它接受任意 URL。这允许我们将访问的 URL 传递到我们的 Vue 应用程序中,然后对客户端和服务器复用相同的路由配置!

为此,建议使用官方提供的 vue-router。我们首先创建一个文件,在其中创建 router。注意,类似于 createApp,我们也需要给每个请求一个新的 router 实例,所以文件导出一个 createRouter 函数:

// router.js
import Vue from 'vue';
import Router from 'vue-router';Vue.use(Router);export function createRouter() {return new Router({mode: 'history',routes: [{path: '/',name: 'home',component: () => import('../views/Home.vue')},{path: '/about',name: 'about',component: () => import('../views/About.vue')}],});
}

store.js

// store.js
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)// 假定我们有一个可以返回 Promise 的
// 通用 API(请忽略此 API 具体实现细节)
import { fetchItem } from '../api'export function createStore () {return new Vuex.Store({state: {items: {}},actions: {fetchItem ({ commit }, id) {// `store.dispatch()` 会返回 Promise,// 以便我们能够知道数据在何时更新return fetchItem(id).then(item => {console.log(item)commit('setItem', { id, item })})}},mutations: {setItem (state, { id, item }) {Vue.set(state.items, id, item)}}})
}

vue.config

// vue.config.js
const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
const nodeExternals = require('webpack-node-externals')
const env = process.env
const isServer = env.RUN_ENV === 'server'console.log(isServer, env.RUN_ENV)module.exports = {publicPath: './',outputDir: `dist/${env.RUN_ENV}`,configureWebpack: {// 将 entry 指向应用程序的 server / client 文件entry: `./src/entry-${env.RUN_ENV}.js`,devtool: 'eval',// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),// 并且还会在编译 Vue 组件时,// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。target: isServer ? 'node' : 'web',// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)output: {libraryTarget: isServer ? 'commonjs2' : undefined},optimization: {splitChunks: isServer ? false : undefined},// https://webpack.js.org/configuration/externals/#function// https://github.com/liady/webpack-node-externals// 外置化应用程序依赖模块。可以使服务器构建速度更快,// 并生成较小的 bundle 文件。externals: isServer ? nodeExternals({// 不要外置化 webpack 需要处理的依赖模块。// 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,// 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单allowlist: /\.css$/}) : undefined,// 这是将服务器的整个输出// 构建为单个 JSON 文件的插件。// 服务端默认文件名为 `vue-ssr-server-bundle.json`// 客户端默认文件名为 `vue-ssr-client-manifest.json`plugins: [isServer ? new VueSSRServerPlugin() : new VueSSRClientPlugin(),]}
}

最后配置一个本地开发使用的server.js

// server.js
const http = require('http')
const path = require('path')
const fs = require('fs')
const express = require('express')
const {createBundleRenderer} = require('vue-server-renderer')
const serverBundle = require('./dist/server/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/client/vue-ssr-client-manifest.json')const app = express()
app.set('port', 8001);
// 静态文件目录指向dist文件夹
app.use(express.static(path.join(__dirname, './dist/client')))const renderer = createBundleRenderer(serverBundle, {runInNewContext: false,template: fs.readFileSync(path.resolve(__dirname, './index.html'), 'utf-8'),clientManifest
})app.get('*', (req, res) => {const context = {title: 'Hello SSR',url: req.url}renderer.renderToString(context, (err, html) => {if (err) {if (err.code === 404) {res.status(404).end('404 not found')} else {res.status(500).end(err.message)}} else {res.end(html)}})
})/*服务启动*/
http.createServer(app).listen(app.get('port'), function () {console.log('service start at ' + app.get('port'));
});

package.json添加下面命令

"start": "npm run build:server && npm run build:client && npm run service",
"build:client": "cross-env RUN_ENV=client vue-cli-service build",
"build:server": "cross-env RUN_ENV=server vue-cli-service build",
"service": "node server.js"

一个坑打包server时报错Server-side bundle should have one single entry file. Avoid using CommonsChu
在config.js里面添加下面几行代码

optimization: {splitChunks: isServer ? false : undefined
}

服务器端包应该有一个条目文件。避免在服务器配置中使用CommonsChunkPlugin。
猜测可能是因为vue-cli3配置了webpack4 里面的分包功能,所以,再弄得环境下给他禁止掉就好了
自己记录也可以给有兴趣的同学参考,不喜勿喷

vue ssr搭建服务端渲染项目相关推荐

  1. Vue SSR之服务端渲染

    目录 准备工作 开始折腾 1. 首先安装 ssr 支持 2. 增加路由test与页面 3. 在src目录下创建两个js: 4. 修改router配置. 5. 改造main.js 6. entry-cl ...

  2. 使用Nuxt.js搭建VUE应用的SSR(服务端渲染)

    Nuxt.js的介绍 Nuxt.js概述 nuxt.js简单的说是Vue.js的通用框架,最常用的就是用来作SSR(服务器端渲染) Vue.js是开发SPA(单页应用)的,Nuxt.js这个框架,用V ...

  3. 使用Nuxt.js框架开发(SSR)服务端渲染项目

    (SSR)服务端渲染的优缺点 优点: 1.前端耗时少,首屏加载速度快.因为后端拼接完了html,浏览器只需要直接渲染出来. 2.有利于SEO.因为在后端有完整的html页面,所以爬虫更容易爬取获得信息 ...

  4. SSR(服务端渲染)

    客户端渲染: 在服务端放了一个html 页面,里面有 客户端发起请求,服务端把页面(响应的是字符串)发送过去,客户端从上到下依次解析,如果在解析的过程中,发现ajax 请求,再次像服务器发送新的请求, ...

  5. vue服务端渲染——项目搭建、开发、生产环境的部署、浏览渲染、SEO优化

    几个月前,公司要求(服务端渲染)--用vue-ssr做了个服务端渲染,从起搭建.开发.部署.浏览器渲染到优化,希望对有需要的小伙伴有帮助,若是有不足之处,望指出,一起讨论学习.--几个月过去了,公司又 ...

  6. 手把手带你用next搭建一个完善的react服务端渲染项目(集成antd、redux、样式解决方案)

    前言 本文参考了慕课网jokcy老师的React16.8+Next.js+Koa2开发Github全栈项目,也算是做个笔记吧. 源码地址 github.com/sl1673495/n- 介绍 Next ...

  7. Node项目部署到阿里云服务器(ECS),以Nuxt.js服务端渲染项目为例

    1.前言 最近打算业余时间搭个网站,选择的技术栈为node+mongodb+Nuxt.js(基于vue,用于创建服务端渲染 (SSR) 应用),以下不会教科书式讲解,只是提供整体思路.参考资料以及关键 ...

  8. vue如何实现服务端渲染

    一.服务端渲染 服务器端渲染:后端先调用数据库,获得数据以后,将数据和页面元素进行拼装,组合成完整的 html页面,再直接返回给浏览器,以用户浏览,也就是说明数据和页面是由服务器所去完成,返回浏览器展 ...

  9. SSR(服务端渲染)于CSR(客户端渲染)

    SSR (Server Side Rendering,服务端渲染) 希望的是:服务端第一次只把渲染好的 HTML 发给客户端,这样客户端就能直接显示出来网页的样式,首次绘制(First Paint)就 ...

最新文章

  1. xcode 消除警告
  2. python3 mysql错误 pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
  3. 刺激(codevs 1958)
  4. sql left join用法_一张图看懂 SQL 的各种 join 用法
  5. 阿里工作流引擎_免费开源,一款快速开发模块化脚手架,含工作流引擎
  6. Struts1 生成Action请求的几种方式分析
  7. 微课|中学生可以这样学Python(2.2.2节+2.2.5节):关系运算符和集合运算符
  8. 一文62页PPT读懂中国供应链金融
  9. 正厚软件 | 为什么要转行IT?
  10. Android 图片波浪动画,Android水纹波浪动画
  11. 音频小波去噪(sym8和db)后语谱图对比标注
  12. 给定一个整数,判断它能否被3,5,7整除
  13. Autodesk 3dsmax 下载!亲测有效!
  14. 选煤厂工艺流程图和设备流程图
  15. H5页面布局之图片液态化(自适应)处理简述
  16. 如何为HBuilderX安装sass?HBuilderX中如何使用sass?
  17. Python从父目录的其他文件夹中导入模块的解决方案(亲测有效)
  18. jQuery项目案例(一):电影排行榜项目
  19. php 调用百度AI实现图像审核功能
  20. 配网终端加密模块国密算法芯片

热门文章

  1. githug通关部分黏贴(git代码练习)
  2. 栈帧ebp,esp详解
  3. 利用OpenCV实现图像矫正
  4. 《攻守道》笔记(3)
  5. matlab 三分之一倍频程,三分之一倍频程谱
  6. Adobe Acrobat XI Pro 11.x 安装指南
  7. 电脑计算机打不开显示远程过程,Win10打不开图片提示“远程过程调用失败”的解决方案...
  8. 论文里引用专利参考文献怎么写?
  9. JS JQuery 操作: Json转 Excel 下载文件
  10. 怎么调节PDF文件的尺寸大小?