开始使用 Webpack

安装

前提:已经安装了nodejs & npm
有了 npm 后安装非常的方便,不论是在windows还是mac下, 只需要一句

1
npm install webpack -g

就可以把 webpack 安装在全局环境下,然后就可以在terminal 或者是 cmd 里直接使用 webpack 了。一般在项目的目录下使用的时候会加上 –save-dev 这个参数

1
npm install webpack --save-dev

打包

假设目录下有一个 app.js 文件

1
2
3
function helloworld () {
alert('hello world!');
}

在命令行中输入:

1
webpack ./app.js ./bundle.js

发现目录下已经生成了一个 bundle.js 文件,并且伴随着一个 webpack 任务的完成信息的输出

webpack task

输出的信息:

  • 这次打包的MD5(Hash)
  • Webpack 的版本号(Version)
  • 还有打包花费的时间(Time)

随后会看到一个列表:

  • 打包后的文件名称 Asset
  • 包大小 Size
  • 代码块编号 Chunks
  • 代码块名称 Chunk Names

打开bundle.js 会看到已经生成了的文件, 下面的代码为了方便阅读去掉了不必要的注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
(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] = {
exports: {},
id: moduleId,
loaded: false
};
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
// Flag the module as loaded
module.loaded = true;
// Return the exports of the module
return module.exports;
}
// expose the modules object (__webpack_modules__)
__webpack_require__.m = modules;
// expose the module cache
__webpack_require__.c = installedModules;
// __webpack_public_path__
__webpack_require__.p = "";
// Load entry module and return exports
return __webpack_require__(0);
})([
/* 0 */function(module, exports) {
function helloworld () {
alert('hello world!');
}
}]);

为了更了解webpack打包的工作原理以及打包后的代码在浏览器中的如何运行,阅读了一下生成后的代码
整个代码是一个自运行函数,分两部分:

  • 第一部分可以理解是webpack启动架,其中定义了一个空对象(installedModules)来存放 webpack modules,定义了webpack 运行环境下的require函数(’webpack_require‘),最后这一句:webpack_require(0) 是把作为参数传入的实际代码通过require函数执行了一遍
  • 第二部分是 app.js里的实际代码,前面的注释是webpack 给实际代码模块的 moduleId ,在app.js 的实际代码外面多了一个匿名函数,把参数module,export,webpack_require传了进来,方便实际 app.js里的代码使用。

模块化

webpack 支持多种js模块方案的打包:

  • ES6 modules
  • Commonjs
  • AMD

假设有两个js 文件,一个是 app.js, 另一个 util.js,utils里的内容如下:

1
2
3
4
5
6
7
// CommonJs 规范的模块化
// utils.js
module.exports = {
say: function (word) {
alert(word);
}
};

app.js 加入对util的引用

1
2
3
4
5
var util = require(./util.js);
function helloworld () {
util.say('hello world!');
}

打包完的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
([
/* 0 */function(module, exports, __webpack_require__) {
var util = __webpack_require__(1)
function helloworld () {
util.say('hello world!');
}
},
/* 1 */function(module, exports) {
module.exports = {
say: function (word) {
alert(word);
}
};
}]);

发现在bundle.js 里,app里引用的util.js的地址已经变为webpack的moduleId了,require也被替换为webpack的启动架中定义的webpack_require方法。每个模块都被编号,app.js 为 0, util.js 为 1。在代码中使用了require 方法的,外面匿名函数传入的参数也增加了webpack_require。


强大的 Webpack

背景

