vue ssr服务端渲染小白解惑

>初学ssr入坑

初学vue服务端渲染疑惑非常多,我们大部分前端都是半路出家,上手都是前后端分离,对服务端并不了解,不说java、php语言了,连node服务都还没搞明白,理解服务端渲染还是有些困难的;

网上有非常多的vue服务渲染的入门案例,但看了很久,很多,还是一头雾水,搞不明白这些文件和关键字的联系和意思:

server.js

entrt-client.js

server-js

built-server-bundle.js

vue-ssr-server-bundle.json

vue-ssrclientmanifest.json

createBundleRenderer

clientManifest

这篇内容会按照 基础服务端渲染--vue实例渲染--加入vueRouter--加入vueX的顺序入坑,后续应该还有--开发模式--seo优化--部分渲染,这里先不挖那么多坑了;

>基础服务端渲染

顾名思义,得启个服务:(建个新项目,不要用vue-cli)

//server.js

const express = require('express');

const chalk = require('chalk');//加个chalk就是console好看点。。

const server = express();

server.get('*', (req, res) => {

res.set('content-type', "text/html");

res.end(`

Hello

`)

})

server.listen(8080,function(){

let ip = getIPAdress();

console.log(`服务器开在:http://${chalk.green(ip)}:${chalk.yellow(8080)}`)

})

function getIPAdress(){//node下的os模块可以拿到启动该文件的服务端的部分信息

var interfaces = require('os').networkInterfaces();

for (var devName in interfaces) {

var iface = interfaces[devName];

for (var i = 0; i < iface.length; i++) {

var alias = iface[i];

if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {

return alias.address;

}

}

}

}

启动 node server.js

再看页面 正常,这就是最基础的服务端渲染

其实就是一个get请求,返回一个字符串,浏览器默认展示返回结果;

然而对于这个字符串的解析还不明确,什么意思,比如:

去掉这句话,页面就成了这样,原因不深究,自己百度

>加入vue实例

跳过官网说的built-server-bundle.js应用,意思就是不用管这个文件了,只是一个过渡文件,项目中也不会用到。直接使用createBundleRenderer方法,直接用vue-ssr-server-bundle.json;

看下现在的目录结构:

新增了5个文件;有关客户端的配置entry-client.js不是必须的,这里先不管;

app.js是用来创建vue实例的;

entry-server.js是用来创建生成vue-ssr-server-bundle.json(需要用到app.js)所需的配置配件;是给webpack.server.config.js用的;

webpack.server.config.js是用来生成vue-ssr-server-bundle.json的;

vue-ssr-server-bundle.json是给server.js中的createBundleRenderer用的。

//app.js

import Vue from 'vue'

import Vue from './App.vue'//这里一定要写上.vue,不然会匹配到app.js,require不区分大小写0.0

export default createApp=function(){

return new Vue({

render:h => h(App)

})

}

一个createApp生成一个vue实例;

//App.vue

这是个app

export default {}

还没用到

//weback-base.config.js

const path = require('path')

const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {

output:{

path:path.resolve(__dirname,'./dist'),

filename:'build.js',

},

module: {

rules: [

{

test:/\.js$/,

use: {

loader: 'babel-loader',

options: {

presets: ['@babel/preset-env']

}

},

exclude:[/node_modules/,/assets/]

},

{

test:/\.vue$/,

use:['vue-loader']

}

]

},

resolve: {

alias:{

'@':path.resolve(__dirname,'../')

},

extensions:['.js','.vue','.json']

},

plugins:[

new VueLoaderPlugin()

]

}

有关webpack配置不啰嗦

//webpack.server.config.js用来生成vue-ssr-server-bundle.json

const merge = require('webpack-merge')

const baseConfig = require('./webpack.base.js')

const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')

module.exports = merge(baseConfig, {

entry: './entry-server.js',

// 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),

// 并且还会在编译 Vue 组件时,

// 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。

target: 'node',

// 对 bundle renderer 提供 source map 支持

devtool: 'source-map',

// 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)

output: {

libraryTarget: 'commonjs2'

},

// 这是将服务器的整个输出

// 构建为单个 JSON 文件的插件。

// 默认文件名为 `vue-ssr-server-bundle.json`

plugins: [

new VueSSRServerPlugin()

]

})

这个配置哪都能找到,重点是VueSSRServerPlugin这个插件,生成vue-ssr-server-bundle.json全靠它,去掉的话生成的是built-server-bundle.js;关于merge插件,libraryTarget,target配置问题自己百度webpack去0.0;

