webpack
是一个JavaScript应用程序的静态模块打包器。当webpack
处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle
。
webpack
有4个核心概念:入口(entry
)、输出(output
)、loader
、插件(plugins
)。
入口
入口起点(entry point
)指示webpack
应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack
会找出有哪些模块和库是入口起点(直接和间接)依赖的。
每个依赖项随即被处理,最后输出到称之为bundles
的文件中。
可以通过在webpack
配置中配置entry
属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src
。
单个入口(简写)语法
用法:entry: string|Array
//webpack.config.js
const config = {
entry: './path/to/my/entry/file.js'
};
// 等价于
const config = {
entry: {
main: './path/to/my/entry/file.js'
}
};
module.exports = config;
向entry
属性传入「文件路径数组」将创建“多个主入口”。在你想要多个依赖文件一起注入,并且将它们的依赖导向到一个chunk
时,传入数组的方式就很有用。
对象语法
用法:entry: {[entryChunkName: string]: string|Array
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
出口
出口属性告诉webpack
在哪里输出它所创建的bundles
,以及如何命名这些文件,默认值为./dist
。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个output
字段,来配置这些处理过程。
注意,即使可以存在多个入口起点,但只指定一个输出配置。
用法
在webpack
中配置output
属性的最低要求是,将它的值设置为一个对象,包括以下两点:
-
filename
用于输出文件的文件名。 - 目标输出目录
path
的绝对路径。
//webpack.config.js
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
module.exports = config;
此配置将一个单独的bundle.js
文件输出到/home/proj/public/assets
目录中。
多个入口起点
如果配置创建了多个单独的chunk
(例如,使用多个入口起点或使用像CommonsChunkPlugin
这样的插件),则应该使用占位符来确保每个文件具有唯一的名称。
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 写入到硬盘:./dist/app.js, ./dist/search.js
loader
loader
用于对模块的源代码进行转换。loader
可以使你在import
或"加载"模块时预处理文件。loader
可以将文件从不同的语言转换为JavaScript,或将内联图像转换为data URL
。loader
甚至允许你直接在JavaScript模块中import
CSS文件!
loader
让webpack
能够去处理那些非JavaScript文件(webpack
自身只理解JavaScript)。loader
可以将所有类型的文件转换为webpack
能够处理的有效模块,然后你就可以利用webpack
的打包能力,对它们进行处理。
本质上,webpack loader
将所有类型的文件,转换为应用程序的依赖图(和最终的bundle
)可以直接引用的模块。
loader
能够import
导入任何类型的模块,这是webpack
特有的功能。
在webpack
的配置中loader
有两个目标:
-
test
属性,用于标识出应该被对应的loader
进行转换的某个或某些文件。 -
use
属性,表示进行转换时,应该使用哪个loader
。
示例
例如,你可以使用loader
告诉webpack
加载CSS文件,或者将TypeScript转为JavaScript。为此,首先安装相对应的loader
:
npm install --save-dev css-loader
npm install --save-dev ts-loader
然后指示webpack
对每个 .css
使用css-loader
,以及对所有 .ts
文件使用ts-loader
:
//webpack.config.js
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' }
]
}
};
使用loader
有三种使用loader
的方式:
- 配置(推荐):在
webpack.config.js
文件中指定loader
。 - 内联:在每个
import
语句中显式指定loader
。 - CLI:在shell命令中指定它们。
配置
module.rules
允许你在webpack
配置中指定多个loader
。 这是展示loader
的一种简明方式。
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
内联
可以在import
语句或任何等效于import
的方式中指定loader
。使用!
将资源中的loader
分开。分开的每个部分都相对于当前目录解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
通过前置所有规则及使用!
,可以对应覆盖到配置中的任意loader
。
选项可以传递查询参数,例如?key=value&foo=bar
,或者一个JSON对象,例如?{"key":"value","foo":"bar"}
。
CLI
也可以通过CLI使用loader
:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
这会对.jade
文件使用jade-loader
,对.css
文件使用style-loader
和css-loader
。
loader特性
-
loader
支持链式传递。能够对资源使用流水线。一组链式的loader
将按照相反的顺序执行。loader
链中的第一个loader
返回值给下一个loader
。在最后一个loader
,返回webpack
所预期的JavaScript。 -
loader
可以是同步的,也可以是异步的。 -
loader
运行在Node.js中,并且能够执行任何可能的操作。 -
loader
接收查询参数。用于对loader
传递配置。 -
loader
也能够使用options
对象进行配置。 - 除了使用
package.json
常见的main
属性,还可以将普通的npm模块导出为loader
,做法是在package.json
里定义一个loader
字段。 - 插件可以为
loader
带来更多特性。 -
loader
能够产生额外的任意文件。
解析 loader
loader 遵循标准的模块解析。多数情况下,loader
将从模块路径(通常将模块路径认为是 npm install
, node_modules
)解析。
loader
模块需要导出为一个函数,并且使用Node.js兼容的 JavaScript 编写。通常使用npm进行管理,但是也可以将自定义loader
作为应用程序中的文件。按照约定,loader
通常被命名为 xxx-loader
(例如 json-loader
)。
插件
loader
被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
想要使用一个插件,你只需要require()
它,然后把它添加到plugins
数组中。多数插件可以通过选项自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用new
操作符来创建它的一个实例。
//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
用法
由于插件可以携带参数/选项,你必须在webpack
配置中,向plugins
属性传入new
实例。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;