vue打包上线优化

前言:前面的三步都是在所有文件打包时必须要用的,后面的几步都是只针对于后台管理项目的打包

项目开始时webpack配置

vue-cli3以后,我们修改webpack配置,需要自己在项目根路径下创建vue.config.js文件。

一、 配置 proxy 跨域

使用vue-cli发开项目,在本地开发环境中,如果遇到跨域的问题。可以通过配置proxy的方式,解决跨域问题

module.exports = {
  devServer: {
   open: false, // 自动启动浏览器
   host: '0.0.0.0', // localhost
   port: 6060, // 端口号
   hotOnly: false, // 热更新

   overlay: {
      //  当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
      warnings: false,
      errors: true
    },
    proxy: {
      //配置跨域
      '/api': {
        target: 'https://www.test.com', // 接口的域名
        // ws: true, // 是否启用websockets
        changOrigin: true, // 开启代理,在本地创建一个虚拟服务端
        pathRewrite: {
          '^/api': '/'
        }
      }
    }
  }
}

配置完成后,当我们在去请求https://www.test.com/v1/api/userinfo接口时,就可以这么写

this.axios({
url:'/api/v1/api/userinfo',
method:'get'
}).then(res=>{
//......
})

二、配置 alias 别名

使用vue-cli开发项目,最大特色是组件化。组件中频繁引用其他组件或插件。我们可以把一些常用的路径定义成简短的名字。方便开发中使用。

//加载path模块
const path = require('path')
//定义resolve方法,把相对路径转换成绝对路径
const resolve = dir => path.join(__dirname, dir)

module.exports = {
  chainWebpack: config => {
    // 添加别名
    config.resolve.alias
      .set('@', resolve('src'))
      .set('assets', resolve('src/assets'))
      .set('api', resolve('src/api'))
      .set('views', resolve('src/views'))
      .set('components', resolve('src/components'))
  }
}

配置完成后,我们在项目中可以这样写路径

//之前这么写
import Home from '../views/Home.vue'
//配置alias别名后
import Home from 'views/Home.vue'
//也可以这么写
import Home from '@/views/Home.vue'

项目结束后打包前webpack配置

目的:
  • 提高打包速度
  • 减小项目体积、提高首屏加载速度
  • 提高用户体验(骨架屏)

打包前必做

项目开发完成后,运行npm run build进行打包操作。打包前对webpack配置。

module.exports = {
  publicPath: './', // 静态资源路径(默认/,打包后会白屏)
  outputDir: 'dist', // 打包后文件的目录 (默认为dist)
  assetsDir: 'static', //  outputDir的静态资源(js、css、img、fonts)目录  默认为‘’没有单独目录js/css/img在根目录中。
  }

三、去除生产环境sourceMap

问题: vue项目打包之后js文件夹中,会自动生成一些map文件,占用相当一部分空间

sourceMap资源映射文件,存的是打包前后的代码位置,方便开发使用,这个占用相当一部分空间。

map文件的作用在于:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错,有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错。

生产环境是不需要sourceMap的,如下配置可以去除

module.exports = {
  //去除生产环境的productionSourceMap
  productionSourceMap: false,
}

去除sourceMap前后对比,减少了很大体积。

前:dist大小为7M

后:dist大小为3M


一、项目优化

实现步骤:

  1. 添加进度条
  2. 根据报错修改代码(根据ESLint的警告提示更改对应的代码)
  3. 安装插件,移除项目的console.log信息
  4. 生成打包报告(vue-cli-service build --report)
  5. 修改webpack的默认配置
  6. 加载外部CDN
  7. 定制首页内容
  8. 路由懒加载
  9. 项目上线

二、添加进度条

给项目添加进度条效果,先打开项目控制台,打开依赖,安装nprogress
cnpm install nprogress
打开main.js,编写如下代码

//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
import 'nprogress/nprogress.css'
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
  //当进入request拦截器,表示发送了请求,我们就开启进度条
  NProgress.start()
  //为请求头对象,添加token验证的Authorization字段
  config.headers.Authorization = window.sessionStorage.getItem("token")
  //必须返回config
  return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config =>{
  //当进入response拦截器,表示请求已经结束,我们就结束进度条
  NProgress.done()
  return config
})

三、根据报错修改代码

根据ESLint的警告提示更改对应的代码
在.prettierrc文件中更改设置"printWidth":200, 将每行代码的文字数量更改为200

{
    "semi":false,
    "singleQuote":true,
    "printWidth":200
}

这个是你开启了ESLint才能用到,如果没有开始ESLint可以跳过

四、执行build

