从0到1构建vueSSR项目之node以及vue-cli3的配置

作者:绅士 时间:2024-04-27 16:06:59 

前言

上一次做了路由的相关配置,原本计划今天要做vuex部分,但是想了想,发现vuex单独的客户端部分穿插解释起来很麻烦,所以今天改做服务端部分。

服务端部分做完,再去做vuex的部分,这样就会很清晰。

vue ssr是分两个端,一个是客户端,一个是服务端。

所以要做两个cli3的配置。

那么下面就直接开始做吧。

修改package.json的命令


//package.json :client代表客户端 :server代表服务端
//使用VUE_NODE来作为运行环境是node的标识
//cli3内置 命令 --no-clean 不会清除dist文件
 "scripts": {
   "serve:client": " vue-cli-service serve",
   "build":"npm run build:server -- --silent && npm run build:client -- --no-clean --silent",
   "build:client": "vue-cli-service build",
   "build:server": "cross-env VUE_NODE=node vue-cli-service build",
   "start:server": "cross-env NODE_ENV=production nodemon nodeScript/index"
 }

修改vue.config.js配置

添加完相关脚本命令之后,我们开始改造cli3配置。

首先要require('vue-server-renderer')

然后再根据VUE_NODE环境变量来决定编译的走向以及生成不同的环境清单

先做cli3服务端的入口文件


// src/entry/server.js
import {
 createApp
} from '../main.js'

export default context => {

return new Promise((resolve, reject) => {
   const {
     app,
     router
   } = createApp(context.data)
   //根据node传过来的路由 来调用router路由的指向
   router.push(context.url)

router.onReady(() => {
     //获取当前路由匹配的组件数组。
     const matchedComponents = router.getMatchedComponents()
     //长度为0就是没找到该路由所匹配的组件
     //可以路由设置重定向或者传回node node来操作也可以
     if (!matchedComponents.length) {

return reject({
         code: 404
       })
     }

resolve(app)

}, reject)
 })
}

这里是cli3的配置


//vue.config.js

const ServerPlugin = require('vue-server-renderer/server-plugin'),//生成服务端清单
  ClientPlugin = require('vue-server-renderer/client-plugin'),//生成客户端清单
  nodeExternals = require('webpack-node-externals'),//忽略node_modules文件夹中的所有模块
  VUE_NODE = process.env.VUE_NODE === 'node',
  entry = VUE_NODE ? 'server' : 'client';//根据环境变量来指向入口

module.exports = {
 css: {
   extract: false//关闭提取css,不关闭 node渲染会报错
 },
 configureWebpack: () => ({
   entry: `./src/entry/${entry}`,
   output: {
     filename: 'js/[name].js',
     chunkFilename: 'js/[name].js',
     libraryTarget: VUE_NODE ? 'commonjs2' : undefined
   },
   target: VUE_NODE ? 'node' : 'web',
   externals: VUE_NODE ? nodeExternals({
     //设置白名单
     whitelist: /\.css$/
   }) : undefined,
   plugins: [//根据环境来生成不同的清单。
     VUE_NODE ? new ServerPlugin() : new ClientPlugin()
   ]
 }),
 chainWebpack: config => {
   config.resolve
     .alias
       .set('vue$', 'vue/dist/vue.esm.js')
   config.module
     .rule('vue')
       .use('vue-loader')
         .tap(options => {
           options.optimizeSSR = false;
           return options;
         });
   config.module
     .rule('images')
       .use('url-loader')
         .tap(options => {
           options = {
             limit: 1024,
             fallback:'file-loader?name=img/[path][name].[ext]'
           }
           return options;
         });
 }
}

node相关配置

用于node渲染 必然要拦截get请求的。然后根据get请求地址来进行要渲染的页面。

官方提供了vue-server-renderer插件

大概的方式就是 node拦截所有的get请求,然后将获取到的路由地址,传给前台,然后使用router实例进行push

再往下面看之前 先看一下官方文档

创建BundleRenderer
createBundleRenderer

将 Vue 实例渲染为字符串。
renderToString

渲染应用程序的模板
template

生成所需要的客户端或服务端清单
clientManifest

先创建 服务端所需要的模板


//public/index.nodeTempalte.html
<!DOCTYPE html>
<html>
 <head>
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="/favicon.ico" rel="external nofollow" >
   <meta charset="utf-8">
   <title>vuessr</title>
 </head>
 <body>
   <!--vue-ssr-outlet-->
 </body>
</html>

node部分

先创建三个文件
index.js //入口
proxy.js //代理
server.js //主要配置


//server.js
const fs = require('fs');
const { resolve } = require('path');
const express = require('express');
const app = express();
const proxy = require('./proxy');
const { createBundleRenderer } = require('vue-server-renderer')

//模板地址
const templatePath = resolve(__dirname, '../public/index.nodeTempalte.html')
//客户端渲染清单
const clientManifest = require('../dist/vue-ssr-client-manifest.json')
//服务端渲染清单
const bundle = require('../dist/vue-ssr-server-bundle.json')
//读取模板
const template = fs.readFileSync(templatePath, 'utf-8')
const renderer = createBundleRenderer(bundle,{
 template,
 clientManifest,
 runInNewContext: false
})

//代理相关
proxy(app);
//请求静态资源相关配置
app.use('/js', express.static(resolve(__dirname, '../dist/js')))
app.use('/css', express.static(resolve(__dirname, '../dist/css')))
app.use('/font', express.static(resolve(__dirname, '../dist/font')))
app.use('/img', express.static(resolve(__dirname, '../dist/img')))
app.use('*.ico', express.static(resolve(__dirname, '../dist')))

