本文介绍了一些 webpack 的核心概念以及一些概念术语,并对核心配置做了一些简单的用法讲解。建议刚刚接触 Webpack 的朋友可以先了解一下。想了解更多 Webpack 使用以及配置的话可以参考我的下一篇文章: 从零开始搭建一个 Webpack 开发环境配置(附 Demo)
为什么需要使用 webpack
模块化开发的趋势
我们在开发的过程中,之前都是使用引入 script 的方式进行各种工具和插件的引入,但是这样会造成很大程度上的全局污染,所以引入了 模块化 的概念,但是不管是 commomJs 还是 CMD,AMD 的方式,浏览器无法识别,而使用 webpack 就可以自动的将文件编译成浏览器可以识别的代码less、sass 以及 ES6 语法的使用
同样的,直接使用 less、sass 和 ES6 语法,直接使用,浏览器甚至 node 环境也无法正常识别,所以这时候 loader 就派上用场了,可以使用 less-loader、sass-loader 以及 babel-lodaer 对对应的文件进行转换之后,就可以正常的编译了监听文件的变化并自动刷新网页,做到实时预览
提供 HTTP 服务而不是使用本地文件预览
对于打包后的文件进行压缩,模块拆分,减小打包后的文件体积
等等还有很多别的优势,这里我就不一一列举了
webpack 安装
全局安装:
1
npm install --global webpack
本地安装:
1
2npm install --save-dev webpack
npm install --save-dev webpack-cli
Webpack 概念
webpack 是一个可高度配置的现代 JavaScript 应用程序模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
Webpack 核心概念
入口
入口点可以告诉 webpack 从哪里启动以及遵循依赖关系图,以此知道要打包什么东西。你可以考虑将待打包文件的根目录作为你应用程序的入口点。
个人理解:入口就是 webpack 在处理应用程序时,需要知道从哪个文件开始执行,这个文件就是整个程序的入口文件。
用法:entry: string|Array
基本用法
webpack.config.js1
2
3
4
5const config = {
entry: './src/index.js'
};
module.exports = config;
数组语法
一般适用于多页面应用,多个入口的场景。
webpack.config.js1
2
3
4
5const config = {
entry: ['./src/entry1', './src/entry2']
};
module.exports = config;
对象语法
一般适用于分离 应用程序(app) 和 第三方库(vendor) 入口。
webpack.config.js
1 | const config = { |
配置动态入口
假如项目里有多个页面需要为每个页面的入口配置一个 Entry ,但这些页面的数量可能会不断增长,则这时 Entry 的配置会受到到其他因素的影响导致不能写成静态的值。
webpack.config.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 同步函数
entry: () => {
return {
a:'./pages/a',
b:'./pages/b',
}
};
// 异步函数
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
输出
上面既然已经有入口文件了,那么 webpack 执行了一系列操作之后,生成的新的打包后的文件应该放到哪儿呢,所以我们需要指定一下。
在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:
- filename 用于输出文件的文件名
- 目标输出目录 path 的绝对路径
基本用法
webpack.config.js1
2
3
4
5
6
7
8
9
10
11
12const path = require('path');
const config = {
entry: './src/index.js',
output: {
// 最基本的两个配置要求
filename: 'bundle.js', // 输出文件的文件名
path: path.resolve(__dirname, 'dist') // 目标输出目录 path 的绝对路径,这里必须是绝对路径
}
};
module.exports = config;
多个入口起点
如果配置创建了多个单独的 “chunk”,则应该使用占位符(参考内置的占位符变量)来确保每个文件具有唯一的名称。
webpack.config.js1
2
3
4
5
6
7
8
9
10
11const path = require('path');
const config = {
output: {
// 最基本的两个配置要求
filename: '[name]-bundle.js', // 输出文件的文件名
path: path.resolve(__dirname, 'dist') // 目标输出目录 path 的绝对路径
}
};
module.exports = config;
内置的占位符变量
变量名 | 含义 |
---|---|
id | Chunk 的唯一标识,从0开始 |
name | Chunk 的名称 |
hash | Chunk 的唯一标识的 Hash 值 |
chunkhash | Chunk 内容的 Hash 值 |
loader
loader 用于对模块的源代码进行转换。loader 可以使你在 import
、require()
或”加载”模块时预处理文件。
loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
基本使用
例如:加载 css 模块:
安装对应的 loader
1
npm install --save-dev style-loader css-loader
然后指示 webpack 对每个 .css 使用 css-loader 和 style-loader
webpack.config.js
1
2
3
4
5
6
7module.exports = {
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader' }
]
}
};
配置 loader
rules 配置模块的读取和解析规则,通常用来配置 Loader。其类型是一个数组,数组里每一项都描述了如何去处理部分文件。 配置一项 rules 时大致通过以下方式:
条件匹配:通过 test 、 include 、 exclude 三个配置项来命中 Loader 要应用规则的文件
应用规则:对选中后的文件通过 use 配置项来应用 Loader,可以只应用一个 Loader 或者按照从后往前的顺序应用一组 Loader,同时还可以分别给 Loader 传入参数
重置顺序:一组 Loader 的执行顺序默认是从右到左(从下到上、从后到前)执行,通过 enforce 选项可以让其中一个 Loader 的执行顺序放到最前或者最后
在 Loader 需要传入很多参数时,你还可以通过一个 Object 来描述
test include exclude 这三个命中文件的配置项可以传入一个字符串或正则,其实它们还都支持数组类型
具体使用: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
38module.exports = {
module: {
rules: [
{
// 命中 JavaScript 文件
test: [
/\.js?$/,
/\.jsx?$/
],
// 用 babel-loader 转换 JavaScript 文件
// ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快重新编译速度
use: [
{
loader:'babel-loader',
options:{
cacheDirectory:true,
},
// enforce:'post' 的含义是把该 Loader 的执行顺序放到最后
// enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面
enforce:'post'
}
],
// 只命中src目录里的js文件,加快 Webpack 搜索速度
include: path.resolve(__dirname, 'src')
},
{
// 命中 SCSS 文件
test: /\.scss$/,
// 使用一组 Loader 去处理 SCSS 文件。
// 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。
use: ['style-loader', 'css-loader', 'sass-loader'],
// 排除 node_modules 目录下的文件
exclude: path.resolve(__dirname, 'node_modules')
}
]
}
};
plugins
Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。
基本使用
比如每次打包文件到 dist 文件夹下,就可能导致文件夹下面的文件过多,内容过大,那么此时我们可能需要在打包之前先将 dist 文件下的文件都删除掉,但是每次都手动删除岂不是太麻烦,此时我们就可以使用 clean-webpack-plugin 插件来帮助我们清理 dist 文件夹
插件安装1
npm install clean-webpack-plugin --save-dev
webpack.config.js1
2
3
4
5
6
7const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(['dist'])
]
}
其他概念术语
资源(Asset)
这是一个普遍的术语,用于图片、字体、媒体,还有一些其他类型的文件,常用在网站和其他应用程序。这些文件通常最终在输出(output ) 中成为单个文件,但也可以通过一些东西内联,像 style-loader 或者 url-loader 。
Bundle
由多个不同的模块生成,bundles 包含了早已经过加载和编译的最终源文件版本。
Chunk
这是 webpack 特定的术语被用在内部来管理 building 过程。bundle 由 chunk 组成,其中有几种类型(例如,入口 chunk(entry chunk) 和子 chunk(child chunk))。通常 chunk 会直接对应所输出的 bundle,但是有一些配置并不会产生一对一的关系。
依赖关系图(Dependency Graph)
有时候一个文件依赖于其他文件,webpack 将其视为依赖关系(dependency)。从一个或多个入口点开始,webpack 递归构建一个依赖关系图,里面包含了你的应用程序需要的所有模块/资源(mudule/asset)。
模块(Module)
提供比完整程序接触面(surface area)更小的离散功能块。精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的。
- 模块解析(Module Resolution):一个模块可以作为另一个模块的依赖模块,resolver 是一个库( library )用于帮助找到模块的绝对路径… 模块将在 resolve.modules 中指定的所有目录内搜索。
Tree Shaking
移除未使用/多余的代码,或者更准确地说,只导入引用的代码。编译器(compiler)(例如 webpack)将通过分析各种 import 语句和引入代码的使用情况,来确定哪些部分的依赖关系被实际使用,删除不是“树”的部分,以实现此功能
第三方库入口点(Vendor Entry Point)
从 app.js 和 vendors.js 开始创建依赖图(dependency graph)。这些依赖图是彼此完全分离、互相独立的,允许你使用 CommonsChunkPlugin 从「应用程序 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle。可以帮助你在 webpack 中实现被称为长效缓存的通用模式。
优化
Bundle 分离(Bundle Splitting)
这个流程提供一个优化 build 的方法,允许 webpack 为应用程序生成多个 bundle。最终效果是,当其他某些 bundle 的改动时,彼此独立的另一些 bundle 都可以不受到影响,减少需要重新发布的代码量,因此由客户端重新下载并利用浏览器缓存。代码分离(Code Splitting)
指将代码分离到每个 bundles/chunks 里面,你可以按需加载,而不是加载一个包含全部的 bundle。
总结
本文简单介绍了一下 Webpack 的作用以及 Webpack 核心概念的用法。想了解更多的朋友可以参考我的下一篇文章:从零开始搭建一个 Webpack 开发环境配置(附 Demo)