安装一个插件(babel-plugin-transform-remove-console)在项目build阶段移除所有的console信息
cnpm install babel-plugin-transform-remove-console
下载完插件之后,打开babel.config.js,编辑代码如下:

// 这个是babel.config.js自带的代码,我们要给他注释掉
// module.exports = {
//     presets: [
//         '@vue/cli-plugin-babel/preset'
//     ]
// }

//项目发布阶段需要用到的babel插件
const productPlugins = []

//判断是开发还是发布阶段
if (process.env.NODE_ENV === 'production') {
    //发布阶段
    productPlugins.push("transform-remove-console")
}

module.exports = {
    "presets": [
        '@vue/cli-plugin-babel/preset'
    ],
    "plugins": [
        [
            "component",
            {
                "libraryName": "element-ui",
                "styleLibraryName": "theme-chalk"
            }
        ],
        ...productPlugins
    ]
}

写到这里我们先不急着打包上线,而是先让项目在本地启动一下,如果在本地启动成功了,那么就可以进行下一步了,如果在本地一直启动不成功,报错显示找不到babel-plugin-component这个模板
一定要cnpm install babel-plugin-component
在这里插入图片描述

五、生成打包报告

这时候我们就要就要进行最激动人心的时候了,打包上线

首先要在package.json找到build,在build后面加上vue-cli-service build --report

在这里插入图片描述

  • 在vscode的终端里或在项目的地址栏里输入cmd打开的命令提示符(黑窗口)也好,输入npm run buildyarn build进行打包

  • 在这里插入图片描述

  • 打包完之后会在项目的根目录里出现一个dist文件夹,里面包含了你的项目可以直接打开文件夹里面的index.html文件
    在这里插入图片描述

  • 打开report.html,这个就是打包报告,使用Alt+B打开HTML文件在这里插入图片描述在这里插入图片描述

  • 打包报告
    在这里插入图片描述
    在这里插入图片描述

六、修改webpack的默认配置

默认情况下,vue-cli 3.0生成的项目,隐藏了webpack配置项,如果我们需要配置webpack
需要通过vue.config.js来配置。
在项目根目录中创建vue.config.js文件

module.exports = {
    chainWebpack:config=>{
        //发布模式
        config.when(process.env.NODE_ENV === 'production',config=>{
            //entry找到默认的打包入口,调用clear则是删除默认的打包入口
            //add添加新的打包入口
            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')
        })
    }
}

让项目在本地启动一下,如果在本地启动成功了,那么就可以进行下一步了

  • 这个时候启动本地,本地会报错,说找不到‘main-prod.js’,‘main-dev.js’,这两个js文件
  • 这两个文件是main.js分开的两个文件,首先把main.js里面的代码都先复制到这两个文件里
main-prod.js 发布模式

详细代码:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
//把element-ui改为按需引入,样式注释
// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
// import './plugins/VueQuillEditor.js'
//全局注册富文本编辑器
Vue.use(VueQuillEditor)

//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
// import 'nprogress/nprogress.css'
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
    //当进入request拦截器,表示发送了请求,我们就开启进度条
    NProgress.start()
        //为请求头对象,添加token验证的Authorization字段
    config.headers.Authorization = window.sessionStorage.getItem("token")
        //必须返回config
    return config
});
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config => {
    //当进入response拦截器,表示请求已经结束,我们就结束进度条
    NProgress.done()
    return config
})
Vue.config.productionTip = false

import axios from "axios";
Vue.prototype.$axios = axios;


import TreeTable from 'vue-table-with-tree-grid'

// Vue.use(ElementUI)
//全局组件,树形表格
Vue.component('tree-table', TreeTable)

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')
main-dev.js 开发模式

详细代码:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

import './plugins/VueQuillEditor.js'
//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
import 'nprogress/nprogress.css'
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
    //当进入request拦截器,表示发送了请求,我们就开启进度条
    NProgress.start()
        //为请求头对象,添加token验证的Authorization字段
    config.headers.Authorization = window.sessionStorage.getItem("token")
        //必须返回config
    return config
});
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config => {
    //当进入response拦截器,表示请求已经结束,我们就结束进度条
    NProgress.done()
    return config
})
Vue.config.productionTip = false

import axios from "axios";
Vue.prototype.$axios = axios;


import TreeTable from 'vue-table-with-tree-grid'

Vue.use(ElementUI)
Vue.component('tree-table', TreeTable)

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

七、加载外部CDN

默认情况下,依赖项的所有第三方包都会被打包到js/chunk-vendors.vue.config.js文件中,导致该js文件过大
那么我们可以通过externals排除这些包,使它们不被打包到js/chunk-vendors.vue.config.js文件中
下面的代码

