项目优化

(1) 添加Loading进度条效果

(2) 解决server警告(语法错误)

  • https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=193

    Vue-Cli面板【任务】=>【运行serve命令】=>【仪表盘】=>【N个警告】
    点击仪表盘左边的【输出】,查看详情

  • 有些是Eslint检查出的语法规范错误,比如:

    1. 某某变量定义了但没有使用某某 is defined but never used
    2. 希望某某代码处于一行不要折行Expected "某某" to be the same line
    3. 某某变量不是驼峰命名Identifier 'attr id' is not in camel case
    4. 不希望是 var,使用 let 或者 const 代替Unexpected var, use let or const instead
  • 这些Eslint语法报错与.prettierrc.js息息相关

    1
    2
    3
    4
    5
    6
    7
    8
    9
    module.exports = {
    semi: false, //代码末尾的分号
    singleQuote: true, //使用单引号
    bracketSpacing: true, //括号内部不要出现空格
    useTabs: false, //使用 tab 缩进
    tabWidth: 2, //缩进空格数
    trailingComma: 'none', //末尾逗号
    printWidth: 1000, //行宽,超过这个数值才换行。否则默认每个标签属性单独占一行
    }

(3) 解决build警告(控制台语句)

  • https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=194

    Vue-Cli面板【任务】=>【运行build命令】=>【仪表盘】=>【N个警告】
    点击仪表盘左边的【输出】,查看详情

  • 很多报错情况是不希望出现控制台语句Unexpected console statement

    可以使用插件babel的插件transform-remove-console移除所有console方法的调用。
    选中Vue-Cli面板【依赖】=>【安装依赖】=>【开发依赖】=>【安装babel-plugin-transform-remove-console
    在项目根目录的babel.config.js文件中的plugins数组中增加transform-remove-console插件名称:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    module.exports = {
    presets: [
    '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
    [
    'component',
    {
    libraryName: 'element-ui',
    styleLibraryName: 'theme-chalk'
    }
    ],
    'transform-remove-console'
    ]
    }

    但使用需谨慎,比如:删除 console 语句引发的惨案
    若只想在发布阶段移除console,开发阶段的语句保留,可以这样用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 项目发布阶段需要用到的babel插件
    const prodPlugins = []
    if(process.env.NODE_ENV === 'production'){
    prodPlugins.push('transform-remove-console')
    }
    module.exports = {
    presets: [
    '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
    [
    'component',
    {
    libraryName: 'element-ui',
    styleLibraryName: 'theme-chalk'
    }
    ],
    // 发布产品时候的插件数组(三个点是展开运算符)
    ...prodPlugins
    ]
    }
  • 有的是资源大小超过某个建议值,提示可能影响性能

    1
    2
    3
    4
    asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
    This can impact web performance.
    Assets:
    js/chunk-vendors.4b32b0ed.js (1.98 MiB)
  • 有的可能是入口点组合资源大小超过了建议的限制,可能影响性能

    1
    2
    3
    4
    5
    6
    7
    entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
    Entrypoints:
    app (2.39 MiB)
    css/chunk-vendors.a5710808.css
    js/chunk-vendors.4b32b0ed.js
    css/app.7aa62b74.css
    js/app.ee0648c7.js

(4) 生成打包报告

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=196

