浏览器从服务器访问网页时获取的 JavaScript、CSS 资源都是文本形式的,文件越大网页加载时间越长。 为了提升网页加速速度和减少网络传输流量,可以对这些资源进行压缩。 压缩的方法除了可以通过 GZIP 算法对文件压缩外,还可以对文本本身进行压缩。
对文本本身进行压缩的作用除了有提升网页加载速度的优势外,还具有混淆源码的作用。 由于压缩后的代码可读性非常差,就算别人下载到了网页的代码,也大大增加了代码分析和改造的难度。
下面来一一介绍如何在 Webpack 中压缩代码。
目前最成熟的 JavaScript 代码压缩工具是 UglifyJS, 它会分析 JavaScript 代码语法树,理解代码含义,从而能做到诸如去掉无效代码、去掉日志输出代码、缩短变量名等优化。
要在 Webpack 中接入 UglifyJS 需要通过插件的形式,目前有两个成熟的插件,分别是:
由于 ParallelUglifyPlugin 在4-4使用ParallelUglifyPlugin中介绍过就不再复述, 这里重点介绍如何配置 UglifyJS 以达到最优化的压缩 JavaScript 代码。
UglifyJS 提供了非常多的选择用于配置在压缩过程中采用哪些规则,所有的选型说明可以在其官方文档上看到。 由于选项非常多,就挑出一些常用的拿出来详细讲解其应用方式:
sourceMap
beautify
false
comments
compress.warnings
drop_console
console
collapse_vars
var x = 5; y = x
y = 5
reduce_vars
x = 'Hello'; y = 'Hello'
var a = 'Hello'; x = a; y = b
也就是说,在不影响代码正确执行的前提下,最优化的代码压缩配置为如下:
const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin'); module.exports = { plugins: [ // 压缩输出的 JS 代码 new UglifyJSPlugin({ compress: { // 在UglifyJs删除没有用到的代码时不输出警告 warnings: false, // 删除所有的 `console` 语句,可以兼容ie浏览器 drop_console: true, // 内嵌定义了但是只用到一次的变量 collapse_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值 reduce_vars: true, }, output: { // 最紧凑的输出 beautify: false, // 删除所有的注释 comments: false, } }), ], };
从以上配置中可以看出 Webpack 内置了 UglifyJsPlugin,需要指出的是 UglifyJsPlugin 当前采用的是 UglifyJS2 而不是老的 UglifyJS1, 这两个版本的 UglifyJS 在配置上有所区别,看文档时注意版本。
除此之外 Webpack 还提供了一个更简便的方法来接入 UglifyJSPlugin,直接在启动 Webpack 时带上 --optimize-minimize 参数,即 webpack --optimize-minimize, 这样 Webpack 会自动为你注入一个带有默认配置的 UglifyJSPlugin。
--optimize-minimize
webpack --optimize-minimize
本实例提供项目完整代码
虽然当前大多数 JavaScript 引擎还不完全支持 ES6 中的新特性,但在一些特定的运行环境下已经可以直接执行 ES6 代码了,例如最新版的 Chrome、ReactNative 的引擎 JavaScriptCore。
运行 ES6 的代码相比于转换后的 ES5 代码有如下优点:
const
所以在运行环境允许的情况下,我们要尽可能的使用原生的 ES6 代码去运行,而不是转换后的 ES5 代码。
在你用上面所讲的压缩方法去压缩 ES6 代码时,你会发现 UglifyJS 会报错退出,原因是 UglifyJS 只认识 ES5 语法的代码。 为了压缩 ES6 代码,需要使用专门针对 ES6 代码的 UglifyES。
UglifyES 和 UglifyJS 来自同一个项目的不同分支,它们的配置项基本相同,只是接入 Webpack 时有所区别。 在给 Webpack 接入 UglifyES 时,不能使用内置的 UglifyJsPlugin,而是需要单独安装和使用最新版本的 uglifyjs-webpack-plugin。 安装方法如下:
npm i -D uglifyjs-webpack-plugin@beta
Webpack 相关配置代码如下:
const UglifyESPlugin = require('uglifyjs-webpack-plugin') module.exports = { plugins: [ new UglifyESPlugin({ // 多嵌套了一层 uglifyOptions: { compress: { // 在UglifyJs删除没有用到的代码时不输出警告 warnings: false, // 删除所有的 `console` 语句,可以兼容ie浏览器 drop_console: true, // 内嵌定义了但是只用到一次的变量 collapse_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值 reduce_vars: true, }, output: { // 最紧凑的输出 beautify: false, // 删除所有的注释 comments: false, } } }) ] }
同时,为了不让 babel-loader 输出 ES5 语法的代码,需要去掉 .babelrc 配置文件中的 babel-preset-env,但是其它的比如 babel-preset-react 还是要保留, 因为正是 babel-preset-env 负责把 ES6 代码转换为 ES5 代码。
.babelrc
babel-preset-env
babel-preset-react
CSS 代码也可以像 JavaScript 那样被压缩,以达到提升加载速度和代码混淆的作用。 目前比较成熟可靠的 CSS 压缩工具是 cssnano,基于 PostCSS。
cssnano 能理解 CSS 代码的含义,而不仅仅是删掉空格,例如:
margin: 10px 20px 10px 20px
margin: 10px 20px
color: #ff0000
color:red
还有很多压缩规则可以去其官网查看,通常压缩率能达到 60%。
把 cssnano 接入到 Webpack 中也非常简单,因为 css-loader 已经将其内置了,要开启 cssnano 去压缩代码只需要开启 css-loader 的 minimize 选项。 相关 Webpack 配置如下:
const path = require('path'); const {WebPlugin} = require('web-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { module: { rules: [ { test: /\.css/,// 增加对 CSS 文件的支持 // 提取出 Chunk 中的 CSS 代码到单独的文件中 use: ExtractTextPlugin.extract({ // 通过 minimize 选项压缩 CSS 代码 use: ['css-loader?minimize'] }), }, ] }, plugins: [ // 用 WebPlugin 生成对应的 HTML 文件 new WebPlugin({ template: './template.html', // HTML 模版文件所在的文件路径 filename: 'index.html' // 输出的 HTML 的文件名称 }), new ExtractTextPlugin({ filename: `[name]_[contenthash:8].css`,// 给输出的 CSS 文件名称加上 hash 值 }), ], };
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8