概念
构建
将源代码转化为分发代码的过程称为构建。
- 源代码:用于书写和编辑的代码
- 分发代码:在构建过程中,经过最小化和优化后产生的输出结果,最终将在浏览器中加载
打包
根据依赖图将多个模块的代码合并到一个或者几个 chunk 中的过程称为打包。
模块
一个文件就是一个模块,模块可以是任何类型的文件,原生支持 js 和 json 文件,其他类型的文件需要使用对应的 loader 转换成 js 文件。
chunk 组
module.exports = {
entry: {
home: './home.js',
about: './about.js',
},
};
chunk 组:每个键值对就是一个 chunk 组。以上配置包括两个 chunk 组:home 组 about 组。
每个 chunk 组至少包括一个 initial chunk,以及零个或者多个 non-initial chunk。
chunk
chunk: 一个导出的 js 文件就是一个 chunk,一个 chunk 中的代码可以包括多个模块。
initial chunk
根据入口模块的依赖图打包形成的 bundle 称为 initial chunk,有几个入口模块就生成几个 initial chunk。
entry
指定入口模块
output.filename
指定 initial chunk 的名称
non-initial chunk:
non-initial chunk 包括 async chunk 和 split chunk:
- import() 导入的模块,根据该模块的依赖图打包形成一个 async chunk。通过注释指定 async chunk 的 name
import(/* webpackChunkName: 'foo' */'./foo')
。 - 通过 splitChunks 从一个 initial chunk 或者一个 async chunk 中分离出 split chunk,例如 vendor common runtime 等 chunk。
output.chunkFilename
指定 non-initial chunk 的名称。
模块解析规则
模块的依赖关系
模块之间存在依赖关系,通过以下方式来表明依赖关系,根据依赖关系绘制依赖图。
js 文件中:
import
require
import()
css 文件中:
@import
url()
html 文件中:
<img src="">
模块的路径解析
模块的路径有三种表达方式:
- 绝对路径:不要使用
- 相对路径:在代码中引入自定义的模块(js 模块、css、img 等资源等)
- 模块路径:在代码中引入第三方模块,在配置文件中配置 loader
当使用模块路径的时候,优先使用 resolve.alias 设置的模块别名的路径来解析模块,如果没有对应的模块别名,再根据模块解析的步骤来解析模块路径。
// 第三方模块使用模块路径
import _ from 'lodash'
// 自己的模块使用相对路径
import sum from './vendor/sum.js'
import './css/style.css'
import Icon from './images/icon.png'
// js 文件可以省略扩展名,推荐不要省略
import sum from './vendor/sum'
// 动态引入模块可以使用相对路径、绝对路径和模块路径
import('./vendor/sum.js')
import('lodash')
通过 css-loader 可以将 css 文件中的 url() 理解为模块依赖,引入图片等资源,推荐使用相对路径
.hello {
background: url('../images/icon.png') no-repeat;
}
通过 html-loader 可以将 html 文件中的 img src="" 理解为模块依赖,引入图片等资源,推荐使用相对路径
<img src="./images/icon.png">
entry 的路径解析
entry 可以是相对路径,也可以是模块路径,相对路径相对于 context 选项,该选项默认值为配置文件所在的目录。
module.exports = {
// context 必须是绝对路径
context: path.resolve(__dirname),
entry: {
// 相对路径,相对 context 选项
index: './src/index.js',
// 模块路径,根据模块的解析规则来解析
vendor: 'lodash'
}
};
loader 的路径解析
loader 可以是相对路径、绝对路径、模块路径,解析规则与模块的解析规则一样。
module: {
rules: [
test: /\.css$/,
// 推荐使用模块路径
use: ['style-loader', 'css-loader']
]
}
其他知识点
runtime 和 manifest
runtime 和 manifest 都是 webpack 生成的内容,每次打包 runtime 和 manifest 都不同,为了缓存,应该将 runtime 和 manifest 分离出来。
- manifest 是数据,保留原始的各个模块的信息。
- runtime 是 webpack 生成的代码
runtime 根据 manifest,将源代码中 import 和 require 都转换为 __webpack_require__(module identifier)
缓存
生产模式下,推荐 bundle 文件名 filename: [name].[contenthash].js
,contenthash 可以保证一旦更新模块,则生成的包会重新下载。
process.env.NODE_ENV
在 package.json 中
{
"scripts": {
"build": "NODE_ENV=production webpack",
"dev": "NODE_NEV=development webpack serve --open"
}
}
在 webpack.config.js 中的 process.env.NODE_ENV
访问的是通过命令行传入的参数 NODE_ENV,也就是 package.json 文件中 scripts 里面定义的 NODE_ENV 的值。
const webpack = require('webpack');
// 这里的值是通过命令行传入的参数值,如果是 npm run build,则值为 production。
console.log(process.env.NODE_ENV)
module.exports = {
entry: {
app: './src/app'
},
output: {
path: 'dist',
filename: 'bundle.js'
},
plugins: [
new webpack.DefinePlugin({
// 这里定义了可以在模块中访问的 process.env.NODE_ENV 的值
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
]
};
在模块中访问的 process.env.NODE_ENV
其实是在配置文件中通过 DefinePlugin 定义的值,而不是通过命令行传入的值。
将配置文件的 mode 设置为 development 或者 production,相当于自动通过 DefinePlugin 定义了可以在模块中访问的 process.env.NODE_ENV
为 mode 的值。
网友评论