8. webpack4-vue2 性能优化

463 阅读2分钟

vue2-webpack4-project

1. 压缩 index.html

压缩 index.html ,通过 html-webpack-plugin 实现。通过属性 options.minify 实现,该属性在 production 模式自动设定为 ture ,所以有两种方式实现 。

  • 修改 webpack 打包模式为 production :生产环境默认配置
  • 设置 options.minify 为 true:开发环境配置,方便对比效果

压缩前

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>8. 性能优化</title>
    <meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body>
<!-- vue 挂载元素 -->
<div id="app"></div>
<script src="main.bundle.js"></script></body>
</html>

修改 webpack.config.js

new HtmlWebpackPlugin({
    //指定模板路径
    template: path.resolve(process.cwd(), 'public/index.html'),
    minify: true
}),

压缩后

<!doctype html><html><head><meta charset="utf-8"><title>8. 性能优化</title><meta name="viewport" content="width=device-width,initial-scale=1"></head><body><div id="app"></div><script src="main.bundle.js"></script></body></html>

2. 压缩 JavaScript

生产环境下默认使用 TerserPlugin ,并且也是代码压缩方面比较好的选择。

压缩前

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
            .....
/******/ });

压缩后

!function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}}; ...... new r.a({render:t=>t(p)}).$mount("#app")}]);

3. 减少 JavaScript :tree-shaking

参考文档描述:通过 import 和 export 语法,我们已经找出需要删除的“未引用代码(dead code)”,然而,不仅仅是要找出,还要在 bundle 中删除它们。为此,我们需要将 mode 配置选项设置为 production 得出结论 tree-shaking 在 production 模式默认开启,development 模式关闭。下面仅作验证。

3.1 准备 js 文件

<!--修改 textPrint.js-->
export  function textPrint(){
    console.log("textPrint")
}
export  function textPrint2(){
    console.log("textPrint2")
}

3.2 导入并使用 js 文件

<!--App.vue-->
<script>
import {textPrint} from "./js/textPrint";
export default {
  name: "App",
  methods:{
    textClick(){
      textPrint()
    }
  }
}
</script>

3.3 设置 development 模式,并打包

可看到未使用的 textPrint2 函数也在打包文件中。

<!-- mian.boundle.js 部分内容-->
/***/ "./src/js/textPrint.js":
/*!*****************************!*\
  !*** ./src/js/textPrint.js ***!
  \*****************************/
/*! exports provided: textPrint, textPrint2 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"textPrint\", function() { return textPrint; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"textPrint2\", function() { return textPrint2; });\nfunction textPrint(){\r\n    console.log(\"textPrint\")\r\n}\r\nfunction textPrint2(){\r\n    console.log(\"textPrint2\")\r\n}\n\n//# sourceURL=webpack:///./src/js/textPrint.js?");

/***/ }),

3.4 设置 production 模式,并打包

打开 mian.boundle.js ,代码已经经过压缩并混淆。可看到只有已使用的 textPrint,未使用的 textPrint2 函数不在打包文件中。

4. 提取 css

管理资源-加载 CSS中提到:在多数情况下,可以进行 CSS 提取,以便在生产环境中节省加载时间。提取 CSS 通过 mini-css-extract-plugin 完成。

  • 版本选择: 1.6.2
  • 2.x 版本开始要求 webpack5

4.1 安装

yarn add mini-css-extract-plugin@1.6.2 -D

4.2 修改 webpack.config.js

根据建议

  • production 模式使用 mini-css-extract-plugin
  • development/webpack-dev-server 使用 style-loader ,速度更快
  • mini-css-extract-plugin 和 style-loader 不能一起使用
<!--仅展示变更内容-->
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

//定义模式变量,区别加载plugin、loader
const mode = "production";
const devMode = mode !== "production";

module.exports = {
    // 指定打包模式:development、production
    mode: mode,
    // entry 对象是用于 webpack 查找启动并构建 bundle。其上下文是入口文件所处的目录的绝对路径的字符串。
    entry: './src/main.js',
    ......
    plugins: [......].concat(devMode?[]:[new MiniCssExtractPlugin()]),//开发模式不提取 CSS
    ...... 
    module: {
        rules: [
            //添加 vue 支持
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            //添加 css 支持
            {
                test: /\.css$/i,
                // use: ['style-loader', 'css-loader']
                // 开发模式:style-loader ;生产模式:MiniCssExtractPlugin
                use: [ devMode?"style-loader":MiniCssExtractPlugin.loader, 'css-loader']
            },
            ......
        ]
    }
};