//vue.config.js
module.exports = {
    chainWebpack:config=>{
        //发布模式
        config.when(process.env.NODE_ENV === 'production',config=>{
            //entry找到默认的打包入口,调用clear则是删除默认的打包入口
            //add添加新的打包入口
            config.entry('app').clear().add('./src/main-prod.js')

            //使用externals设置排除项
            config.set('externals',{
                vue:'Vue',
                'vue-router':'VueRouter',
                axios:'axios',
                lodash:'_',
                echarts:'echarts',
                nprogress:'NProgress',
                'vue-quill-editor':'VueQuillEditor'
            })
        })
        //开发模式
        config.when(process.env.NODE_ENV === 'development',config=>{
            config.entry('app').clear().add('./src/main-dev.js')
        })
    }
}

设置好排除之后,为了使我们可以使用vue,axios等内容,我们需要加载外部CDN的形式解决引入依赖项。
打开开发入口文件main-prod.js,删除掉默认的引入代码

import Vue from 'vue'
import App from './App.vue'
import router from './router'
// import './plugins/element.js'
//导入字体图标
import './assets/fonts/iconfont.css'
//导入全局样式
import './assets/css/global.css'
//导入第三方组件vue-table-with-tree-grid
import TreeTable from 'vue-table-with-tree-grid'
//导入进度条插件
import NProgress from 'nprogress'
//导入进度条样式
// import 'nprogress/nprogress.css'
// //导入axios
import axios from 'axios'
// //导入vue-quill-editor(富文本编辑器)
import VueQuillEditor from 'vue-quill-editor'
// //导入vue-quill-editor的样式
// import 'quill/dist/quill.core.css'
// import 'quill/dist/quill.snow.css'
// import 'quill/dist/quill.bubble.css'

axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/'
//请求在到达服务器之前,先会调用use中的这个回调函数来添加请求头信息
axios.interceptors.request.use(config => {
  //当进入request拦截器,表示发送了请求,我们就开启进度条
  NProgress.start()
  //为请求头对象,添加token验证的Authorization字段
  config.headers.Authorization = window.sessionStorage.getItem("token")
  //必须返回config
  return config
})
//在response拦截器中,隐藏进度条
axios.interceptors.response.use(config =>{
  //当进入response拦截器,表示请求已经结束,我们就结束进度条
  NProgress.done()
  return config
})
Vue.prototype.$http = axios

Vue.config.productionTip = false

//全局注册组件
Vue.component('tree-table', TreeTable)
//全局注册富文本组件
Vue.use(VueQuillEditor)

//创建过滤器将秒数过滤为年月日,时分秒
Vue.filter('dateFormat',function(originVal){
  const dt = new Date(originVal)
  const y = dt.getFullYear()
  const m = (dt.getMonth()+1+'').padStart(2,'0')
  const d = (dt.getDate()+'').padStart(2,'0')

  const hh = (dt.getHours()+'').padStart(2,'0')
  const mm = (dt.getMinutes()+'').padStart(2,'0')
  const ss = (dt.getSeconds()+'').padStart(2,'0')

  return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

然后打开public/index.html添加外部cdn引入代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>电商后台管理系统</title>

    <!-- 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" />
    <!-- element-ui 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.8.2/theme-chalk/index.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>
    <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>

    <!-- element-ui 的 js 文件 -->
    <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>

  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue_shop doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

八、定制首页内容

开发环境的首页和发布环境的首页展示内容的形式有所不同
如开发环境中使用的是import加载第三方包,而发布环境则是使用CDN,那么首页也需根据环境不同来进行不同的实现
我们可以通过插件的方式来定制首页内容,打开vue.config.js,编写代码如下:

module.exports = {
    chainWebpack:config=>{
        config.when(process.env.NODE_ENV === 'production',config=>{
            ......
            
            //使用插件
            config.plugin('html').tap(args=>{
                //添加参数isProd
                args[0].isProd = true
                return args
            })
        })

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

            //使用插件
            config.plugin('html').tap(args=>{
                //添加参数isProd
                args[0].isProd = false
                return args
            })
        })
    }
}

然后在public/index.html中使用插件判断是否为发布环境并定制首页内容

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title><%= htmlWebpackPlugin.options.isProd ? '' : 'dev - ' %>电商后台管理系统</title>
	<!--这个是java的一种语法,前后端不分离-->
    <% if(htmlWebpackPlugin.options.isProd){ %>
    <!-- nprogress 的样式表文件 -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />
    <!-- element-ui 的 js 文件 -->
    <script src="https://cdn.staticfile.org/element-ui/2.8.2/index.js"></script>
    <% } %>
  </head>

