鉴于我在学习的过程使用webpack的频率较高,所以想着要记录一下webpack的一些核心的知识点,此博文涉及的知识点可能不深,但涵盖了webpack的主要内容,主要目的是想将此次的学习过程记录下来,以便进行后续的深入学习,如果在理解上有偏差的话,还请大家不吝赐教~
概念篇
核心概念
webpack 是一个现代JavaScript应用程序的模块打包器。当webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成少量的bundle - 通常只有一个,由浏览器加载。在开始之前,我们需要先理解四个核心概念:入口(entry)、输出(output)、loader、插件(plugins)。
入口(Entry)
webpack创建应用程序所依赖的关系图时,图的起点就是我们的入口起点。入口起点告诉webpack从哪里开始,可以认为是app的第一个启动文件。
单入口语法,用法:entry: string|Array
1
2
3module.exports = {
entry: '.src/app.js' //将src目录下的app.js文件作为入口文件
}对象语法,用法:entry: {[entryChunkName: string]: string|Array
}
对象语法常用于:多页面应用程序,如1
2
3
4
5
6
7module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
}
表面上告诉我们,webpack需要创建3个依赖图,这些依赖图彼此之间完成分离,互相独立的。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益。
出口(Output)
将所有文件归拢后,我们需要告诉webpack如何处理这些归拢在一起的文件。1
2
3
4
5
6
7
8
9const path = require('path'); //引入path对象
module.exports = {
entry: '.src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack.bundle.js'
}
};
多个入口起点:出口处应该使用占位符来确保每个文件具有唯一的名称。1
2
3
4
5
6
7
8
9
10module.exports = {
entry: {
app: __dirname + '.src/app.js',
search: __dirname + './src/search.js'
},
output: {
path: __dirname + '/dist',
filename: 'bundle-[name].js' //dist目录下将生成"bundle-app.js"和"bundle-search.js"文件
}
};
我们通过output.filename和output.path属性,来告诉输出文件的名称以及路径。
Loader
webpack把每个文件(.css, .html, .less, .scss, .jpg等)都作为模块处理,然而 webpack 自身只理解 JavaScript。loader 可以使你在 import 或”加载”模块时预处理文件。
loader在文件被添加到依赖图中时,将文件转换为模块。
- 识别出应该被对应的loader进行转换的文件。(test属性)
- 转换这些文件,从而使其能够被添加到依赖图中(并且最终添加到 bundle 中)。(use属性)
在使用前,我们需要提前安装相对应的loader,如:1
$ cnpm install --save-dev vue-loader
1 | const path = require('path'); //引入path对象 |
在应用程序中,我们有三种使用loader的方法:
- 配置(推荐):在webpack.config.js文件中指定loader。
内联:在每个 import 语句中显式指定 loader,如:
1
import Styles from 'style-loader!css-loader?modules!./styles.css';
CLI:在 shell 命令中指定它们,如:
1
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
插件(Plugins)
由于loader仅在每个文件的基础上执行转换,而插件更常用于(但不限于)在打包模块的 “compilation” 和 “chunk” 生命周期执行操作和自定义功能。想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中,多数插件可以通过选项(option)自定义。插件目的在于解决loader无法实现的其他事。
由于插件可以携带参数/选项,你必须在webpack配置中,向plugins属性传入 new 实例。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path'); //引入path对象
module.exports = {
entry: '.src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack.bundle.js'
},
module: {
rules: [
{ test: /\.vue$/,loader: 'vue-loader' } //用来解析vue后缀的文件
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
模块(Modules)
在模块化编程中,开发者将程序分解成离散功能块,并称之为模块,每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。
对比Node.js模块,webpack模块能够以各种方式表达它们的依赖关系,如:
- ES2015 import语句
- CommonJS require()语句
- AMD define和require语句
- css/sass/less 文件中的 @import 语句
- 样式(url(…))或 HTML 文件img标签中的图片链接
webpack 通过 loader 可以支持各种语言和预处理器编写模块。
模块解析
resolver是一个库,用于帮助找到模块的绝对路径。
使用enhanced-resolve,webpack 能够解析三种文件路径:
- 绝对路径
1
import "C:\\Users\\user\\file";
由于我们已经取得了文件的绝对路径,因此不需要进一步在做解析。
- 相对路径
1
import "../src/file1";
在这种情况下,使用import或require的资源文件所在的目录被认为是上下文目录,在import/require中给定的相对路径,会添加此上下文路径,以产生模块的绝对路径。
- 模块路径
1
import "module/lib/file";
模块将在resolve.modules中指定的所有目录内搜索。
构建目标(Targets)
因为服务器和浏览器代码都可以用JavaScript编写,所以webpack提供了多种构建目标。1
2
3module.exports = {
target: 'node' //webpack会编译为用于「类Node.js」环境
};
多个Target:尽管webpack不支持向target传入多个字符串,你可以通过打包两份分离的配置来创建同构的库:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20const path = require('path');
const serverConfig = {
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.node.js'
}
//…
};
const clientConfig = {
target: 'web', // 默认是 'web',可省略
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.js'
}
//…
};
module.exports = [ serverConfig, clientConfig ];
上面的例子将在你的dist文件夹下创建lib.js和lib.node.js文件。
模块热替换
模块热替换功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:
- 保留在完全重新加载页面时丢失的应用程序状态。
- 只更新变更内容,以节省宝贵的开发时间。
- 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。
总结
webpack概念篇就差不多结束啦,其中包含webpack中核心的几个概念以及各自的用法,接下来我将继续记录webpack管理资源的相关知识点,希望能对大家有所帮助~