//路由请求
app.get('*', (req, res) => {
 res.setHeader("Content-Type", "text/html")
 //传入路由 src/entry/server.js会接收到 使用vueRouter实例进行push
 const context = {
   url: req.url
 }

renderer.renderToString(context, (err, html) => {
   if (err) {
     if (err.url) {
       res.redirect(err.url)
     } else {
       res.status(500).end('500 | 服务器错误');
       console.error(`${req.url}: 渲染错误 `);
       console.error(err.stack)
     }
   }
   res.status(context.HTTPStatus || 200)
   res.send(html)
 })
})
module.exports = app;

//proxy.js

const proxy = require('http-proxy-middleware');

function proxyConfig(obj){
 return {
   target:'localhost:8081',
   changeOrigin:true,
   ...obj
 }
}
module.exports = (app) => {
 //代理开发环境
 if (process.env.NODE_ENV !== 'production') {
   app.use('/js/main*', proxy(proxyConfig()));
   app.use('/*hot-update*',proxy(proxyConfig()));
   app.use('/sockjs-node',proxy(proxyConfig({ws:true})));
 }
}

//index.js
const app = require('./server')

app.listen(8080, () => {
console.log('\033[42;37m DONE \033[40;33m localhost:8080 服务已启动\033[0m')
})

做完这一步之后,就可以预览基本的服务渲染了。

后面就只差开发环境的配置,以及到node数据的传递(vuex)


npm run build
npm run start:server
打开localhost:8080
F12 - Network - Doc 就可以看到内容

从0到1构建vueSSR项目之node以及vue-cli3的配置

最终目录结构


|-- vuessr
 |-- .gitignore
 |-- babel.config.js
 |-- package-lock.json
 |-- package.json
 |-- README.md
 |-- vue.config.js
 |-- nodeScript //node 渲染配置
 |  |-- index.js
 |  |-- proxy.js
 |  |-- server.js
 |-- public//模板文件
 |  |-- favicon.ico
 |  |-- index.html
 |  |-- index.nodeTempalte.html
 |-- src
   |-- App.vue
   |-- main.js
   |-- router.config.js//路由集合
   |-- store.config.js//vuex 集合
   |-- assets//全局静态资源源码
   |  |-- 备注.txt
   |  |-- img
   |    |-- logo.png
   |-- components//全局组件
   |  |-- Head
   |    |-- index.js
   |    |-- index.scss
   |    |-- index.vue
   |    |-- img
   |      |-- logo.png
   |-- entry//cli3入口
   |  |-- client.js
   |  |-- server.js
   |  |-- 备注.txt
   |-- methods//公共方法
   |  |-- 备注.txt
   |  |-- mixin
   |    |-- index.js
   |-- pages//源码目录
   |  |-- home
   |  |  |-- index.js
   |  |  |-- index.scss
   |  |  |-- index.vue
   |  |  |-- img
   |  |  |  |-- flow.png
   |  |  |  |-- head_portrait.jpg
   |  |  |  |-- logo.png
   |  |  |  |-- vuessr.png
   |  |  |-- vue
   |  |  |  |-- index.js
   |  |  |  |-- index.scss
   |  |  |  |-- index.vue
   |  |  |-- vueCli3
   |  |  |  |-- index.js
   |  |  |  |-- index.scss
   |  |  |  |-- index.vue
   |  |  |-- vueSSR
   |  |  |  |-- index.js
   |  |  |  |-- index.scss
   |  |  |  |-- index.vue
   |  |  |-- vuex
   |  |    |-- index.js
   |  |    |-- index.scss
   |  |    |-- index.vue
   |  |-- router//路由配置
   |  |  |-- index.js
   |  |-- store//vuex配置
   |    |-- all.js
   |    |-- gather.js
   |    |-- index.js
   |-- static//cdn资源
     |-- 备注.txt

来源:https://segmentfault.com/a/1190000018043697

标签:vueSSR,vue-cli3,配置
0
投稿

猜你喜欢

  • zend framework文件上传功能实例代码

    2024-05-05 09:17:17
  • SpringBoot Logback日志记录到数据库的实现方法

    2024-01-16 11:58:11
  • Python内置加密模块用法解析

    2021-09-17 02:26:19
  • 对python3 一组数值的归一化处理方法详解

    2023-06-26 11:07:25
  • jquery弹出层背景变暗 Lee dialog

    2008-08-18 13:11:00
  • 懒懒交流会:ClassName的长命名 VS. 短命名

    2009-11-28 16:08:00
  • 如何从PyTorch中获取过程特征图实例详解

    2022-07-08 04:04:44
  • 用JavaScript实现PHP的urlencode与urldecode函数

    2023-11-23 08:18:14
  • js判断密码强度的方法

    2024-04-19 10:58:24
  • Django中更新多个对象数据与删除对象的方法

    2021-08-13 13:31:46
  • MySQL复制表的三种方式(小结)

    2024-01-17 11:33:09
  • Python虚拟环境项目实例

    2023-03-07 16:59:01
  • python文件读写操作与linux shell变量命令交互执行的方法

    2022-10-24 06:37:55
  • Django多数据库的实现过程详解

    2024-01-21 17:47:21
  • oracle 常见等待事件及处理方法

    2009-04-24 12:01:00
  • Python合并多个Excel数据的方法

    2022-11-02 06:31:33
  • mysql 5.7.13 安装配置方法图文教程(win10 64位)

    2024-01-28 09:07:21
  • 30种SQL语句优化的方法汇总

    2024-01-24 22:55:52
  • Microsoft SQL Server数据库开发问题详解

    2009-10-23 14:16:00
  • Django实现快速分页的方法实例

    2022-12-27 06:02:30
  • asp之家 网络编程 m.aspxhome.com