Vue打包优化

Vue打包优化

  1. 分析包大小
  2. 理解Vue项目的开发环境和生产环境
  3. 路由懒加载
  4. 清除console
  5. cdn引入外部资源
  6. 第三方库按需加载
  7. 使用gzip
  8. 浏览器的请求资源的策略

分析包大小

下载webpack-bundle-analyzer

npm i webpack-bundle-analyzer -D

可以通过命令

npm run build --report

然后会出现这个界面,能帮助我们清晰看到包大小请求 (vue-cli 2的项目)

在这里插入图片描述

如果你使用的是Vue官方的vue-cli 3.0+的脚手架,可以直接通过可视化工具来构建并查看。

在这里插入图片描述

vendor*.js 是所有第三方依赖js的集合

app*.js 是我们写的所有业务代码的集合,通常可以通过路由懒加载来减少这个文件的大小,可以称为拆包,拆包后会多出很多chunck.js文件

其他的chunck*.js是各个路由对应的js文件

理解Vue项目的开发环境和生产环境

vue-cli 2的项目Webpack配置是暴露在外的,vue-cli 3+的Webpack配置是被隐藏了的。这里简单说一下vue-cli 3+的配置:

首先分析一下vue-cli3的 构建命令:vue-cli-service serve --mode development ,mode参数的值development会被设置为名为NODE_ENV的环境变量的值,这就是为什么我们在js中可以获取到process.env.NODE_ENV.

理解项目打包命令

//开发运行命令:
vue-cli-service serve --mode development
//构建发布命令:
vue-cli-service build --mode production
//mode参数的值会用作修改进程环境变量NODE_ENV
"scripts": {
    //默认--mode development,运行该命令后process.env.NODE_ENV==='development'
    "serve": "vue-cli-service serve", 
    //默认--mode production 运行该命令后process.env.NODE_ENV==='production'
    "build": "vue-cli-service build", 
    "lint": "vue-cli-service lint"
 },

其次,采用vue-cli3构建的项目,首先会读取.env.**的文件(默认是没有这样的文件),通常可以这个文件里设置进程环境变量,(注意:这里设置的环境变量会覆盖vue-cli命令的–mode所设置环境变量值)。当运行 vue-cli-service serve时会去读 .env.development文件,而运行vue-cli-service build会去读 .env.production文件。

你可以在根目录下新建2个文件.env.development.env.production 分别存放这样的内容

NODE_ENV='development'
VUE_APP_BASE_URL='/api'
NODE_ENV='production'
VUE_APP_BASE_URL='http://example.com/api/v1'

这样就相当于分别设置了开发环境和生产环境的变量,接下来在你的axios配置文件中可以这样来使用环境变量:

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_URL,
  timeout: 10000 // 请求超时时间
})

路由懒加载

在路由中,用这种方式引入组件

const routes = [
    {
        path:'/home',
        name:'home',
        component: ()=> import('../pages/home'),
    },
]

而不是这种方式

import Home from ''../pages/home''
const routes = [
    {
        path:'/home',
        name:'home',
        component: Home,
    },
]

清除console

方式一:通过babel插件 (适用vue-cli 3.x)

1)安装babel-plugin-transform-remove-console

npm i babel-plugin-transform-remove-console -D

2)配置 babel.config.js 文件

const prodPlugins = [] //生产环境的开发插件
if(process.env.NODE_ENV === 'production'){ //如果是生产环境(即npm build时)
  prodPlugins.push("transform-remove-console")
}

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

方式二:uglifyjs插件 (适用vue-cli 2.x)

安装插件uglifyjs-webpack-plugin (若没有安装则需单独安装)

npm i uglifyjs-webpack-plugin -D

找到webpack.prod.conf.js,做如下修改

new UglifyJsPlugin({
    uglifyOptions: {
        compress: {
            warnings: false,
            // ===========新增==========
            drop_debugger: true,  //自动删除debugger
            drop_console: true    //自动删除console.log
            // ===========新增==========
        }
    },
    sourceMap: config.build.productionSourceMap,
    parallel: true
}),

cdn引入外部资源

