模块化工具webpack基础篇

前言

webpack是目前前端开发必不可少的一款模块加载器兼构建工具,它能极其方便的处理各种资源的打包和使用, 让前端开发获得与后端开发几乎一致的体验。

Webpack是什么

CommonJS 和 AMD 是用于 JavaScript 模块管理的两大规范,前者定义的是模块的同步加载,主要用于NodeJS;而后者则是异步加载,通过 requirejs 等工具适用于前端。随着 npm 成为主流的 JavaScript 组件发布平台,越来越多的前端项目也依赖于 npm 上的项目,或者自身就会发布到 npm 平台。因此,让前端项目更方便的使用 npm 上的资源成为一大需求。

web开发中常用到的静态资源主要有JavaScript、CSS、图片、Jade等文件,webpack中将静态资源文件称之为模块。webpack是一个module bundler(模块打包工具),其可以兼容多种js书写规范,且可以处理模块间的依赖关系,具有更强大的js模块化的功能。Webpack对它们进行统一的管理以及打包发布,其官方主页用下面这张图来说明Webpack的作用:

webpack

Webpack的核心原理

Webpack的两个最核心的原理分别是:

1.一切皆模块
正如js文件可以是一个“模块(module)”一样,其他的(如css、image或html)文件也可视作模 块。因此,你可以require(‘myJSfile.js’)亦可以require(‘myCSSfile.css’)。这意味着我们可以将事物(业务)分割成更小的易于管理的片段,从而达到重复利用等的目的。

2.按需加载
传统的模块打包工具(module bundlers)最终将所有的模块编译生成一个庞大的bundle.js文件。但是在真实的app里边,“bundle.js”文件可能有10M到15M之大可能会导致应用一直处于加载中状态。因此Webpack使用许多特性来分割代码然后生成多个“bundle”文件,而且异步加载部分代码以实现按需加载。

Webpack特点

  1. 对 CommonJS 、 AMD 、ES6的语法做了兼容
  2. 对js、css、图片等资源文件都支持打包
  3. 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持
  4. 有独立的配置文件webpack.config.js
  5. 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间
  6. 支持 SourceUrls 和 SourceMaps,易于调试
  7. 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活
  8. webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快

Webpack安装和配置

安装

webpack 可以作为全局的 npm 模块安装,也可以在当前项目中安装。

1
2
npm install -g webpack  //全局安装
npm install --save-dev webpack //局部安装

对于全局安装的webpack,直接执行此命令会默认使用当前目录的webpack.config.js作为配置文件。如果要指定另外的配置文件,可以执行:

1
webpack —config webpack.custom.config.js

配置

每个项目下都必须配置有一个 webpack.config.js ,它的作用如同常规的 gulpfile.js/Gruntfile.js ,就是一个配置项,告诉 webpack 它需要做什么。

webpack.config.js文件通常放在项目的根目录中,它本身也是一个标准的Commonjs规范的模块。在导出的配置对象中有几个关键的参数:

entry

entry 参数定义了打包后的入口文件,可以是个字符串或数组或者是对象;如果是数组,数组中的所有文件会打包生成一个filename文件;如果是对象,可以将不同的文件构建成不同的文件:

1
2
3
4
5
6
7
8
9
10
11
12
{
entry: {
index: "./page1/index.js",
//支持数组形式,将加载数组中的所有模块,但以最后一个模块作为输出
login: ["./entry1/login.js", "./entry2/register.js"]
},
output: {
path: "dist/js/page",
publicPath: "/output/",
filename: "[chunk].[name].bundle.js"
}
}

ps: chunk:被entry所依赖的额外的代码块,同样可以包含一个或者多个文件

该段代码最终会生成一个 page1.bundle.js 和 page2.bundle.js,并存放到 ./dist/js/page 文件夹下

output

output参数是个对象,定义了输出文件的位置及名字:

1
2
3
4
5
6
7
8
9
10
11
12
13
output: {
path: path.resolve(__dirname, "build"), //打包输出路径,建议使用绝对路径,使用webpack-dev-server, 可将该目录设置为为虚拟web服务器的根目录

// 配置文件在html中引用的根路径,改变静态资源引入的相对路径
publicPath: "/assets/",
//publicPath: "http://cdn.com/assets/",//可加上完整的url,效果与上面一致

// filename 指输出的每个js模块名称及存放路径的定义,会影响在html中模块的引用路径
filename: "js/bundle.js", // 单页应用只有一个入口文件时使用,在html页面上通过<script src="/js/bundle.js"></script>引用入口模块
filename: "js/[name].js", // 传统多页应用有多个入口文件时使用,[name] 代入entry配置中的任意一项模块的名称,如:index, 在不同的页面上引用不同的入口,例如在index.html页面上通过<script src="/js/index.js"></script>引用入口模块
filename: "js/[hash]/[chunkhash].js", // 为生产环境实现前端静态资源增量更新时使用,[hash]是根据每次编译后项目总体文件的hash值, [chunkhash]是根据每个模块内容计算出的hash值

}