九、路由懒加载

如果说你在项目创建开始的时候就使用了路由懒加载,那么就可以跳过这一步
当路由被访问时才加载对应的路由文件,就是路由懒加载。
路由懒加载实现步骤:
1.安装: cnpm install @babel/plugin-syntax-dynamic-import
打开项目,在package.json查找

2.在babel.config.js中声明该插件,打开babel.config.js

//项目发布阶段需要用到的babel插件
const productPlugins = []

//判断是开发还是发布阶段
if(process.env.NODE_ENV === 'production'){
  //发布阶段
  productPlugins.push("transform-remove-console")
}

module.exports = {
  "presets": [
    "@vue/app"
  ],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ],
    ...productPlugins,
    //配置路由懒加载插件
    "@babel/plugin-syntax-dynamic-import"
  ]
}

3.将路由更改为按需加载的形式,打开router.js,更改引入组件代码如下:

import Vue from 'vue'
import Router from 'vue-router'
const Login = () => import(/* webpackChunkName:"login_home_welcome" */ './components/Login.vue')
// import Login from './components/Login.vue'
const Home = () => import(/* webpackChunkName:"login_home_welcome" */ './components/Home.vue')
// import Home from './components/Home.vue'
const Welcome = () => import(/* webpackChunkName:"login_home_welcome" */ './components/Welcome.vue')
// import Welcome from './components/Welcome.vue'
const Users = () => import(/* webpackChunkName:"user" */ './components/user/Users.vue')
// import Users from './components/user/Users.vue'
const Rights = () => import(/* webpackChunkName:"power" */ './components/power/Rights.vue')
// import Rights from './components/power/Rights.vue'
const Roles = () => import(/* webpackChunkName:"power" */ './components/power/Roles.vue')
// import Roles from './components/power/Roles.vue'
const Cate = () => import(/* webpackChunkName:"goods" */ './components/goods/Cate.vue')
// import Cate from './components/goods/Cate.vue'
const Params = () => import(/* webpackChunkName:"goods" */ './components/goods/Params.vue')
// import Params from './components/goods/Params.vue'
const GoodList = () => import(/* webpackChunkName:"goods" */ './components/goods/List.vue')
// import GoodList from './components/goods/List.vue'
const GoodAdd = () => import(/* webpackChunkName:"goods" */ './components/goods/Add.vue')
// import GoodAdd from './components/goods/Add.vue'
const Order = () => import(/* webpackChunkName:"order" */ './components/order/Order.vue')
// import Order from './components/order/Order.vue'
const Report = () => import(/* webpackChunkName:"report" */ './components/report/Report.vue')
// import Report from './components/report/Report.vue'

十、项目上线

  1. 通过node创建服务器
    在vue_shop同级创建一个文件夹vue_shop_server存放node服务器
    使用终端打开vue_shop_server文件夹,输入命令npm init -y
    初始化包之后,输入命令npm i express -S
    打开vue_shop目录,复制dist文件夹,粘贴到vue_shop_server中
    在vue_shop_server文件夹中创建app.js文件,编写代码如下:
const express = require('express')

const app = express()

app.use(express.static('./dist'))

app.listen(8998,()=>{
    console.log("server running at http://127.0.0.1:8998")
})

然后再次在终端中输入 node app.js
好处:代码较少
坏处:需要一直打开终端,如果关闭终端的话,别人也就访问不到项目了

  1. 开启gzip压缩
    打开vue_shop_server文件夹的终端,输入命令:npm i compression -D
    打开app.js,编写代码:
const express = require('express')

const compression = require('compression')

const app = express()

app.use(compression())
app.use(express.static('./dist'))

app.listen(8998,()=>{
    console.log("server running at http://127.0.0.1:8998")
})
  1. 配置https服务
    配置https服务一般是后台进行处理,前端开发人员了解即可。
    首先,需要申请SSL证书,进入https://freessl.cn官网
    在后台导入证书,打开今天资料/素材,复制素材中的两个文件到vue_shop_server中
    打开app.js文件,编写代码导入证书,并开启https服务
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'))

// app.listen(8998,()=>{
//     console.log("server running at http://127.0.0.1:8998")
// })

//启动https服务
https.createServer(options,app).listen(443)

好处:启动项目之后,关闭项目终端,也是可以访问到项目的
坏处:服务器一般是后台进行处理,前端开发人员了解即可。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

归途风景111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值