谈谈你对webpack的理解
webpack主要是用来解决模块化问题的。
什么是模块
将某一个复杂的项目按照某种规则或者规范划分为多个文件,每个文件就是一个模块。模块内部是数据是私有的。
模块化实现历程
早期模块化的方式中,每个能实现某些功能js文件被设计为一个单独的模块,然后通过script标签
引入
1 | <script src="module-a.js"></script> |
这种方式的缺点很明显,被引入后,模块中的变量都成为全局变量
,存在变量污染
问题,而且模块之间没有依赖关系
。
随后,就出现了命名空间
方式,规定每个模块只
暴露一个全局对象,然后模块的内容都挂载到这个对象中。
1 | window.moduleA = { |
这样就解决了全局变量污染
的问题,但是没有解决依赖混乱
的问题,而且不安全,模块内部的数据可以被随意修改
。
后来又选择用立即执行函数
为模块添加私有空间, 解决了内部数据可以被随意修改的问题。
1 | (function ($) { |
支持传入参数,能在一定程度上解决模块依赖问题,但是必须注意引入模块的先后顺序
,否则就会出现undefined
的问题。
理想的解决方式是,在页面中引入一个JS入口文件
,其余用到的模块可以通过代码控制,按需加载进来。
除了模块加载的问题以外,还需要规定模块化的规范,如今流行的则是CommonJS
、ES Modules
我们上述讨论的模块化的范围只包括js
文件,后来html,css等文件也可以被模块化,这就需要借助webpack
。
模块化的好处
解决了声明冲突问题,提高了代码的可维护性与复用性,使得项目中文件的依赖关系明确,支持按需加载。
什么是webpack
用于现代JavaScript
应用程序的静态模块打包工具。
webpack的构建流程
初始化阶段
合并
配置文件
和shell语句
中的配置参数,创建compiler
对象,并初始化插件
。编译阶段
调用
compiler
对象的run
方法,开始编译,从入口文件出发,使用配置的loader
递归解析依赖的文件,把他们转变成可用的js模块,并构建模块依赖图
。打包并输出
根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
Chunk
,再把每个Chunk
转换成一个单独的文件并输出。
loader和plugin
loader
loader主要被用来进行文件的转化,使之变成可用的模块,扩大了webpack模块化的范围。
plugin
主要用来解决loader
无法解决的其他事情,本质是一个具有apply
方法的js对象
,这个方法会被compiler
对象调用。webpack构建过程中会广播很多事件,plugin可以监听自己感兴趣的事件,从而改变最后的打包结果。
常见的plugin:
html-webpack-plugin:
在打包结束后,自动生成⼀个
html
文件,并自动引入
打包后的js文件。1
2
3
4
5
6
7
8
9
10const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
new HtmlWebpackPlugin({
title: "My App",
filename: "app.html",
template: "./src/html/index.html"
})
]
};mini-css-extract-plugin:
提取
CSS
代码到一个单独的文件中。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader,'css-loader','sass-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
})
]
}