一、概念
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
有四个概念:entry、output、loader、plugins
(都需要在webpack.config.js中配置)
1、入口(entry)
构建依赖时的起始文件,并且可以配置多个入口。
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack
会找出有哪些模块和库是入口起点(直接和间接)依赖的。
默认值为 ./src。
2、输出(output)
打出来的包放到哪个位置,可以配置文件路径和文件名
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件.
默认值为 ./dist。
3、loader
用来将非js文件转换成webpack可以理解的模块。在webpack将特定类型文件(一般用文件后缀来区分)打包前,先使用loader进行转换。
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack的打包能力,对它们进行处理。
注意,loader 能够 import 导入任何类型的模块(例如 .css 文件),这是 webpack 特有的功能,其他打包程序或任务执行器的可能并不支持。我们认为这种语言扩展是有很必要的,因为这可以使开发人员创建出更准确的依赖关系图。
在更高层面,在 webpack 的配置(config文件中的rules)中 loader 有两个目标: test 属性,用于标识出应该被对应的 loader
进行转换的某个或某些文件。 use 属性,表示进行转换时,应该使用哪个 loader。
在 webpack 配置中定义 loader 时,要定义在 module.rules 中,而不是 rules
4、插件(plugins)
用来处理loader处理不了的情况,并且是全局性的,loader一次只能处理一个文件。
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。
5、模式
通过选择 development 或 production 之中的一个,来设置 mode 参数,可以启用相应模式下的 webpack 内置的优化
module.exports = {
mode: 'production'
};
二、入口起点(entry points)
1、单入口写法
const config = {
entry: './path/to/my/entry/file.js'
};
module.exports = config;
entry 属性的单个入口语法,是下面的简写:
const config = {
entry: {
main: './path/to/my/entry/file.js'
}
};
当你向 entry 传入一个数组时会发生什么?向 entry 属性传入「文件路径(file path)数组」将创建“多个主入口(multi-main entry)”。在你想要多个依赖文件一起注入,并且将它们的依赖导向(graph)到一个“chunk”时,传入数组的方式就很有用。然而,使用此语法在扩展配置时有失灵活性。
2、对象语法
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。
3、常见场景
分离 应用程序(app) 和 第三方库(vendor) 入口
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
下面这段没看明白
**这是什么?**从表面上看,这告诉我们 webpack 从 app.js 和 vendors.js 开始创建依赖图(dependency graph)。这些依赖图是彼此完全分离、互相独立的(每个 bundle 中都有一个 webpack 引导(bootstrap))。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程序(single page application)中。
**为什么?**此设置允许你使用 CommonsChunkPlugin 从「应用程序 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle,并把引用 vendor 的部分替换为 webpack_require() 调用。如果应用程序 bundle 中没有 vendor 代码,那么你可以在 webpack 中实现被称为长效缓存的通用模式。
4、多页面应用程序
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
**这是什么?**我们告诉 webpack 需要 3 个独立分离的依赖图(如上面的示例)。
**为什么?**在多页应用中,(译注:每当页面跳转时)服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。然而,这给了我们特殊的机会去做很多事:
使用 CommonsChunkPlugin 为每个页面间的应用程序共享代码创建 bundle。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益。
三、输出(output)
配置 output 选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口起点,但只指定一个输出配置。
多入口起点:
如果配置创建了多个单独的 “chunk”(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用**占位符(substitutions)**来确保每个文件具有唯一的名称。
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}
// 写入到硬盘:./dist/app.js, ./dist/search.js
四、模式(mode)
1、提供模式的方法(cli和配置文件)
cli:
webpack --mode=production
配置:
module.exports = {
mode: 'production'
};
记住,只设置 NODE_ENV,则不会自动设置 mode。所以应当是设置mode,然后让webpack自动设置NODE_ENV。
五、loader
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。
loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件
1、使用loader
三种方式:配置(推荐)、内联(在import时就指定loader)、cli
2、配置[configuration]
就是配置文件中的那个rules数组。
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
}
]
}
]
}
2、内联
可以在 import 语句或任何等效于 “import” 的方式中指定 loader。使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
尽可能使用 module.rules,因为这样可以减少源码中的代码量,并且可以在出错时,更快地调试和定位 loader 中的问题。
3、cli
你也可以通过 CLI 使用 loader:
webpack --module-bind jade-loader --module-bind ‘css=style-loader!css-loader’
4、loader的特性
4.1loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
4.2loader 可以是同步的,也可以是异步的。
4.3loader 运行在 Node.js 中,并且能够执行任何可能的操作。
4.4loader 接收查询参数。用于对 loader 传递配置。
4.5loader 也能够使用 options 对象进行配置。
4.6除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
4.7插件(plugin)可以为 loader 带来更多特性。
4.8loader 能够产生额外的任意文件。
loader 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译
六、plugins
插件是 webpack 的支柱功能。插件目的在于解决 loader 无法实现的其他事。
1、配置
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;
七、配置
上面plugins的配置已经足够完整了
八、模块(modules)
对比 Node.js 模块,webpack 模块能够以各种方式表达它们的依赖关系,几个例子如下:
ES2015 import 语句
CommonJS require() 语句
AMD define 和 require 语句
css/sass/less 文件中的 @import 语句。
样式(url(…))或 HTML 文件()中的图片链接(image url)
九、构建目标(target)