webpack基础应用知识总结
# 1️⃣ Webpack 是什么?核心理念是什么?
Webpack 是一个静态模块打包器(module bundler)。
核心思想:
- 把所有资源都当作模块处理(JS、CSS、图片、字体等)
- 通过依赖图(dependency graph)分析模块之间的关系
- 最终输出浏览器可运行的 bundle(或多个 chunk)
一句话解释:
Webpack 把前端项目中所有资源模块化处理,并最终统一打包输出。
# 2️⃣ Webpack 的核心概念(非常重要)
# ① Entry(入口)
告诉 Webpack 从哪个文件开始分析依赖图。
entry: './src/index.js'
可以是多入口:
entry: {
main: './src/main.js',
admin: './src/admin.js'
}
2
3
4
# ② Output(出口)
决定打包的文件输出到哪里、叫什么。
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
2
3
4
# ③ Loader(模块转换器)
Webpack 只能处理 JS,需要 loader 扩展能力。
常见 loader:
| 资源 | 对应 loader |
|---|---|
| CSS | css-loader, style-loader |
| LESS | less-loader |
| 图片 | url-loader / file-loader(Webpack5→asset module) |
| ES6 | babel-loader |
| Vue | vue-loader |
| TS | ts-loader |
示例:
module: {
rules: [
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
2
3
4
5
# ④ Plugins(插件体系,Webpack 最强能力)
Loader 处理一类文件,Plugin 处理整个构建流程。
常见插件:
| 插件 | 作用 |
|---|---|
| html-webpack-plugin | 生成 HTML 并自动注入 bundle |
| clean-webpack-plugin | 清理 dist |
| mini-css-extract-plugin | 抽离 CSS |
| define-plugin | 注入环境变量 |
| terser-webpack-plugin | 压缩 JS |
| css-minimizer-webpack-plugin | 压缩 CSS |
# ⑤ Mode(构建模式)
两种环境:
mode: 'development'
// 或
mode: 'production'
2
3
区别:
| mode | 特点 |
|---|---|
| development | 无压缩、含 source map、模块标识可读 |
| production | 自动压缩、Tree shaking、Scope hoisting |
# ⑥ DevServer(开发服务器)
用于本地开发,支持热更新(HMR)。
devServer: {
hot: true,
port: 8080,
open: true
}
2
3
4
5
# ⑦ Source Map(定位代码错误)
最常见设置:
devtool: 'source-map'
# 3️⃣ Webpack 打包流程
Webpack 的构建过程:
- 读取配置(entry)
- 解析入口文件,构建 AST
- 按依赖逐层递归构建依赖图(module graph)
- Loader 转换对应文件内容
- Plugin 介入构建生命周期(optimize、emit 等)
- 生成 chunk → bundle
- 输出生成到 output 目录
如果让你用一句话描述:
Webpack 从入口出发递归构建依赖图,用 loader 处理模块,再用 plugin 插件机制对构建过程进行扩展,最后输出优化后的 bundle 文件。
# 4️⃣ Webpack 常用优化(面试高频)
# ① Tree Shaking(移除未使用代码)
生产模式自动开启,需要 ES Module。
# ② Code Splitting(代码分割)
通过动态 import 或 SplitChunks 分离公共代码。
import('./views/About.vue')
# ③ 缓存优化(长期缓存)
使用:
output: {
filename: '[name].[contenthash].js'
}
2
3
# ④ 压缩优化
生产环境自动调用:
- terser-webpack-plugin
- css-minimizer-webpack-plugin
# ⑤ 图片优化
使用 asset module 或 image-minimizer-webpack-plugin。
# 5️⃣ Webpack 与 Vite 的区别(面试非常高频)
| 对比点 | Webpack | Vite |
|---|---|---|
| 构建方式 | Bundle(打包再运行) | Native ESM(按需加载) |
| 启动速度 | 慢(依赖多) | 很快 |
| HMR | 重新打包模块 | 按需热更新 |
| 生态 | 成熟、强大 | 新,逐渐完善 |
| 适用项目 | 大型系统、复杂构建 | 快速开发、轻量项目 |
一句话总结:
Vite 开发环境快,Webpack 构建能力强、生态成熟、适合复杂工程。
# 6️⃣ Webpack 常见的面试问题(送你一套)
以下问题属于中高级 Webpack 面试必问:
# ① Loader 和 Plugin 区别?
- Loader:转换某种类型的模块(文件级别)
- Plugin:在 Webpack 完整生命周期执行(整体级别)
# ② Webpack 打包为什么慢?怎么优化?
- 持久化缓存(Webpack 5 默认 filesystem cache)
- 多进程(thread-loader)
- 缩小 loader 作用范围(include/exclude)
- 禁用不必要的 source map
- 使用 CDN、externals
# ③ Tree Shaking 原理是什么?
- 依赖 ES Module 静态结构
- 分析 import/export
- 删除未引用代码
- 配合 Terser 做 DCE(dead code elimination)
# 📌 最后给你一个—Webpack 基础总结一句话版)
Webpack 是一个模块打包器,通过 Entry、Output、Loader、Plugin 构建模块依赖图,再由 Plugin 扩展整个生命周期,最终输出优化过的 bundle。常见优化包括 Tree Shaking、Code Splitting、持久缓存、压缩优化、分离 CSS 等。
# 🔥 真实面试 Webpack 高频 20 问及答案
# 1. Webpack 是什么?它的核心概念是什么?
回答: Webpack 是一个静态模块打包器,它通过解析依赖关系,将项目中的所有资源(JavaScript、CSS、图片、字体等)转换成可在浏览器中运行的文件(bundle)。 Webpack 的核心概念有:
- Entry:入口文件,告诉 Webpack 从哪里开始构建依赖图。
- Output:输出文件,指定打包后的文件存储位置。
- Loader:让 Webpack 能处理非 JavaScript 的资源(例如:CSS、图片、字体等)。
- Plugin:通过插件系统扩展 Webpack 的功能。
# 2. Loader 和 Plugin 有什么区别?
回答:
- Loader:负责转换文件的内容,通常用于处理非 JavaScript 文件(如 CSS、图片、TypeScript 等)。它是文件级别的操作。
- Plugin:用于扩展 Webpack 的功能,执行更复杂的任务,例如压缩、优化、生成 HTML 文件等。它是全局级别的操作,处理整个构建过程。
# 3. Webpack 中的 Tree Shaking 是什么?
回答: Tree Shaking 是一种消除 JavaScript 中未使用代码的技术。Webpack 通过静态分析 ES6 模块(import/export)来确定哪些代码未被使用,并从最终的 bundle 中移除它。它通常在生产模式下启用,依赖于 ES 模块的静态结构。
# 4. 什么是 Code Splitting(代码分割)?如何实现?
回答: Code Splitting 是指将代码拆分成多个文件,以便按需加载。它可以提高应用的初次加载速度。Webpack 提供了三种方式来实现代码分割:
- 入口点分割(Entry Point):通过多个 entry 实现不同入口文件。
- 按需加载(Dynamic Import):使用
import()动态导入模块,Webpack 会根据需求自动分割代码。 - SplitChunksPlugin:Webpack 提供的插件,自动分析代码,将公共模块提取到独立的文件。
# 5. 什么是 Webpack 中的 devServer?
回答:
devServer 是 Webpack 的一个开发服务器,提供热模块替换(HMR)和实时重新加载功能。它帮助开发者在本地开发时快速预览项目,并且提供了类似 HTTP 服务器的功能。
常用配置:
devServer: {
contentBase: './dist',
hot: true,
open: true,
port: 8080
}
2
3
4
5
6
# 6. 什么是 Webpack 中的 contenthash 和 chunkhash?
回答:
chunkhash:根据 chunk 内容生成的 hash 值,常用于文件名中用于缓存控制。contenthash:根据文件内容生成的 hash 值,推荐在生产环境下使用,确保文件内容变化时文件名也会改变。
output: {
filename: '[name].[contenthash].js'
}
2
3
# 7. Webpack 如何处理依赖?
回答:
Webpack 通过静态分析代码中的 import 或 require,递归构建模块依赖图。在构建过程中,Webpack 会逐个加载每个模块并处理它们,最终生成一个或多个打包文件。
# 8. Webpack 5 如何处理 Node.js 的核心模块?
回答:
Webpack 5 移除了对 Node.js 核心模块的自动 polyfill。如果需要使用 Node 核心模块(如 crypto、path 等),需要手动配置或使用 resolve.fallback 配置来提供浏览器端的 polyfill。
resolve: {
fallback: {
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
}
}
2
3
4
5
6
# 9. 为什么 Webpack 使用 source map,它的作用是什么?
回答:
source map 是一种将压缩后的代码映射回源代码的技术,帮助开发者在浏览器调试时查看原始源码,定位错误。
常见配置:
devtool: 'source-map'
# 10. Webpack 中的 hot module replacement (HMR) 是什么?
回答: HMR 是 Webpack 提供的一种功能,允许在代码修改后只更新发生变更的模块,而不需要刷新整个页面。这大大提高了开发效率,并且避免了应用状态丢失。
# 11. Webpack 如何优化打包性能?
回答:
- 缓存优化:启用持久化缓存(Webpack 5 默认)。
- 减少模块解析时间:使用
include和exclude限制 Loader 的应用范围。 - 代码分割:通过动态 import 或 SplitChunksPlugin 来分割代码。
- Tree Shaking:移除未使用的代码。
- 并行处理:使用
thread-loader来启用多进程构建。
# 12. 什么是 Webpack 中的 externals 配置项?
回答:
externals 用于配置将外部依赖从打包中排除,使它们不被 Webpack 打包。常用于将常见库(如 React、Vue)等排除在外,减少打包文件的体积。
externals: {
react: 'React',
'react-dom': 'ReactDOM'
}
2
3
4
# 13. Webpack 中的 publicPath 配置项是什么?
回答:
publicPath 指定了资源的公共 URL 路径。它可以是 CDN 地址、相对路径或绝对路径。publicPath 通常用于指定打包后的资源文件存放位置。
output: {
publicPath: '/assets/'
}
2
3
# 14. 如何实现 Webpack 的持久化缓存?
回答:
在 Webpack 5 中,通过配置持久化缓存(cache)来加速后续构建。默认使用文件系统缓存。
cache: {
type: 'filesystem'
}
2
3
# 15. Webpack 中的 module.rules 配置项是什么?
回答:
module.rules 用于定义如何处理不同类型的文件(模块),通过配置 Loader 对模块进行转换处理。每个 rule 可以指定 test(匹配文件)和 use(使用的 Loader)。
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
2
3
4
5
6
7
8
# 16. Webpack 中的 resolve.alias 有什么作用?
回答:
resolve.alias 用于设置模块路径别名,简化模块引入路径。例如,将某个文件夹或模块映射为一个别名,减少写长路径的麻烦。
resolve: {
alias: {
'@components': path.resolve(__dirname, 'src/components/')
}
}
2
3
4
5
# 17. 为什么要使用 html-webpack-plugin?
回答:
html-webpack-plugin 用于自动生成 HTML 文件,并且将 Webpack 打包后的所有资源(如 JS、CSS 文件)自动注入到 HTML 中,避免手动更新。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
2
3
4
5
6
7
8
9
# 18. Webpack 5 相比 Webpack 4 有哪些主要改进?
回答:
- Module Federation:支持微前端架构。
- 持久化缓存:大幅提升构建速度。
- 移除 Node.js 核心模块的 polyfill:减小打包体积。
- 更好的 Tree Shaking 支持:提升打包性能。
# 19. 什么是 file-loader 和 url-loader?它们的区别是什么?
回答:
file-loader:将文件复制到输出目录,并返回文件的 URL。url-loader:功能与file-loader类似,但当文件小于指定大小时,将文件转换为 Data URL,避免发送 HTTP 请求。
区别:
file-loader始终返回文件路径,而url-loader可能返回 Data URL。
# 20. 如何在 Webpack 中实现图片压缩?
回答:
可以使用 image-webpack-loader 或 url-loader 来压缩图片。
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug
2
3
4
5
6
7
8
9
# webpack应用总结二
# module、chunk、bundle区别
- module --> 各个源代码文件都是模块,webpack中一切都是模块
- chunk --> 多模块合并成的,如 entry、import、splitChunk。类似于内存中还未产出的代码块
- bundle最终输出的文件,每个chunk都会产生一个bundle文件
entry是webpack的入口文件可以按键名生成chunk名。 import可以生成一个chunk,默认引入到html中 在optimization中定义splitChunks通过cacheGroups缓存分组并命名chunk,然后在htmlWebpackPlugin中引入或排除某个chunk文件。
# loader和plugins的区别
- 两者都是为了扩展webpack的功能。loader它只专注于转化文件(transform)这一个领域,完成压缩,打包,语言翻译; 而plugin不仅只局限在打包,资源的加载上,还可以打包优化和压缩,重新定义环境变量等
- loader运行在打包文件之前(loader为在模块加载时的预处理文件);plugins在整个编译周期都起作用
- 一个loader的职责是单一的,只需要完成一种转换。一个loader其实就是一个Node.js模块。当需要调用多个loader去转换一个文件时,每个loader会链式的顺序执行
- webpack运行的生命周期中会广播出许多事件,plugin会监听这些事件,在合适的时机通过webpack提供的API改变输出结果
- loader模块转换器,如less --> css、识别图片格式
- plugins扩展插件,如htmlWebpackPlugin、friendlyLoaderWebpackPlugin、bundleAnalyzerPlugin、CleanWebpackPlugin、MiniCssExtractPlugin、ParallelUglifyPlugin、
webpack.IgnorePlugin、webpack.DefinePlugin
常用的laoder有哪些https://www.webpackjs.com/loaders/ (opens new window) 常用的plugins有哪些https://www.webpackjs.com/plugins/ (opens new window)
# 优化babel-loader
module: {
rules: [
{
test: /\.js$/,
// loader: ['babel-loader?cacheDirectory'], // 没有修改的es6代码不会重新编译
use: {
loader: 'babel-loader',
options: {
presets: [
["@babel/preset-env"],
{
useBuiltIns: 'entry',
corejs: 3,
targets: 'last 2 Chrome versions', // 指定兼容性
// use3rBuiltIns: 'false' 不对polyfill做操作。如果引入@babel/polyfill,则无视配置的浏览器兼容性,引入所有polyfill
// use3rBuiltIns: 'entry' 根据浏览器的兼容性,引入浏览器不兼容的polyfill。兼容的就不会引入了
// use3rBuiltIns: 'usage',根据配置的浏览器兼容性,以及代码中用到的api来进行polyfill的按需添加
// 'corejs':2的时候需要在入口文件中手动添加import '@babel/polyfill',会自动动根据browserlistrc替换成浏览器不兼容的所有polyfill
// 这里需要指定core-js版本,如果”corejs“:3,则import `@babel/polyfill` 需要改成 import 'core-js/stable'; import 'regenerator-runtime/runtime'
// core-js@2 分支中已经不会再添加新特性,新特性都会被添加到core-js@3,比如,Array.prototype.flat()
}
]
}
},
include: srcPath,
// exclude: /node_modules/
},
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
配置bable-loader时include 和exclude写一个,这样减少不必要代码
- cache-loader 根据版本号文件名生成cacheKey做为文件的文件名,看文件是否存在,存在则通过对比mtime(modify time),如果相同return缓存,如果不同走下面的loader,它是一个轻量的,不对比内容的。
- babel-loader 通过文件内、option、版本号生成cacheKey做为文件的文件名,读文件是否已经存在,存在则使用缓存,不存在用bable-core转义、zlib压缩、fs写入缓存,它根据文件内容来缓存。它不影响其它loader。
# ignorePlugin和noParse
忽略掉不需要的插件。 比如jquery引入时如果不需要解析可以在noParse中声明
module:{
noParse:/jquery/,//不去解析jquery中的依赖库
}
2
3
# happyPack
- js单线程,开启多进程打包
- 提高构建速度(特别是多核cpu)
const HappyPack = require('happypack')
modles:{
rules: [
// js
{
test: /\.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ['happypack/loader?id=babel'],
include: srcPath,
// exclude: /node_modules/
}]
}
// plugins中
// happyPack 开启多进程打包
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ['babel-loader?cacheDirectory']
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ParallelUglifyPlugin
- webpack内置Uglify工具压缩js
- js单线程,开启多线程更快
- 和happyPack同理
// 引用
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
// plugins中配置
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
new ParallelUglifyPlugin({
// 传递给 UglifyJS 的参数
// (还是使用 UglifyJS 压缩,只不过帮助开启了多进程)
uglifyJS: {
output: {
beautify: false, // 最紧凑的输出
comments: false, // 删除所有的注释
},
compress: {
// 删除所有的 `console` 语句,可以兼容ie浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 关于开启多进程
如果项目较大时,打包慢,开启多进程能提高速度。但如果项目小,打包快的情况使用,开启多进程会降低速度(进程开销),要按需使用。
# 自动刷新
修改代码后变更的代码显示到浏览器,如果用了webpack-dev-server时会watch自动开启自动刷新
watch: true, // 开启监听,默认为 false
watchOptions: {
ignored: /node_modules/, // 忽略哪些
// 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高
// 默认为 300ms
aggregateTimeout: 300,
// 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的
// 默认每隔1000毫秒询问一次
poll: 1000
}
2
3
4
5
6
7
8
9
10
11
# 热更新
正常的刷新,整个页面全部刷新,速度比较慢,而且状态会丢失。热更新的话,网页不刷新,新代码生效,状态不丢失。
// 第一步引入
const HotModuleReplacementPlugin = require('webpack/lib/HotModuleReplacementPlugin');
// 第二步
entry: {
// index: path.join(srcPath, 'index.js'),
index: [
'webpack-dev-server/client?http://localhost:8080/',
'webpack/hot/dev-server',
path.join(srcPath, 'index.js')
]
},
// 第三步 在devServer中设置 开启
hot:true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
以上开启热更新,修改css样式时能热更新,且不刷新页面,但是修改js还是会刷新页面
// // 开启热更新之后的代码逻辑
// if (module.hot) {
// module.hot.accept(['./math'], () => {
// const sumRes = sum(10, 30)
// console.log('sumRes in hot', sumRes)
// })
// }
2
3
4
5
6
7
上面指有指定的math模块代码修改时会回掉callback函数,显示结果。其它的都会刷新页面。
如果页面确实很复杂,状态很多的情况下可以开启热更新
# DllPlugin动态链接库
- 前端框架如Vue、React,体积大构建慢
- 比较稳定,不常升级版本
- 同一版本只需要构建一次不需要多次构建
- webpack已经内置DllPlugin支持
- (1)DllPlugin --> 打包出dll文件(先预打包)
- (2)DllReferencePlugin --> 使用dll文件(无论做多少改动与升级,只要版本不升级文件不变就一直用那个结果)
提示
无论配置不配置dllPlugin是对程序的源代码没有影响的。
(1)、首先配置webpack.dll.js ,通过dll插件打包出dll文件
点击展开配置示例
const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
const { srcPath, distPath } = require('./paths')
module.exports = {
mode: 'development',
// JS 执行入口文件
entry: {
// 把 React 相关模块的放到一个单独的动态链接库
react: ['react', 'react-dom']
},
output: {
// 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
// 也就是 entry 中配置的 react 和 polyfill
filename: '[name].dll.js',
// 输出的文件都放到 dist 目录下
path: distPath,
// 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
// 之所以在前面加上 _dll_ 是为了防止全局变量冲突
library: '_dll_[name]', // lib全局变量名
},
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.join(distPath, '[name].manifest.json'),
}),
],
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
在package.json中配置script。设置"dll": "webpack --config build/webpack.dll.js"
执行npm run dll
此时dist中会生成react.dll.js和react.manifest.json
(2)、dll的用法:如下 首先在index.html引用react.dll.js文件(产出的js内容 )也可以动态标签方式引入文件。
在dev环境的plugin中AddAssetHtmlPlugin可以将文件动态插入到html中
new AddAssetHtmlPlugin({ filepath: path.join(distPath, 'react.dll.js'), }),
然后配置manifest的地址
// 第一,引入 DllReferencePlugin
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module: {
rules: [
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/ // 第二,不要再转换 node_modules 的代码
},
]
}
// 第三,在plugins中,告诉 Webpack 使用了哪些动态链接库
new DllReferencePlugin({
// 描述 react 动态链接库的文件内容
manifest: require(path.join(distPath, 'react.manifest.json')),
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# webpack 优化构建速度
可用于生产环境的有哪些?
- 优化babel-loader 缓存可以用开发环境也可用于生产环境
- IgnorePlugin 可以避免一些模块的引入
- noParse webpack精准过滤不需要解析的文件
- happyPack开启多进程打包会快一些
- parallelUglifyPlugin 压缩代码
不可用于生产环境的配置有哪些?
- 自动刷新
- 热更新
- dllPlugin
# webpack 性能优化
目标:
- 体积更小
- 合理分包,不重复加载
- 速度更快,内存使用更少
实践:
- 小图片base64编码 用url-loader设置limit
- bundle加hash值,如果没有变的文件hash不变,加载时会命中缓存。
- 懒加载,先把基本文件加载出来,对于大的文件可以异步加载
- 提取公共代码,在optimization中配置splitChunks分割代码块
- ignorePlugin 如:引moment库,里面有多语言忽略掉,自己引入需要的语言
- 使用cdn加速。设置output的publicPath,然后将文件上传到cdn服务器上去。如果是图片的话在配置url-loader时在options中配置publicPatch
- 使用Production,设置mode为production时会自动压缩代码。webpack4.x之后出现的。如果觉得慢可以用ParallelUglifyPlugin开启多线程压缩,根据自已情况如果已经很快了就不要添加了。mode=production的时候,vue、react会自动删除掉调试代码(如开发环境的warning)。production状态会自动开启tree-shaking(必须es6 module才能让tree-shaking生效,如果用commonjs就不行)
- 使用Scope Hosting
# es6 module和commonjs的区别
前端常用的是es6 module,nodejs常用的是commonjs
es6 module是静态引入,是编译时引入
commonjs是动态引入,执行时引入
只有es6 module静态引用才能做静态分析,实现tree-shaking
commonjs 模块输出的是一个值的拷贝,es6模块输出的是值的引用
commonjs 模块运行时加载,es6 模块是编译时输出接口
commonjs 模块加载是一个对象,只有在脚本运行完成才会生成.
es6模块不是对象,它的对外接口只是一种静态定久,在代码静态解析阶段就会生成。
// commonjs方式引入
let apiList = require('../config/api.js')
if(isDev){
// 可以执行时动态引入
apiList = require('../config/api_dev.js')
}
// es6 module方式引入
import apiList from '../config/api.js'
if(isDev) {
// 编译时报错,因为只能静态引入
import apiList from '../config/api.js'
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# tree shaking
一个模块可以有多个方法,只要其中某个方法使用到了,则整个文件会被打到bundle里面,tree shaking就是只把用到的方法打入bundle没用的在
uglify阶段删除掉原理是利用es6模块的特点,只能作为模块顶层语句出现,import的模块名只能是字符常量
webpack默认支持,在production mode下默认开启
- ”sideEffects“:false所有的代码都没有副作用(都可以进行
tree-shaking) - 可能把css和
@babel/polyfill文件干掉,可以设置"sideEffectes:['css']"
- ”sideEffects“:false所有的代码都没有副作用(都可以进行
# scope Hosting
把多个js的内容放到一个函数中去,这样作用域的数量更少一些,耗费的内存更少一些,也不用频繁的跨作用域去调用
scope hositing的原理是将所有的模块按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量防止命名冲突
这个功能在mode为production下默认是开启的。开发环境需 要用webpack.optimizeModuleConcatenationPlugin插件
- 代码体积更小
- 创建函数作用域更少
- 代码可读性更好
配置:
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenatoinPlugin')
module.exports = {
resolve:{
// 针对npm中的第三方模块优先采用jsnext:main中指向的es6 module模块化语法文件
mainFields: ['jsnext:main','browser', 'main']
},
plugins:[
// 开启scope hosting
new ModuleConcatenationPlugin(),
]
}
2
3
4
5
6
7
8
9
10
11
12
13
# 为什么要进行打包和构建
- 体积更小(Tree-shaking、压缩、合并),加载更快
- 编译高级语言或语法(TS、es6+,模块化、scss)
- 兼容性和错误提示(Pollyfill、postcss、eslint)
- 统一高效的开发环境
- 统一的构建流程和产出标准
- 集成公司构建规范(提测、上线等)