//entry-server.js

import { createApp } from './src/app'

export default context => {

return createApp()

}

固定写法,返回一个函数供createBundleRenderer使用;

生成vue-ssr-server-bundle.json

到目前为止安装的插件有:

自己手动一个一个装就行了。

生成vue-ssr-server-bundle.json,使用webpack命令

一切都手动,熟悉webpack;

修改server.js

const express = require('express');

const chalk = require('chalk');

const server = express();

const serverBundle = require('./dist/vue-ssr-server-bundle.json')//**新增**//

const renderer = require('vue-server-renderer').createBundleRenderer(serverBundle,{

runInNewContext: false, // 看名字也知道是生成某个新的Context对象,默认是true,改成false理解为某种缓存机制,提高服务器效率

template: require('fs').readFileSync('./index.html', 'utf-8'),

})//**新增**//

server.get('*', (req, res) => {

//res.set('content-type', "text/html");

//res.end(`

//

//

//

Hello

//

//

你好

//

//

//改成下面这样

const context = {//这里的参数现在还没用,但这个对象还是得用,要做renderToString的参数

url:req.url

}

renderer.renderToString(context, (err, html) => {

if (err) {

res.status(500).end('Internal Server Error')

return

} else {

res.end(html)

}

})

`)

})

server.listen(8080,function(){

let ip = getIPAdress();

console.log(`服务器开在:http://${chalk.green(ip)}:${chalk.yellow(8080)}`)

})

function getIPAdress(){//node下的os模块可以拿到启动该文件的服务端的部分信息,细节自己去node上面查

var interfaces = require('os').networkInterfaces();

for (var devName in interfaces) {

var iface = interfaces[devName];

for (var i = 0; i < iface.length; i++) {

var alias = iface[i];

if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {

return alias.address;

}

}

}

}

试一蛤:node server.js

正常,箭头指的地方官网有解释。别忘了inde.html中加入一行注释:

后续修改title,meta头部都是通过类似的注释方式,原理就是正则匹配替换字符串-。-;

>加入路由vue-router

新增几个文件

需要修改的文件有:

App.vue//加个router-view就行

//app.js

import Vue from 'vue'

import App from './App.vue'

import router from './router'

export function createApp(){

const app = new Vue({

router,

render:h => h(App)

})

return {app,router}

}

把app实例和router都抛出去,给entry-server.js用

// entry-server.js

import { createApp } from './src/app'

export default context => {

//这里用promise的原因有很多,其中有一个就是下面这个onReady方法是异步的。createBundleRenderer支持promise

return new Promise((resolve, reject) => {

const { app, router } = createApp()

router.push(context.url)

router.onReady(() => {//onReady方法还有getMatchedComponents方法还是需要了解一下

const matchedComponents = router.getMatchedComponents()

if (!matchedComponents.length) {

return reject({ code: 404 })

}

resolve(app)

}, reject)

})

}

最后看一下router.js

//router.js

import Vue from 'vue'

import VueRouter from 'vue-router'

//页面要先声明后使用,不要问为什么

import home from './pages/home'

import store from './pages/store'

Vue.use(VueRouter)

export default new VueRouter({

mode: 'history',

routes:[

{path:'/',name:'home',component:home},

{path:'/store',name:'store',component:store},

]

})

再看一下两个页面的代码;

//store.vue

this is store

export default {}

改的差不多了,试一哈:

重新打个包webpack --config webpack.server.js

启动node server

>entry-client.js是干啥的

到目前为止还没用到entry-client.js叫客户端配置,不着急使用,先做个测试,写点逻辑试试:

修改下store.vue

//store.vue

{{msg}}

export default {

data(){

msg:'this is store'

},

created(){

this.msg = 'this is created'

},

mounted(){

this.msg = 'this is mounted'

},

methods: {

run(){

alert('this is methods')

}

}

}

看这个样子页面最终展示的结果应该是this is mounted,然而结果是这样的:

很好解释,服务端对于钩子函数的理解也是很正确的,created会在页面返回之前执行,而mounted是在vue实例成型之后执行,就是页面渲染后,这个是要在客户端才会执行,可是为什么页面出来了没有执行mounted,而且run的点击事件没有生效;

看看页面:

一个js文件都没加载,怎么执行逻辑,就是个静态页面0.0;

这时候entry-client.js就出场了

新增两个文件

//entry-client.js

import { createApp } from './src/app.js';

const { app } = createApp();

app.$mount('#app');

