vue ssr搭建服务端渲染项目
什么是服务器端渲染 (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搭建服务端渲染项目相关推荐
- Vue SSR之服务端渲染
目录 准备工作 开始折腾 1. 首先安装 ssr 支持 2. 增加路由test与页面 3. 在src目录下创建两个js: 4. 修改router配置. 5. 改造main.js 6. entry-cl ...
- 使用Nuxt.js搭建VUE应用的SSR(服务端渲染)
Nuxt.js的介绍 Nuxt.js概述 nuxt.js简单的说是Vue.js的通用框架,最常用的就是用来作SSR(服务器端渲染) Vue.js是开发SPA(单页应用)的,Nuxt.js这个框架,用V ...
- 使用Nuxt.js框架开发(SSR)服务端渲染项目
(SSR)服务端渲染的优缺点 优点: 1.前端耗时少,首屏加载速度快.因为后端拼接完了html,浏览器只需要直接渲染出来. 2.有利于SEO.因为在后端有完整的html页面,所以爬虫更容易爬取获得信息 ...
- SSR(服务端渲染)
客户端渲染: 在服务端放了一个html 页面,里面有 客户端发起请求,服务端把页面(响应的是字符串)发送过去,客户端从上到下依次解析,如果在解析的过程中,发现ajax 请求,再次像服务器发送新的请求, ...
- vue服务端渲染——项目搭建、开发、生产环境的部署、浏览渲染、SEO优化
几个月前,公司要求(服务端渲染)--用vue-ssr做了个服务端渲染,从起搭建.开发.部署.浏览器渲染到优化,希望对有需要的小伙伴有帮助,若是有不足之处,望指出,一起讨论学习.--几个月过去了,公司又 ...
- 手把手带你用next搭建一个完善的react服务端渲染项目(集成antd、redux、样式解决方案)
前言 本文参考了慕课网jokcy老师的React16.8+Next.js+Koa2开发Github全栈项目,也算是做个笔记吧. 源码地址 github.com/sl1673495/n- 介绍 Next ...
- Node项目部署到阿里云服务器(ECS),以Nuxt.js服务端渲染项目为例
1.前言 最近打算业余时间搭个网站,选择的技术栈为node+mongodb+Nuxt.js(基于vue,用于创建服务端渲染 (SSR) 应用),以下不会教科书式讲解,只是提供整体思路.参考资料以及关键 ...
- vue如何实现服务端渲染
一.服务端渲染 服务器端渲染:后端先调用数据库,获得数据以后,将数据和页面元素进行拼装,组合成完整的 html页面,再直接返回给浏览器,以用户浏览,也就是说明数据和页面是由服务器所去完成,返回浏览器展 ...
- SSR(服务端渲染)于CSR(客户端渲染)
SSR (Server Side Rendering,服务端渲染) 希望的是:服务端第一次只把渲染好的 HTML 发给客户端,这样客户端就能直接显示出来网页的样式,首次绘制(First Paint)就 ...
最新文章
- xcode 消除警告
- python3 mysql错误 pymysql.err.OperationalError: (2013, 'Lost connection to MySQL server during query')
- 刺激(codevs 1958)
- sql left join用法_一张图看懂 SQL 的各种 join 用法
- 阿里工作流引擎_免费开源,一款快速开发模块化脚手架,含工作流引擎
- Struts1 生成Action请求的几种方式分析
- 微课|中学生可以这样学Python(2.2.2节+2.2.5节):关系运算符和集合运算符
- 一文62页PPT读懂中国供应链金融
- 正厚软件 | 为什么要转行IT?
- Android 图片波浪动画,Android水纹波浪动画
- 音频小波去噪(sym8和db)后语谱图对比标注
- 给定一个整数,判断它能否被3,5,7整除
- Autodesk 3dsmax 下载!亲测有效!
- 选煤厂工艺流程图和设备流程图
- H5页面布局之图片液态化(自适应)处理简述
- 如何为HBuilderX安装sass?HBuilderX中如何使用sass?
- Python从父目录的其他文件夹中导入模块的解决方案(亲测有效)
- jQuery项目案例(一):电影排行榜项目
- php 调用百度AI实现图像审核功能
- 配网终端加密模块国密算法芯片
热门文章
- githug通关部分黏贴(git代码练习)
- 栈帧ebp,esp详解
- 利用OpenCV实现图像矫正
- 《攻守道》笔记(3)
- matlab 三分之一倍频程,三分之一倍频程谱
- Adobe Acrobat XI Pro 11.x 安装指南
- 电脑计算机打不开显示远程过程,Win10打不开图片提示“远程过程调用失败”的解决方案...
- 论文里引用专利参考文献怎么写?
- JS JQuery 操作: Json转 Excel 下载文件
- 怎么调节PDF文件的尺寸大小?