path: 打包文件存放的绝对路径
publicPath: 网站运行时的访问路径
filename:打包后的文件名
当我们在entry中定义构建多个文件时,filename可以对应的更改为[name].js用于定义不同文件构建后的名字。

module

在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等静态文件都是模块,不同模块的加载是通过模块加载器(webpack-loader)来统一管理的。loaders之间是可以串联的,一个加载器的输出可以作为下一个加载器的输入,最终返回到JavaScript上:

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
47
48
49
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
//query和options功能相同,推荐使用option
options: {
loaders: {
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
},
//把要处理的目录包括进来,多个用[]数组,单个直接写入
include: [
path.resolve(__dirname, "app")
],
//排除不处理的目录
exclude: /node_modules/
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/, //排除node_modules文件夹
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'file-loader',
query: {
limit: 8192,
name: './images/[name].[ext]?[hash]'
},

},
// 使用多个插件,使用use,sass文件使用style-loader, css-loader, less-loader来处理
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
extractTextPlugin.extract(['style','css', 'less'])
],
}
]
}

注意
webpack 2.x 之后 module.loaders改成了module.rules
webpack1.x中loaders可以链式调用,在2.x中使用rule.use配置项替换
取消在模块中自动添加-loader后缀

resolve

webpack在构建包的时候会按目录的进行文件的查找,resolve属性中的extensions数组中用于配置程序可以自行补全哪些文件后缀:

1
2
3
4
5
6
7
8
9
10
11
12
resolve: {
//查找module的话从这里开始查找
root: '/pomy/github/flux-example/src', //绝对路径
//自动扩展文件后缀名,意味着我们require模块可以省略不写后缀名
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}

然后我们想要加载一个js文件时,只要 require(‘common’)就可以加载common.js文件了。

注意一下, extensions 第一个是空字符串 ! 对应不需要后缀的情况.

plugin

webpack提供了[丰富的组件]用来满足不同的需求,当然我们也可以自行实现一个组件来满足自己的需求:

1
2
3
plugins: [
//your plugins list
]

在webpack中编写js文件时,可以通过require的方式引入其他的静态资源,可通过loader对文件自动解析并打包文件。通常会将js文件打包合并,css文件会在页面的header中嵌入style的方式载入页面。但开发过程中我们并不想将样式打在脚本中,最好可以独立生成css文件,以外链的形式加载。这时extract-text-webpack-plugin插件可以帮我们达到想要的效果。需要使用npm的方式加载插件,然后参见下面的配置,就可以将js中的css文件提取,并以指定的文件名来进行加载。

1
npm install extract-text-webpack-plugin –save-dev
1
2
3
plugins: [
new ExtractTextPlugin('styles.css')
]

externals

防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。

例如,从 CDN 引入 jQuery,而不是把它打包:

1
2
3
<script src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"></script>
1
2
3
externals: {
"jquery": "jQuery"
}

这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:

1
2
3
import $ from 'jquery';

$('.my-element').animate(...);

关于 webpack.config.js 更详尽的配置可以参考 这里

Webpack常用命令

webpack的使用通常有三种方式:

1、命令行使用:webpack 其中entry.js是入口文件,result.js是打包后的输出文件
2、node.js API使用:

1
2
3
4
var webpack = require('webpack');
webpack({
//configuration
}, function(err, stats){});

3、默认使用当前目录的 webpack.config.js 作为配置文件。如果要指定另外的配置文件,可以执行:webpack –config webpack.custom.config.js

webpack 的执行也很简单,直接执行

1
webpack --display-error-details

常用命令

webpack的使用和browserify有些类似,下面列举几个常用命令:

webpack 最基本的启动webpack命令
webpack -w 提供watch方法,实时进行打包更新
webpack -p 对打包后的文件进行压缩
webpack -d 提供SourceMaps,方便调试
webpack –colors 输出结果带彩色,比如:会用红色显示耗时较长的步骤
webpack –profile 输出性能数据,可以看到每一步的耗时
webpack –display-modules 默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块

参考资料:

webpack
webpack中文文档
【翻译向】webpack2 指南(上)
【翻译向】webpack2 指南(中)
【翻译向】webpack2 指南(下)
今天,你升级Webpack2了吗?
webpack使用小记
Webpack 2 有哪些新东西
webpack2 终极优化
基于webpack搭建前端工程解决方案探索
webpack入门
webpack使用优化(基本篇
webPack 参考
webpack打包bundle.js体积大小优化
开发工具心得:如何 10 倍提高你的 Webpack 构建效率
详解前端模块化工具-Webpack
webpack 多页面构建
使用Webpack打包时的“多页”实践
Webpack2.x踩坑与总结
Webpack——令人困惑的地方