打包时,为了直观地发现项目中存在的问题,可以在打包时生成报告。生成报告的方式有两种:

  1. 通过命令行参数的形式生成报告(手动运行打包命令)

    1
    2
    3
    // 通过 vue-cli 的命令选项可以生成打包报告
    // --report 选项可以生成 report.html 以帮助分析包内容
    vue-cli-service build --report
  2. 通过可视化的UI面板直接查看报告(推荐
    在可视化的UI面板中,通过控制台分析面板,可以方便地看到项目中所存在的问题。

(5) 通过 vue.config.js 修改 webpack 的默认配置

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=197

通过 vue-cli 3.0 工具生成的项目,默认隐藏了所有 webpack 的配置项,目的是为了屏蔽项目的配置过程,让程序员把工作的重心,放到具体功能和业务逻辑的实现上。

如果程序员有修改 webpack 默认配置的需求,可以在项目根目录中,按需创建 vue.config.js 这个配置文件,从而对项目的打包发布过程做自定义的配置(具体配置参考 https://cli.vuejs.org/zh/config/#vue-config-js )。

1
2
3
4
5
// vue.config.js 
// 这个文件中,应该导出一个包含了自定义配置选项的对象
module.exports = {
// 选项...
}

(6) 为开发模式与发布模式指定不同的打包入口

默认情况下,Vue项目的开发模式发布模式,共用同一个打包的入口文件(即 src/main.js)。为了将项目的开发过程与发布过程分离,我们可以为两种模式,各自指定打包的入口文件,即:

  1. 开发模式的入口文件为 src/main-dev.js
  2. 发布模式的入口文件为 src/main-prod.js

(7) configureWebpack 和 chainWebpack

在 vue.config.js 导出的配置对象中,新增 configureWebpack 或 chainWebpack 节点,来自定义 webpack
的打包配置。

在这里, configureWebpack 和 chainWebpack 的作用相同,唯一的区别就是它们修改 webpack 配置的方
式不同:

  1. chainWebpack 通过链式编程的形式,来修改默认的 webpack 配置
  2. configureWebpack 通过操作对象的形式,来修改默认的 webpack 配置

两者具体的使用差异,可参考如下网址:

https://cli.vuejs.org/zh/guide/webpack.html#webpack-%E7%9B%B8%E5%85%B3

(8) 通过 chainWebpack 自定义打包入口

https://www.bilibili.com/video/BV1mQ4y1r7yZ?p=199

代码示例如下(需要写到vue.config.js中):

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
chainWebpack: config => {
// 发布模式
config.when(process.env.NODE_ENV === 'production', config => {
config.entry('app').clear().add('./src/main-prod.js')
})

// 开发模式
config.when(process.env.NODE_ENV === 'development', config => {
config.entry('app').clear().add('./src/main-dev.js')
})
}
}

(9) 通过 externals 加载外部 CDN 资源

https://www.bilibili.com/video/BV1x64y1S7S7?p=200
https://www.bilibili.com/video/BV1x64y1S7S7?p=201

默认情况下,通过 import 语法导入的第三方依赖包,最终会被打包合并到同一个文件中,从而导致打包成功
后,单文件体积过大的问题。

为了解决上述问题,可以通过 webpack 的 externals 节点,来配置并加载外部的 CDN 资源。凡是声明在
externals 中的第三方依赖包,都不会被打包到 js/chunk-vendors.js 中。在项目配置文件vue.config.js中的发布模式添加如下:

具体配置代码如下(粘贴到发布模式的代码块中):

1
2
3
4
5
6
7
8
9
config.set('externals', {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
lodash: '_',
echarts: 'echarts',
nprogress: 'NProgress',
'vue-quill-editor': 'VueQuillEditor'
})

同时,需要在 public/index.html 文件的头部,添加如下的 CDN 资源引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- nprogress 的样式表文件 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
<!-- 富文本编辑器 的样式表文件 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.core.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.snow.min.css" />
<link rel="stylesheet" href="https://cdn.staticfile.org/quill/1.3.4/quill.bubble.min.css" />
<script src="https://cdn.staticfile.org/vue/2.5.22/vue.min.js"></script>
<script src="https://cdn.staticfile.org/vue-router/3.0.1/vue-router.min.js"></script> <!-- 不进行本文下方“首页内容定制”过程,会因为重复引用router而使页面不正常 -->
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.staticfile.org/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdn.staticfile.org/echarts/4.1.0/echarts.min.js"></script>
<script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
<!-- 富文本编辑器的 js 文件 -->
<script src="https://cdn.staticfile.org/quill/1.3.4/quill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-quill-editor@3.0.4/dist/vue-quill-editor.js"></script>

注意:以上CDN可能已失效或更新,可自行查找替换合适版本

(10) 通过 CDN 优化 ElementUI 的打包

https://www.bilibili.com/video/BV1x64y1S7S7?p=202

虽然在开发阶段,我们启用了 element-ui 组件的按需加载,尽可能的减少了打包的体积,但是那些被按需加
载的组件,还是占用了较大的文件体积。此时,我们可以将 element-ui 中的组件,也通过 CDN 的形式来加
载,这样能够进一步减小打包后的文件体积。

具体操作流程如下:

  1. main-prod.js 中,注释掉 element-ui 按需加载的代码
  2. index.html 的头部区域中,通过 CDN 加载 element-ui 的 js 和 css 样式
1
2
3
4
<!-- element-ui 的样式表文件 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.css" />
<!-- element-ui 的 js 文件 -->
<script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>

(11) 首页内容定制

https://www.bilibili.com/video/BV1x64y1S7S7?p=203

不同的打包环境下,首页内容可能会有所不同。我们可以通过插件的方式进行定制,插件配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
chainWebpack: config => {
// 发布模式
config.when(process.env.NODE_ENV === 'production', config => {
config.plugin('html').tap(args => {
args[0].isProd = true
return args
})
})

// 开发模式
config.when(process.env.NODE_ENV === 'development', config => {
config.plugin('html').tap(args => {
args[0].isProd = false
return args
})
})
}

public/index.html 首页中,可以根据 isProd 的值,来决定如何渲染页面结构:

1
2
3
4
5
6
7
<!– 按需渲染页面的标题 -->
<title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>

<!– 按需加载外部的 CDN 资源 -->
<% if(htmlWebpackPlugin.options.isProd) { %>
<!—通过 externals 加载的外部 CDN 资源-->
<% } %>

(12) 路由懒加载

https://www.bilibili.com/video/BV1x64y1S7S7?p=204

当打包构建项目时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成
不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
具体需要 3 步:

  1. 安装 @babel/plugin-syntax-dynamic-import (开发依赖)包。
  2. babel.config.js 配置文件中声明该插件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 项目发布阶段需要用到的babel插件
    const prodPlugins = []
    if(process.env.NODE_ENV === 'production'){
    prodPlugins.push('transform-remove-console')
    }
    module.exports = {
    presets: [
    '@vue/cli-plugin-babel/preset'
    ],
    plugins: [
    [
    'component',
    {
    libraryName: 'element-ui',
    styleLibraryName: 'theme-chalk'
    }
    ],
    // 发布产品时候的插件数组(三个点是展开运算符)
    ...prodPlugins,
    // 声明该插件
    '@babel/plugin-syntax-dynamic-import'
    ]
    }
  3. 将路由改为按需加载的形式,示例代码如下:
1
2
3
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-boo" */ './Baz.vue')

关于路由懒加载的详细文档,可参考如下链接:

https://router.vuejs.org/zh/guide/advanced/lazy-loading.html

  • 按需懒加载的代码在routor.js中样子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import Vue from 'vue'
    import VueRouter from 'vue-router'

    // import VueLogin from './components/VueLogin.vue'
    const VueLogin = () => import(/* webpackChunkName: "login_home_welcome" */ './components/VueLogin.vue')
    // import VueHome from './components/VueHome.vue'
    const VueHome = () => import(/* webpackChunkName: "login_home_welcome" */ './components/VueHome.vue')
    // import VueWelcome from './components/VueWelcome.vue'
    const VueWelcome = () => import(/* webpackChunkName: "login_home_welcome" */ './components/VueWelcome.vue')

    // 以下引入不再演示,自行分组和改造(一般按功能或页面分组)
    import VueUsers from './components/user/VueUsers.vue'
    import VueRights from './components/power/VueRights.vue'
    import VueRoles from './components/power/VueRoles.vue'

    import VueCate from './components/goods/VueCate.vue'
    import VueParams from './components/goods/VueParams.vue'

    import VueList from './components/goods/VueList.vue'
    import VueAdd from './components/goods/VueAdd.vue'

    import VueOrder from './components/order/VueOrder.vue'
    import VueReport from './components/report/VueReport.vue'

项目上线

  • 项目上线相关配置
    1. 通过 node 创建 web 服务器。
    2. 开启 gzip 配置(文件传输压缩)。
    3. 配置 https 服务。
    4. 使用 pm2 管理应用。

(1) 通过 node 创建 web 服务器

https://www.bilibili.com/video/BV1x64y1S7S7?p=205

创建 node 项目,并安装 express,通过 express 快速创建 web 服务器,将 vue 打包生成的 dist 文件夹,托管为静态资源即可,关键代码如下:

1
2
3
4
5
6
7
8
9
const express = require('express')
// 创建 web 服务器
const app = express()
// 托管静态资源
app.use(express.static('./dist'))
// 启动 web 服务器
app.listen(80, () => {
console.log('web server running at http://127.0.0.1')
})

具体步骤:

  • 新建一个vue_shop_server文件夹
  • 执行npm init -y,初始化一个包管理配置文件,会自动生成package.json等文件
  • 安装npm i express -S
  • 复制项目根目录vue_shop中的打包文件夹dist,粘贴到vue_shop_server文件夹中
  • vue_shop_server文件夹中新建入口文件app.js,粘贴以下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const express = require('express')
    // 创建 web 服务器
    const app = express()
    // 托管静态资源
    app.use(express.static('./dist'))
    // 启动 web 服务器
    app.listen(80, () => {
    console.log('web server running at http://127.0.0.1')
    })
  • 打开终端,执行命令node .\app.js

(2) 开启 gzip 配置

https://www.bilibili.com/video/BV1x64y1S7S7?p=206

使用 gzip 可以减小文件体积,使传输速度更快。

具体步骤:

  • 如果刚刚服务器正在运行命令node .\app.js,先停掉
  • 安装相应包npm i compression -S
  • app.js中导入包const compression = require('compression')
  • 在托管资源代码前注册启用中间件app.use(compression())
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const express = require('express')
    const compression = require('compression')

    // 创建 web 服务器
    const app = express()

    // 一定要把这行代码,写到 托管静态资源 之前(也就是先压缩再托管)
    app.use(compression())

    // 托管静态资源
    app.use(express.static('./dist'))

    // 启动 web 服务器
    app.listen(80, () => {
    console.log('web server running at http://127.0.0.1')
    })
  • 执行命令node .\app.js,重新启动

(3) 配置 HTTPS 服务

https://www.bilibili.com/video/BV1x64y1S7S7?p=207

  • 为什么要启用 HTTPS 服务?

    1. 传统的 HTTP 协议传输的数据都是明文,不安全
    2. 采用 HTTPS 协议对传输的数据进行了加密处理,可以防止数据被中间人窃取,使用更安全
  • 个人免费申请 SSL 证书( https://freessl.org

    1. 进入 https://freessl.cn/ 官网,输入要申请的域名并选择品牌。
    2. 输入自己的邮箱并选择相关选项。
    3. 验证 DNS(在域名管理后台添加 TXT 记录)。
    4. 验证通过之后,下载 SSL 证书( full_chain.pem 公钥;private.key 私钥)。

      配套资料的vue-项目实战day7/素材文件夹中有一对full_chain.pemprivate.key

  • full_chain.pemprivate.key放到vue_shop_server文件夹中

  • 在后台项目中导入证书

    1
    2
    3
    4
    5
    6
    7
    const https = require('https');
    const fs = require('fs');
    const options = {
    cert: fs.readFileSync('./full_chain.pem'),
    key: fs.readFileSync('./private.key')
    }
    https.createServer(options, app).listen(443);

导入后大概是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const express = require('express')
const compression = require('compression')
const https = require('https');
const fs = require('fs');
const app = express()

const options = {
cert: fs.readFileSync('./full_chain.pem'),
key: fs.readFileSync('./private.key')
}

// 一定要把这行代码,写到 托管静态资源 之前(也就是先压缩再托管)
app.use(compression())
app.use(express.static('./dist'))

// 启动 web 服务器
// app.listen(80, () => {
// console.log('web server running at http://127.0.0.1')
// })

https.createServer(options, app).listen(443)

(4) 使用 pm2 管理应用

使项目在终端窗口关闭后仍能运行

  1. 在服务器中安装 pm2:npm i pm2 -g
  2. 启动项目:pm2 start 入口脚本文件 --name 自定义网站名称
  3. 查看运行项目:pm2 ls
  4. 停止项目:pm2 stop 自定义名称(如果名称太长,可以用id代替,如pm2 stop 0
  5. 重启项目:pm2 restart 自定义名称(可以用id代替,如pm2 restart 0
  6. 删除项目:pm2 delete 自定义名称(可以用id代替,如pm2 delete 0

比如此项目的启动命令可以是pm2 start .\app.js --name web_vueshop


【参考内容】:

2022-08-24 拖了太久了,终于看完这个视频了。
完结撒花!感谢黑马!感谢刘龙彬!感谢所有解决我问题的博主!