对于vue, vuex, vue-router,axios,better-scroll等,因为这些库时可以导入一个全局变量的,所以我们可以利用Webpack的externals参数来配置,让vue在打包时不从node-modules里面引入库而是使用CDN加载外部资源的方式来引入这些库。配置如下:(注意版本号与开发的一致)

修改vue.config.js


const isProduction = (process.env.NODE_ENV === 'production')
const cdn = {
  css:[
  ],
  js:[
    "https://unpkg.com/vue@2.6.11/dist/vue.min.js",
    "https://unpkg.com/vue-router@3.2.0/dist/vue-router.min.js",
    "https://unpkg.com/axios@0.21.1/dist/axios.min.js",
    "https://unpkg.com/@better-scroll/core@2.2.1/dist/core.min.js",
  ]
}

module.exports = {
 
  // eslint-loader 是否在保存的时候检查
  lintOnSave: false,
  // webpack-dev-server 相关配置
  devServer: {
    ...
  },

  // 链式配置webpack
  chainWebpack: config => {
    config.plugin('html').tap(args => {
      if(isProduction){
        // 把cdn对象挂到htmlWebpackPlugin.options上,可以在html中访问到
        args[0].cdn = cdn
      }
      return args
    })
  },
  // 对象配置webpack
  configureWebpack: config => {
      if(isProduction){
        // 打包时取消import加载资源
        config.externals = {
          'vue' : 'Vue',
          'vue-router': 'VueRouter',
          'axios': 'axios',
          '@better-scroll/core': 'BScroll'
        }
      }
  },
};

如果是在vue-cli 2.x项目中:则是找到webpack.prod.conf进行修改

// =================新增=================
const cdn = {
  css:[
  ],
  js:[
    "https://unpkg.com/vue@2.5.2/dist/vue.min.js",
    "https://unpkg.com/vue-router@3.0.1/dist/vue-router.min.js",
    "https://unpkg.com/vuex@3.0.1/dist/vuex.min.js",
    "https://unpkg.com/@better-scroll/core@2.2.1/dist/core.min.js",
    "https://unpkg.com/axios@0.18.0/dist/axios.min.js",
  ]
}
// =================新增=================


const webpackConfig = merge(baseWebpackConfig,{
   new HtmlWebpackPlugin({
      filename: config.build.index,
      template: 'index.html',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
      chunksSortMode: 'dependency',
      // =================新增=================
      // 这两个属性都是自定义到HtmlWebpackPlugin上的,从而可以在index.html中获取这些属性数据
      cdn: cdn, // cdn配置
      // =================新增=================
  }),
  // =================新增=================
  // 构建时忽略的资源
  externals: {
    'vue' : 'Vue',
    'vue-router': 'VueRouter',
    'vuex': 'Vuex',
    'axios': 'axios',
    '@better-scroll/core': 'BScroll'
  }
  // =================新增=================
})

然后是修改index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport"
        content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
  <title>移动端开发</title>
  <!-- ============以下是新增的============= -->
  <!-- cnd 加载css start-->
  <% if(htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css){
    htmlWebpackPlugin.options.cdn.css.forEach(function(item){
  %>
  <link href="<%= item %>" rel="stylesheet" />
  <% })} %>
  <!-- cnd 加载css end-->
  <!-- ============以上是新增的============= -->
  <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
  <script>
    if ('addEventListener' in document) {
      document.addEventListener('DOMContentLoaded', function() {
        FastClick.attach(document.body);
      }, false);
    }
    // 假设移动端屏幕375px, 则1rem=100px .16rem=16px
    // 假设移动端屏幕414px, 则1rem=110.4px .16rem=17.664px
    function setFS(){
      let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;
      var fontSize = htmlWidth / 3.75 ;
      if(fontSize>200){
        fontSize = 200
      }
      document.getElementsByTagName('html')[0].style.fontSize = fontSize +'px';
    }
    setFS()
    window.onresize = setFS   
  </script>
</head>
<body>
<div id="app"></div>

  <!-- ============以下是新增的============= -->
  <!-- cnd 加载js start-->
  <% if(htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js)
  {
    htmlWebpackPlugin.options.cdn.js.forEach(function(item){
  %>
    <script type="text/javascript" src="<%= item %>"></script>
  <% })} %>
  <!-- cnd 加载js end-->
  <!-- ============以上是新增的============= -->