Webpack 已经随着 react 火了一段时间,不得不说前端的变化十分的快。每年都有新东西出来,Webpack 还没有玩热,又来了一个rollup,号称是下一代的打包工具。对前端来说,一涉及到性能,开发方式,打包就是一个回避不了的问题,在前端还没有这么百花齐放的过去也是这样。最早的时候用各种后台语言写的 combo 合并工具,后来是 ant,还有 Google closure compiler,再后来node 开始发展起来,随后伴随着node 的生态圈 Grunt Gulp 国内的 Fis 都开始流行起来。来到如今已经是一个百花齐放百家争鸣的好时代,任何优秀的工具都可以流行起来。早在前端 Bigpipe 技术被提出的时候,模块化开发的雏形就已经奠定,后来代码组织方式从早期的命名空间,到后来Commonjs规范,AMD 规范,以及国内的 CMD 规范都是为了解决代码如何模块化开发的问题。ES6规范的发布给了前端模块化开发先天的支持,意味着前端模块化开发可以通过各种辅助工具进入到下一个时代。

早在Webpack 刚刚发布我就尝试了一下,当时几乎没有中文资料,偶尔国内 React社区 能翻到一下开荒的文章,自己花费了一些时间跑起来,但是很快也就被自己抛到脑后还是继续使用gulp。现在回想起来很大原因还是开发方式的问题,当时还没有使用 Babel 和 ES6, 也没有在代码中时刻 import 的习惯。所以可见每个工具其实是和开发方式和代码组织密切分不开的,近来模块化大行其道,各种前端MVVM 框架层出不穷,Webpack 已经成为项目工程化的标配。最近也开始在项目中使用Vue + Vuex + ES6 + Webpack 真实感受到了webpack 的各种便利。

Webpack Introduction

官方文档 http://webpack.github.io/docs/

官方的介绍是 MODULE BUNDLER (模块打包器), 就是一个打包工具。从官方的定义来看似乎很纯粹,就是一个打包工具其他的事情Webpack不管,但实际上通过Webpack可以

  • 模块打包
    webpack 会从入口开始去分析你的模块依赖从而把你的代码合并在一起生成一个文件,或是多个。

  • 模块化开发
    webpack 视万物为模块,无论是 js 还是 css 还是 图片,字体,以及其他资源,Webpack 都可以使用的简单的一句import 或是require 就可以让你在项目中使用你的引入的资源

  • 处理资源
    webpack 使用各种loader 来处理资源,常见的loader比如 style-loader, css-loader, less-loader, bable-loader, url-loader 框架相关的loader比如:jsx-loader, vue-loader

    • 压缩,混淆 es6, js
      使用bable-loader 来转换 es6 的语法
      可以使用 eslint-loader 验证你的js,官方提供 UglifyJsPlugin 插件来压缩混淆js

    • 处理css,less, sass, postcss
      可以通过 postcss-loader 来预处理css,比如加上css 属性的不同浏览器前缀

    • 处理图片,字体
      可以通过 url-loader 来把不需要外链的资源统统转为base64编码
      可以使用第三方插件 ImageminPlugin 对所有图片进行压缩

  • 自动合并共用代码
    webpack 的官方插件 CommonsChunkPlugin,你可以自由控制粒度

  • 搭建开发服务器
    使用 webpack-dev-server
    或使用 koa/express + webpack-hot-middle + webpack-dev-middle

  • 自动刷新浏览器
    liveloading小意思,webpack可以模块热更新,就是说局部更改代码比你刷新浏览器更快

  • 最小化引入资源
    下一代 rollup 的打包工具最耀眼的功能就是支持 treeshaking 了,而 webpack 2.0 也支持

Webpack 还有很多有用的功能:解析资源别名使你不用在import 后面写一大长串路径。你担心调试的时候找不到哪行代码,可以使用devtool的 sourcemap。如果你不想你的css 打包到js 里你可以使用 ExtractTextPlugin 来抽取css。你也可以配合 http-proxy-middleware 来做远程接口转发,由于开发的时候静态资源服务器是node,所以有各式各样的 middleware 来满足你的各种需求。

Webpack 强大和灵活的地方是他的 plugin 和 loader,通过 loader 可以很轻易的对任何匹配的资源做操作,通过 plugin 则可以参与处理打包的阶段。再者他还提供了 middleware 的方式,可以配合 koa, express 一起使用。