基本配置;

//webpack.client.config.js

const merge = require('webpack-merge')

const baseConfig = require('./webpack.base.config.js')

const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')

module.exports = merge(baseConfig, {

entry: './entry-client.js',

optimization:{

runtimeChunk:true

},

plugins: [

// 此插件在输出目录中

// 生成 `vue-ssr-client-manifest.json`。

new VueSSRClientPlugin(),

]

})

这个地方重点除了VueSSRClientPlugin生成vue-ssr-client-manifest.json外,optimization是webpack4产物,用来分离生成共公chunk,配置还算复杂,可以看下这里webpack4 optimization总结

修改下server.js

//server.js

const express = require('express');

const chalk = require('chalk');

const server = express();

const serverBundle = require('./dist/vue-ssr-server-bundle.json')

const clientManifest = require('./dist/vue-ssr-client-manifest.json')//新增

const renderer = require('vue-server-renderer').createBundleRenderer(serverBundle,{

runInNewContext: false, // 推荐

template: require('fs').readFileSync('./index.html', 'utf-8'),

clientManifest // //新增

})

server.get('*', (req, res) => {

res.set('content-type', "text/html");

const context = {

url:req.url

}

renderer.renderToString(context, (err, html) => {

if (err) {

res.status(500).end('Internal Server Error')

return

} else {

res.end(html)

}

})

})

server.listen(8080,function(){

let ip = getIPAdress();

console.log(`服务器开在:http://${chalk.green(ip)}:${chalk.yellow(8080)}`)

})

function getIPAdress(){//node下的os模块可以拿到启动该文件的服务端的部分信息,细节自己去node上面查

var interfaces = require('os').networkInterfaces();

for (var devName in interfaces) {

var iface = interfaces[devName];

for (var i = 0; i < iface.length; i++) {

var alias = iface[i];

if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {

return alias.address;

}

}

}

}

打包下:webpack --config webpack.client.config.js

node server 一下,看看页面

js有了,可是为什么还不行,不能点0.0;

看看。奥报错了

读取不到静态文件;

修改server.js加个静态文件托管:

再看看

事件也有了,页面没变化,console一下,发现值其实已经变了,

看看代码,是这里忘加return了;

>加入vuex

加个sotre.js

// store.js

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({

state: {

msg: ''

},

actions: {

setMsg ({ commit }, val) {

commit('setMsg', val)

}

},

mutations: {

setMsg (state, val) {

Vue.set(state, 'msg', val)//关键

}

}

})

很基础的逻辑,关键在Vue.set这个方法,增加响应式;

修改下app.js

//app.js

import Vue from 'vue'

import App from './App.vue'

import router from './router'

import store from './store'//加个store就行了

export function createApp(){

const app = new Vue({

router,

store,

render:h => h(App)

})

return {app,router}

}

store.vue改成这样

{{msg}}

export default {

data(){},

created(){

this.$store.dispatch('setMsg','this is created')

},

computed:{

msg(){

return this.$store.state.msg;

}

},

mounted(){

this.$store.dispatch('setMsg','this is mounted')

},

methods: {

run(){

alert('this is methods')

}

}

}

重新打个包,想一下,修改页面的话只需要重新打包client,如果修改了app.js两个就要都重新打包了;

node server 一下

这回总算完成了;

>总结

服务端渲染东西还是挺多的,涉及领域也非常广,比如vue,webpack,node,它们的生态圈都大的可怕,需要学习东西非常多,

坑又多,又大,又深,后面还有很多问题要解决:

异步数据加载;//html返回前先渲染一部分接口拿到的数据

怎么做seo优化;//做服务端渲染的重要原因,处理异步数据加载问题也是为了这个

缓存怎么加;

开发环境搭建;//你并不希望每改一行代码就重新手动打个包,重启下服务吧0.0

还有怎么实现部分页面ssr;//一个项目不可能所有页面都服务端渲染,太耗性能,服务器压力大呀;

