tianyin 2019-06-28
在本次教程中,我们聚焦于如何在你的应用中减少输出文件的体积,从而提升用户体验。这意味着在生产环境下要用不同的方式来处理代码。今天我们将阐述webpack通过mode参数来设置其内置的优化措施, 开始吧。
首先,我们回答究竟为什么要优化你的代码这个问题。如果你有良好编程实践,你可能注重代码的可读性,因此你在代码中添加了大量的空白符(制表符、空格、换行符)和注释。在代码变得更漂亮的同时,也使得文件的体积大大增加了。另一方面,为了用户体验(指减少文件体积)而牺牲可读性也不可取,手工这么做的话很繁琐。因此,这儿有一种解决方案供你在项目中选择。
Webpack4中引入了一个新参数:mode。要求总是在配置中指定。如果不指定,会产生一个警告并退而其次的使用默认值,默认值就是production。如果你使用 mode:"production", Webpack将配置成生成更适合在生产环境下的代码。我们现在就来看看webpack为我们确切地做了些什么。
将mode值设为production将在配置中添加UglifyJsPlugin插件,它通过压缩和最小化,使得你的代码更短,运行得更快。其任务包括简单的缩短变量名,移除空白符,删除重复代码等等。默认会解析每一个.js文件。这篇博文中,我们将讲述UglifyJSPlugin这个插件最基本的配置。即使webpack 4 依据选择的mode值进行了优化,你仍能通过optimization属性来进行自己的配置。
// webpack.config.js const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); module.exports = { mode: "production", // using mode: "production" attaches the following configuration: optimization: { minimize: true, minimizer: [ new UglifyJsPlugin() ] }, }
传给UglifyJsPlugins插件最要紧的属性是uglifyOptions,它有大量默认的配置。而其中最值得关注的部分是compress属性。
new UglifyJsPlugin({ uglifyOptions: { compress: { /*(...)*/ } } })
它负责UglifyJsPlugin插件的很多重要的举措,从而是你的代码更短,更轻。完整列表请参阅官方文档,其也标记出了默认值。
UglifyJsPlugin插件另外一个重要的属性是output。
new UglifyJsPlugin({ uglifyOptions: { compress: { /*(...)*/ }, output: { /*(...)*/ } } })
默认,代码生成器试图输出最短的代码。你可以通过更改output的配置来改变这一行为。你可能无需对默认值改动太多,但有一个值得考虑的属性:drop_console,默认它的设置值是false。如果改为true,将删除代码中所有的console.log调用。如果想了解更多output的属性,请查阅完整列表。
UglifyJsPlugin还有更多的可能的配置,请参读它在Github上的文档。
这个插件允许你创建全局常量用于编译时解析。如果设置mode:"production",webpack默认会设置"process.env.NODE_ENV": JSON.stringify("production")。
// webpack.config.js module.exports = { mode: "production", // using mode: "production" attaches the following configuration: plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), ] }
注意因为直接文本替换,所给的属性值必须包括引号,要这么做JSON.stringify("production")或'"production"'。
在编译时解析意味着你在代码中使用的process.env.NODE_ENV,将被替换成production这个值。
console.log(process.env.NODE_ENV); if(process.env.NODE_ENV === 'production') { console.log('this is production!') }
记住,在webpack编译完代码之后就没有process.env.NODE_ENV这个常量值了。上面的代码在webpack处理之后变成下面的样子:
console.log("production"); if(true) { console.log("this is production!") }
在UglifyJSPlugin插件最小化处理之后,它更是简化为:
console.log("production"); console.log("this is production!")
使用这个插件将赞助你处理编译期间的错误。例如,可能出现你试图导入一个webpack不能解析(译注:就是找不到啦)的文件的情形。此时,Webpack会创建一个有错误信息的新版应用。如果使用NoEmitOnErrorsPlugin,就根本不会创建这个版本。
(译注:原文是这样子的:
Using this plugin will help you deal with errors during the compilation. For example, there might be a situation in which you try to import a file that Webpack can’t resolve. In this situation, Webpack creates a new version of the application with the information about the error. With the usage of NoEmitOnErrorsPlugin, this version is not created at all.
是不是说得云里雾里?其实意思是,如果没有使用NoEmitOnErrorsPlugin,当发生错误时,就会重载一个有错误信息的页面,把用户的屏幕搞花。使用NoEmitOnErrorsPlugin插件,就不会加载这个页面了,错误信息只是在控制台中输出)
// webpack.config.js const webpack = require('webpack'); module.exports = { mode: "production", // using mode: "production" attaches the following configuration: plugins: [ new webpack.NoEmitOnErrorsPlugin(); ] }
Webpack默认将每一个模块包装在独立的闭包函数中,这个包装函数使得javascript的执行稍微变慢了一点。看看下面的例子:
// one.js const dog = 'Fluffy'; export const one = 1;
// two.js const dog = 'Fluffy'; export const two = 2;
// index.js import { one } from './one'; import { two } from './two'; const dog = 'Fluffy'; console.log(one, two);
如没有ModuleConcatenationPlugin插件,输出的打包象这个样子:
// main.js (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony import */ var _one__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony import */ var _two__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); const dog = 'Fluffy'; console.log(_one__WEBPACK_IMPORTED_MODULE_0__["one"], _two__WEBPACK_IMPORTED_MODULE_1__["two"]); /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "one", function() { return one; }); const dog = 'Fluffy'; const one = 1; /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "two", function() { return two; }); const dog = 'Fluffy'; const two = 2; /***/ }) /******/ ]);
当设置mode为production,ModuleConcatenationPlugin插件就会尽心尽责。谢天谢地,现在输出的打包在一个作用域里了。更少的函数意味着更少的运行时开销。
注意,这个例子中我没有进行任何缩小化。由于缩小化器现在知道了模块间的依赖,它能更好的干活。
// main.js (function(module, __webpack_exports__, __webpack_require__) { "use strict"; // CONCATENATED MODULE: ./src/one.js const dog = 'Fluffy'; const one = 1; // CONCATENATED MODULE: ./src/two.js const two_dog = 'Fluffy'; const two = 2; // CONCATENATED MODULE: ./src/index.js const src_dog = 'Fluffy'; console.log(one, two); /***/ }) /******/ ]);
如果你觉得有趣,请阅读article on the webpack blog上针对这一特性的博文。
今天我们学习了配置mode:'production'时Webpack能做的内置优化措施。这样使得你的应用加载得更快,执行得更好。经过一系列的配置处理,达到如此目标,从而满足产品需要。下一个教程我们将覆盖开发模式下的配置,敬请期待!