4.3 执行打包

打包成功后,dist 文件夹下会生成独立的css文件:main.css,内容如下

/*加载字体*/
@font-face {
    /*名称可自定义*/
    font-family: "MyFont";
    /*填写真实路径*/
    src:url(c05a24bab81b62ecb5db2ffcef97e5a1.ttf);
    font-weight: 600;
    font-style: normal;
}

.hello[data-v-7ba5bd90] {
  color: red;
  /*引用字体*/
  font-family: "MyFont";
}

5. 压缩 css:css-抽取分割

生产环境-最小化 CSS 中提到需要压缩CSS,通过 optimize-css-assets-webpack-plugin 实现压缩功能。

5.1 安装

 yarn add optimize-css-assets-webpack-plugin -D

5.2 修改 webpack.config.js

<!--仅展示变更内容-->
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

//定义模式变量,区别加载plugin、loader
const mode = "production";
const devMode = mode !== "production";

module.exports = {
    ......
    optimization: {
        //开发模式不提取 CSS
        minimizer: [].concat(devMode?[]:[new OptimizeCSSAssetsPlugin({})])
    },
   ......
};


5.3 执行打包

打包成功后,dist 文件夹下会生成压缩后独立的css文件:main.css,内容如下

@font-face{font-family:MyFont;font-style:normal;font-weight:600;src:url(c05a24bab81b62ecb5db2ffcef97e5a1.ttf)}.hello[data-v-7ba5bd90]{color:red;font-family:MyFont}

6. 压缩图片:image-webpack-loader

管理资源-加载图片看到可以使用 image-webpack-loaderurl-loader 压缩和优化图像加载。

6.1 安装

yarn add image-webpack-loader -D

6.2 修改 webpack.config.js

<!--仅展示修改部分-->
//添加 图片 支持
{
    test: /\.(png|jpe?g|gif)$/i,
    use: [
        {
            loader: 'file-loader',
        },
        {
            loader: 'image-webpack-loader',
            options: {
                // webpack@2.x and newer
                disable: devMode,
            },
        },
    ],
},

6.3 添加图片资源并加载

<!--仅展示修改部分-->
<!--App.vue-->
<template>
<div class="hello" @click="textClick">
  Hello webpack !
  <img :src="iconImage">
  <img :src="iconImage2">
  <img :src="chartImage">
</div>
</template>

<script>
import {textPrint} from "./js/textPrint";
import iconImage from "./image/icon.jpg";
import iconImage2 from "./image/image2.jpeg";
import chartImage from "./image/chart.png";
export default {
  name: "App",
  data(){
    return {
      iconImage,iconImage2,chartImage
    }
  },
  methods:{
    textClick(){
      textPrint()
    }
  }
}
</script>

6.4 执行打包

打包成功后,dist 文件夹下会生成压缩后图片文件,和原图片相比,体积都有减少,且图片均可正常查看

7. 优化图片加载:url-loader

url-loaderfile-loader 类似, 但是在文件体积小于设定值时可以生成 DataURL 。

7.1 安装

 yarn add url-loader -D

7.2 修改 webpack.config.js

<!--仅展示修改部分-->
//添加 图片 支持
{
    test: /\.(png|jpe?g|gif)$/i,
    use: [
        {
            loader: 'url-loader',
            options: {
                //单位:bytes (icon 图片压缩后的体积2小于 25K)
                limit: 25 *1024,
            },
        },
        {
            loader: 'image-webpack-loader',
            options: {
                // webpack@2.x and newer
                disable: devMode,
            },
        },
    ],
},

7.3 执行打包

打包成功后,dist 文件夹下会生成压缩后图片文件,和上一次打包结果相比,图片少了1张(icon.jpg),由于压缩后体积小于设置的 25KB ,被转换成 DataURL 保存到 main.boundle.js 文件中。

<!--main.boundle.js 部分代码-->
// CONCATENATED MODULE: ./src/image/icon.jpg
/* harmony default export */ var icon = ("data:image/jpeg;base64,/9j/4AAQSC ...... ZTA0hJNM/7pf/2Q==");
// CONCATENATED MODULE: ./src/image/image2.jpeg
/* harmony default export */ var image2 = (__webpack_require__.p + "04d45412dbd83a892814b6f22b6fa7ab.jpeg");
// CONCATENATED MODULE: ./src/image/chart.png
/* harmony default export */ var chart = (__webpack_require__.p + "4e86cf63c020e3fcda7d732d1f0e82e3.png");
// CONCATENATED MODULE: ./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&