<!-- built files will be auto injected -->
</body>
</html>

最后,推荐两个靠谱的cdn服务

jsdelivr (推荐) https://www.jsdelivr.com/

unpkg (推荐) https://unpkg.com/

第三方库按需加载

vant按需导入

参照官网,安装插件 babel-plugin-import ,修改babel配置

// 在.babelrc 中添加配置
// 注意:webpack 1 无需设置 libraryDirectory
{
  "plugins": [
    ["import", {
      "libraryName": "vant",
      "libraryDirectory": "es",
      "style": true
    }]
  ]
}

// 对于使用 babel7 的用户,可以在 babel.config.js 中配置
module.exports = {
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
};

定义vantPlugin.js,在这个文件里引入组件

import Vue from 'vue'
import { 
  Tabbar,
  TabbarItem,
  Toast,
  Dialog,
 }
Vue.use(Tabbar)
Vue.use(TabbarItem)

Vue.prototype.$toast = Toast
Vue.prototype.$dialog = Dialog

element-ui按需导入

参考官网:https://element.eleme.cn/#/zh-CN/component/quickstart

如果是项目用到的element-ui组件较多,更建议通过cdn的方式引入element-ui,因为element-ui体积还是很大的,不适合打包到项目里。

使用gzip

Vue启用gzip压缩

Vue使用gzip压缩,可以使Vue在打包时为js/css/html打包对应的gz压缩文件。

1)安装compression-webpack-plugin

npm i compression-webpack-plugin@4 -D

安装时需要注意 compression-webpack-plugin的版本和webpack的版本是否对应,不对应可能会出错。

compression-webpack-plugin7.x, 对应 webpack 5.9

compression-webpack-plugin4.x, 对应 webpack 5.x

compression-webpack-plugin3.x, 对应 webpack 4.x

compression-webpack-plugin 1.x 对应 webpack 3.x

具体版本要求请参考 Github

如果是vue-cli 3.x项目,修改vue.config.js

// 链式配置webpack
  chainWebpack: config => {
    if(isProduction){ //生产环境下
      // 启用gzip
      const CompressionPlugin = require('compression-webpack-plugin')
      config.plugin('compressionPlugin').use(new CompressionPlugin({
        test: /\.js$|\.css$|\.html$/, // 匹配文件名
        threshold: 10240,           // 对超过10k的数据压缩
        deleteOriginalAssets: false // 不删除源文件
      }))
    }
  },

如果是vue-cli 2.x项目,只需要修改config/index.js,设置下面两项

productionGzip: true,
productionGzipExtensions: ['js', 'css', 'html'],

打包成功后,查看项目js目录:

在这里插入图片描述

服务端使用gzip压缩

Nginx可以开启gzip,Express等其他服务器也可以。这里使用了Express作为服务器。

问题1: Express如何启动gzip压缩?

回答:先安装compression,然后启用的代码如下:

const express = require("express");
const compression = require('compression')

const app = express();
// 注意:compression这个中间件一定要放在最开始,否则可能不生效。compression(options)可以通过options进行配置
app.use(compression())
app.use(express.static('public'))


app.listen(8088, function () {
  console.log("Express-static started on port 8088");
});

问题2: 如何判断后端gzip生效?

答:在浏览器的Network中,查看资源的响应头的Content-Encoding属性,如果是gzip那么说明生效了。

在这里插入图片描述

问题3: 后端开启gzip,就会将相应文件压缩,浏览器就能识别,就已经起到优化的效果了,为什么还需要Vue打包时开启gzip?

回答:服务器拿到请求时会判断是否启动gzip压缩,如果启动则会将请求的资源进行压缩再返回给浏览器,但是压缩这个过程时消耗时间和内存等资源的。所以提前准备好对应的gz文件可以节省时间和服务器资源。

浏览器的请求资源的策略

浏览器第一次访问
在这里插入图片描述

浏览器第二次访问
在这里插入图片描述

显然浏览器对访问的资源做了一个缓存,第二次访问时只需要发必要的请求确认数据完整性即可,不会去获取实际数据。

另外值得说明的是,cdn资源在浏览器访问一次后会有磁盘缓存,之后访问会直接从磁盘缓存中读取。看下图:

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值