本文为腾讯移动分析MTA 产品UI工程师linji的分享。javascript
聚焦webpack2的部分目录:css
简单地归纳--webpack是一个智能模块依赖分析的打包工具,它经过入口js文件以及一系列的插件能把各类资源文件编译、打包为可发布使用的静态资源。如官网中的视图:万物皆模块。
html
文章撰写时webpack最新正式版版本号为2.5.1。前端
命令行工具中安装:java
# 全局安装
npm install -g webpack
# 初始化项目
npm init
#安装到项目目录中
npm install --save-dev webpack复制代码
在根目录建立以下文件:
entry.js -- 入口文件node
import fn from './fn';
fn();复制代码
fn.js -- 被引用的模块react
export default function fn() {
document.write('I am a Function');
}复制代码
webpack.config.js -- webpack配置文件webpack
module.exports = {
entry: './entry.js',
output: {
filename: 'bundle.js'
}
}复制代码
index.html -- 静态页面git
<!DOCTYPE html>
<html>
<body>
<script src="./bundle.js"></script>
</body>
</html>复制代码
在项目目录中执行命令 webpack
,而后在浏览器打开上面的静态页面就能够看到效果了es6
如今简单列出我认为对比webpack1版比较明显的变化
ES6模块的静态导入(import等部分ES6语法的原生支持): 更快捷的初始化工程
ES6模块的动态导入:按官方文档描述,这种动态导入方式正尝试加入到ES的规范之中
export default function async() {
console.log('异步引用');
}复制代码
entry.js 加入代码
import('./async').then(async => {
async.default();
});
// 等价于
/* require.ensure([], (require) => { const async = require('./async'); async.default(); }); */复制代码
import()返回的是promise实例,因此咱们还能够经过
Promise.all([import('./async')]).then(([async]) => {})
的形式去引用多个模块;不过,当你须要兼容IE8-的浏览器时,你须要额外导入promise-polyfill。System.import()和import()方法做用相同,在本文撰写期间的2.5.x版本前者依然可使用,但官方文档有指出这个方法不建议使用
修复ugulifyJS压缩css文件时误删除[dpr]问题:固然咱们能够经过别的工具去代替
函数方式导出配置:能够经过参数来代替设置复杂的环境变量
webpack --env.dev
module.exports = function(env) {
return {
entry: './entry.js',
output: {
filename: 'bundle.js'
},
// 新的“环境变量”使用方式 (此处新增了sourcemap)
devtool: env.dev
? 'cheap-module-eval-source-map'
: false
};
};复制代码
module.loaders
--> modules.rules
使用loader时须要把loader名字写全,如 style
须要写为 style-loader
移除 module.preLoaders, module.postLoaders
如今经过module.rules.enforce
属性来配置
再也不须要手动加入 DedupePlugin
, OccurrenceOrderPlugin
, json-loader
, devServer.inline
等配置
毕竟几乎你们都须要用到它们
webpack-dev-server
, extract-text-webpack-plugin
, html-webpack-plugin
这三个经常使用的工具必须升级到2.x版本,不然没法和webpack2做用
合并分散的resolve配置 resolve.root, resolve.fallback, resolve.modulesDirectories
经过配置好 resolve.modules
有助于提升定位引用文件的速度
const path = require('path');
module.exports = function(env) {
return {
// ...
resolve: {
modules: [
path.resolve(__dirname, 'node_modules'),
],
}
};
};复制代码
下图为之前一次把个迷你项目从webpack1升级到webpack2的基本配置变动
![]()
Tree shaking 示例
修改fn.js
// ...
export function unused(){
document.write('I am an unused Function');
}复制代码
修改entry.js
import fn, {unused} from './fn';
fn();
// ...复制代码
执行 webpack --env
(这里不使用env.dev来查看较为美观的打包代码)后,咱们会发现生成的bundle代码中出现以下片断
webpack --optimize-minimize --env
,打包的代码通过压缩处理后,unused()
这个没有被调用的函数被完全删掉了。Tree shaking 起源
在前端圈子中,该解释 “起源”于 rollup.js 做者。
Rollup中的 Tree-shaking 是无用代码移除(DCE, dead code elimination)的一种实现。利用AST(Abstract Syntax Tree,译做 抽象语法树),找到被使用的代码块而后注入到输出文件中。而Webpack2“原生”支持的ES6模块静态性引用,能够帮助标记编译后的多余代码,并在压缩时"甩掉"它们。
更多关于抽象语法树的理解能够经过在线抽象语法树解释工具去自行体验
ES6模块的静态性的做用:
快速定位代码
使用Commonjs去引用库的时候,调用其子属性会触发对象属性查表,这会下降编译的效率
const lib = require('lib'); lib.someFunc(); // 属性查表
而import的静态特性使其跳过这个步骤;
import * as lib from 'lib'; lib.someFunc(); // 静态处理
提升变量校验效率
Tree shaking 横向对比babel-plugin-import
是一个类tree shaking的babel插件,它可以把 import { Button } from ‘antd’;
这种代码转换为 import Button ‘antd/lib/button’;
的形式。
现在的webpack2的tree shaking 主要适用范围以下import {lastName} form 'name';
-- named importimport name from 'name';
-- default importimport * as all from 'name;
const name = require('name');
现在并非全部开源组件都提供ES6模块的代码,因此若是想最有效的去除多余代码,把 babel-plugin-import 和 webpack2 Tree shaking组合使用来打包压缩生产环境的代码为当下最优选择。
Webpack2 和 Babel 组合的短暂演变
在使用webpack的同时,咱们大多都须要使用到babel来支持转换ES六、ES七、TS等一系列语法糖,那一旦使用babel,务必要防止babel对import语法先行处理。为了达到这个目的,babel的配置也经历过比较明显的转变最终简单易懂:
该速度对比数据为一样代码每项执行5次后取最大时长的数据,代码以下:
import react from 'react'; // react15.5.4 不提供ES6模块
import {compose} from 'refux'; // redux3.6.0 提供ES6模块复制代码
webpack1 | webpack2 | |
---|---|---|
dev-server 启动服务 | 2187ms | 2252ms |
dev-server 文件更改 | 41ms | 27ms |
production | 1991ms | 2057ms |
webpack1 | webpack2 | |
---|---|---|
dev-server | 1.38MB | 1.75MB |
production | 53.3kB | 48.5kB |
因而可知,在开发过程当中,webpack2打包速度较快但需加载的代码文件大小较大;生产环境代码webpack2生成的文件体积更小(但这要求开发者遵循使用ES6模块的写法)
我的最后总结的优缺点以下
随着webpack2版本迭代,以上缺点正慢慢改正
我想不到任何一个不升级的理由,毕竟这是正式版了。:) 如文中有与实际不对等的状况,务必告诉我好让我能撇除误解~~~
webpack2处理原生ES6 Module时,没法使用babel-plugin-add-module-exports插件。该插件能让babel6处理export时,如同babel5同样,生成语句 module.exports = exports["default"]
;webpack2中export default转换后为 __webpack_exports__["default"]
而非 exports["default"]
,故执行代码时会报错。