Webpack原理简单讲解
webpack是JavaScript应用程序的静态模块打包器,webpack处理应用程序时,将递归构建一个依赖关系图,依赖图映射了项目中需要的每一个模块,并打包生成一个或多个bundle.
当在命令行运行指令 webpack 的时候,webpack将默认从当前目录下查找 webpack.config.js 文件
webpack的配置(webpack.config.js)中有四个核心概念需要理解:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugins)
入口(entry)
entry属性将告诉webpack从哪个模块开始构建依赖图,并计算出所有这个模块直接或间接依赖的模块.
entry为String或Array时,entry输出的Chunk的名称将默认是main
entry为Object时,webpack将输出多个Chunk,Chunk的名称将会是key
点击此处查看详细内容
输出(output)
output属性将告诉webpack最终打包文件的输出路径,以及如何命名打包文件.
const path = require('path');
module.exports = {
entry: './src/index.js',
// ./dist/main.js
output: {
// 文件名字可以直接设置
filename: 'my-first-webpack.bundle.js',
// 也可以用过变量设置
// id - Chunk的唯一标识,从0开始
// name - Chunk的名称
// hash - Chunk的唯一标识(即id)的hash值
// chunkhash - Chunk内容的hash值
filename: '[id].[name].[hash].[chunkhash].js',
// 配置输出文件的存放目录
// __dirname是运行命令行时所在路径
path: path.resolve(__dirname, 'dist'),
}
};
复制代码
node中的path,点击此处
点击此处查看详细内容
loader
module属性配置如何处理模块,其中rules配置模块的读取和解析规则,通常用来配置Loader.
未增加自定义配置的情况下,webpack只能处理JavaScript文件和JSON文件,Loader可以使webpack处理其他类型的文件到模块中,添加到依赖图中,被应用程序使用.
条件匹配: 通过 test / include / excluede 三个配置来匹配文件,支持string和array
应用规则: 匹配命中文件之后,使用use中的配置来应用loader,同时可以按"从后往前"的顺序应用多个loader
重置顺序: 一组loader的执行顺序迷人是从右向左执行,通过 enforce 选项可以让其中一个loader的执行顺序放到最后或最前
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [ // 在rules中可以设置多个规则
{
test: /\.txt$/, // 设置用来匹配什么文件需要被转换
// 只命中src目录里的js文件,加快 Webpack 搜索速度
include: path.resolve(__dirname, 'src'),
// 排除 node_modules 目录下的文件
exclude: path.resolve(__dirname, 'node_modules'),
// 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。
use: ['style-loader', 'css-loader', 'sass-loader'],
// use中同样可以设置Object
use: [
{
loader:'babel-loader',
options:{
cacheDirectory:true,
},
// enforce:'post' 的含义是把该 Loader 的执行顺序放到最后
// enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面
enforce:'post'
},
]
}
]
}
};
复制代码
点击此处查看详细内容
插件(plugins)
loaders用来转换某些类型的模块(文件),plugin 则用来执行,打包优化,资源管理和插入环境变量,等各种任务
plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 webpack 带来了很大的灵活性。
通过require方法引入插件,并将其实例化的对象加入plugins中
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
module.exports = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
复制代码
上方例子, html-webpack-plugin 插件会给应用生成一个HTML文件,并在文件中插入打包好的文件.
tip: 使用 Plugin 的难点在于掌握 Plugin 本身提供的配置项,而不是如何在 Webpack 中接入 Plugin。
点击此处查看详细内容
webpack打包的基本逻辑
- 初始化参数
从配置文件和Shell语句中读取并合并参数,得出最终的参数
- 开始编译
用第一步得到的参数初始化Compiler对象,加载所有配置的插件,执行对象中的run方法开始执行编译
- 确认入口
根据配置中的entry找出所有的入口文件
- 编译模块
从入口文件出发,调用所有配置的loader对模块进行翻译,再找出该模块依赖的模块,递归查找所有的模块依赖
- 完成模块编译
经过第四部使用loader对所有模块进行翻译后,得到每个模块被翻译后的最终内容以及他们之间的依赖关系
- 输出资源
根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再把每个chunk转换成一个单独的文件并加入到输出列表中
- 输出完成
确认好输出内容后,根据配置确认输出的路径和文件名,把文件内容写入到文件系统中
tip: 上述过程中,webpack会在特定时间广播出特定时间,插件接受到想要的事件广播之后便会执行特性的逻辑,并且插件可以调用webpack提供的API改变webpack的运行结果
输出文件分析
webpack配置文件
const path = require('path')
// Since webpack 4 the "extract-text-webpack-plugin" should not be used for css.
// Use "mini-css-extract-plugin" instead
// const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const merge = require('webpack-merge')
// 这个在 npm run dev 和 npm run build 时候是不同的
const TARGET = process.env.npm_lifecycle_event
const APP_PATH = path.join(__dirname, '/src')
const dist = path.resolve(__dirname, 'dist')
const common = {
entry: `${APP_PATH}/index.js`,
output: {
path: dist,
filename: 'index.js'
}
}
let other = {}
if (TARGET === 'dev') {
other = {
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
// TODO 理解loader的执行顺序
use: [
'style-loader', // Adds CSS to the DOM by injecting a