java vue 服务端渲染_vue ssr服务端渲染小白解惑相关推荐

  1. 服务端渲染(SSR) 和客户端渲染(CSR)

    一.服务端渲染(SSR)是什么 用户使用的浏览器浏览的都是一些没有复杂逻辑的.简单的页面,这些页面都是在后端将 html 拼接好的,然后返回给前端完整的 html 文件,浏览器拿到这个 html 文件 ...

  2. vue依赖缓存_Vue SSR服务端渲染之数据缓存

    当咱们在作vue的服务器端渲染时,可能会碰到各类各样的坑,内存泄露就是其中的一种.固然,致使内存泄露的缘由有不少,不合理使用Axios也是其中一种,那下面我给你们介绍一下如何有效的避免请求中的内存泄露 ...

  3. vue用户行为收集_vue 实现移动端键盘搜索事件监听

    1.首先注意,input的type="serch" 2.监听keypress事件 (1)KeyDown.KeyUp 事件 这些事件是当一个对象具有焦点时按下 ( KeyDown ) ...

  4. vue上传录音_vue实现移动端input上传视频、音频

    vue移动端input上传视频.音频,供大家参考,具体内容如下 html部分 现场视频 上传视频 现场音频频 上传音频 js部分 getVideo (ev, typer) { let taht = t ...

  5. vue 图片宫格_vue实现移动端九宫格布局

    九宫格 *{ margin: 0px; padding: 0px; } .sudoku_row{ display: flex; align-items: center; width:100%; fle ...

  6. vuejs对象更新渲染_vue 数组和对象渲染问题

    vue 数组和对象渲染问题 最近项目有点忙碌,遇到好多问题都没有总结(╥﹏╥),在开发过程中,取vuex中的数组渲染完成之后,再次修改数组的值,数据更新了,但是视图并没有更新.以为是数组更新的问题,后 ...

  7. 什么是服务器渲染(SSR)、客户端渲染

    什么是服务器渲染.客户端渲染 一.介绍 1.1 服务端渲染(SSR) 简述:     又称为后端渲染,服务器端在返回html之前,在html特定的区域特定的符号里用数据填充,再给客户端,客户端只负责解 ...

  8. java vue 服务端渲染_vue服务端渲染缓存应用详解

    服务端渲染简介 服务端渲染不是一个新的技术:在 Web 最初的时候,页面就是通过服务端渲染来返回的,用 PHP 来说,通常是使用 Smarty 等模板写模板文件,然后 PHP 服务端框架将数据和模板渲 ...

  9. Vuex 数据流管理及Vue.js 服务端渲染(SSR)

    Vuex 数据流管理及Vue.js 服务端渲染(SSR)项目见:https://github.com/smallSix6/fed-e-task-liuhuijun/tree/master/fed-e- ...

最新文章

  1. 【效率】如何有效提问
  2. mysql update delete_MySQL中UPDATE与DELETE语句的使用教程
  3. SAP Commerce开发时的Spring学习要点记录
  4. Javascript 事件冒泡处理
  5. 【uoj#142】【UER #5】万圣节的南瓜灯 乱搞+并查集
  6. PVFS2 1.4.0的安装、配置与性能测试
  7. 为什么莫名其妙的就被调用了
  8. HDFS概述(6)————用户手册
  9. thread.sleep会释放锁吗_面试 LockSupport.park()会释放锁资源吗?
  10. jni如何判断两个jobject是否为同一个java对象
  11. 表格结构标签 thead tbody
  12. 怎样用excel剔除异常数据_注意避坑 | 这10个错误的Excel使用方法别再用了!
  13. python re 正则提取中文
  14. win7系统换主板后无法进系统,卡logo,无法进安全模式的解决方案
  15. 主板没有rgb接口怎么接灯_DIY只为玩游戏?主板配上RGB灯让机箱发光
  16. html页面不能放大缩小,互联网常识:html怎么禁止页面放大缩小
  17. 如何领取1024勋章
  18. java中driver是什么意思_java.sql.SQLException: com.sqljdbc.Driver什么意思啊?
  19. 家乡主题网页设计代码 旅游主题网页设计 html静态网页设计制作 dw静态网页成品模板素材网页 web前端网页设计与制作 div静态网页设计
  20. “有些时候,想要赢得天才的尊重,就只能违抗他” |【经纬低调分享】

热门文章

  1. Python数据容器:list + set + tuple + dict + str 简记 黑马课程
  2. 学Java怎么看API(详细图解)+查看Java源码(IDEA)
  3. Adobe Photoshop CC 2018 安装失败 安装遇到错误怎么解决
  4. PA0-PA开发环境配置
  5. 【Jinja2】模板继承(八)
  6. 云计算考证笔记、集群特性、HA
  7. 哈希表与字符串--13-[剑]字符串转换为整数[中等]
  8. 第一场数据挖掘比赛的一些经验心得
  9. 【编程题】【Scratch二级】2021.09 画正多边形
  10. 这是一个怎样的零售行业数字化运营方案?让多家公司实现营收翻倍!