共计 5960 个字符,预计需要花费 15 分钟才能阅读完成。
装置与启动
Webpack 5 公布曾经有一段时间了,很多小伙伴都在思考要不要降级,有没有降级的必要,不晓得降级后有哪些扭转;
明天咱们就来做个比照看看,webpack5 带来了那些全新的扭转;
没有比照就没有挫伤,为了更好地挫伤 webpack 4 , 咱们应用 webpack4 和 webpack 5 别离构建一个 React 我的项目来做比照:
mkdir webpack4 | |
mkdir webpack5 | |
# 别离执行 初始化命令 | |
npm init -y |
创立文件 /src/index.js,/src/App.js,/src/index.html
React 代码示例
index.js
import React from "react" | |
import ReactDom from "react-dom" | |
import App from "./App" | |
ReactDom.render(,document.getElementById('root')) |
App.js
index.html
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Document</title> | |
</head> | |
<body> | |
<!-- 加一行正文 --> | |
<div id="root"></div> | |
</body> | |
</html> |
装置与启动
webpack4
// webpack4 | |
npm install webpack@4 webpack-cli@3 html-webpack-plugin css-loader style-loader babel-loader @babel/core @babel/preset-env @babel/preset-react -D | |
npm install react react-dom |
因为仓库中目前默认就曾经是 webpack5 了,所以,想要装置 webpack4,咱们须要加上 @4 的版本号;
webpack5
// webpack5 | |
npm install webpack webpack-cli html-webpack-plugin css-loader style-loader babel-loader @babel/core @babel/preset-env @babel/preset-react -D | |
npm install react react-dom |
根底配置 webpack.config.js
const path = require('path') | |
const HtmlWebpackPlugin = require('html-webpack-plugin') | |
module.exports = { | |
// entry 入口,output 进口,module 模块,plugins 插件 mode 工作模式,devServer 开发服务器 | |
// mode 工作模式 | |
mode: 'development', // production、development、none | |
// 入口 | |
entry:'./src/index.js', | |
// 进口 | |
output:{ | |
filename:'./bundle.js', | |
path:path.resolve(__dirname,'dist') | |
}, | |
// 模块 | |
module:{ | |
rules:[ | |
{ | |
test:/\.js$/, | |
exclude:/node_modules/, | |
use:[ | |
{ | |
loader:'babel-loader', | |
options:{ | |
presets:[ | |
'@babel/preset-env', | |
'@babel/preset-react' | |
] | |
} | |
} | |
] | |
}, | |
] | |
}, | |
// 插件 | |
plugins:[ | |
new HtmlWebpackPlugin({template:'./src/index.html'}) | |
] | |
} |
启动命令的区别
先装置 npm install webpack-dev-server -D
配置服务器:
// 服务器 | |
devServer:{ | |
port:3004, | |
open:true | |
}, |
webpack 4:webpack4/package.json
"scripts": { | |
"test": "echo \"Error: no test specified\"&& exit 1", | |
"build": "webpack", | |
"start": "webpack-dev-server" | |
}, |
webpack 5:webpack5/package.json
"scripts": { | |
"test": "echo \"Error: no test specified\"&& exit 1", | |
"build":"webpack", | |
"start":"webpack serve" | |
}, |
资源模块解决
https://webpack.docschina.org/guides/asset-modules/#source-assets
资源模块 (asset module) 是一种模块类型,它容许应用资源文件(字体,图标等)而无需配置额定 loader。
在 webpack 5 之前,通常应用:
- raw-loader 将文件导入为字符串
- url-loader 将文件作为 data URI 内联到 bundle 中
- file-loader 将文件发送到输入目录
资源模块类型(asset module type),通过增加 4 种新的模块类型,来替换所有这些 loader:
- asset/resource 发送一个独自的文件并导出 URL(之前通过应用 file-loader 实现)
- asset/inline 导出一个资源的 data UR(之前通过应用 url-loader 实现)
- asset/source 导出资源的源代码(之前通过应用 raw-loader 实现)
- asset 在导出一个 data URI 和发送一个独自的文件之间主动抉择(之前通过应用 url-loader,并且配置资源体积限度实现)
webpack4:
// 模块 | |
module:{ | |
rules:[ | |
{ | |
test:/\.js$/, | |
exclude:/node_modules/, | |
use:[…………] | |
}, | |
{test:/\.(png|jpg|gif)$/, | |
// 装置 url-loader file-loader | |
loader:'url-loader', | |
options:{ | |
// 小于 8KB 转 base64 | |
limit:8*1024 | |
} | |
} | |
] | |
}, |
webpack5:
// 模块 | |
module:{ | |
rules:[ | |
{ | |
test:/\.js$/, | |
exclude:/node_modules/, | |
…………………… | |
}, | |
{test:/\.(png|jpg|gif)$/, | |
// 通用资源类型 | |
type:'asset', | |
// 当初,webpack 将依照默认条件,主动地在 resource 和 inline 之间进行抉择:// 小于 8kb 的文件,将会视为 inline 模块类型,否则会被视为 resource 模块类型。// 自定义设置 | |
parser:{ | |
dataUrlCondition:{maxSize:8*1024} | |
} | |
} | |
] | |
}, |
文件缓存
https://webpack.docschina.org/configuration/other-options/#cache
缓存生成的 webpack 模块和 chunk,可能改善构建速度。
cache 会在 开发模式 下被设置成 type: ‘memory’ 而且在 生产模式 中被禁用。
cache: true 与 cache: {type: ‘memory’} 配置作用统一。
cache.type
cache.type 将 cache 类型设置成内存或者文件系统。‘memory’ | ‘filesystem’
memory 选项很简略,它会通知 webpack 将内容寄存在内存中并且不容许额定的配置;
filesystem 选项,应用文件缓存零碎;
cacheDirectory
cacheDirectory 定义缓存目录,默认为 node_modules/.cache/webpack。
cache.cacheDirectory 选项仅当 cache.type 被设置成 filesystem 才可用。
webpack.config.js
// mode 工作模式 | |
mode:'development', | |
cache:{ | |
type:'filesystem', | |
// 默认缓存到 node_modules/.cache/webpack 中 | |
// 也能够自定义缓存目录 | |
// cacheDirectory:path.resolve(__dirname,'node_modules/.cac/webpack') | |
} |
即便内容批改,增量编译的缓存成果也很显著
更好的 Tree Shaking
https://webpack.docschina.org/guides/tree-shaking/
Tree Shaking 技术,也被称为“树摇”,没错,翻译的就是这么间接,意思也很简略,未应用的导出内容不会被打包生成;它依赖于 ES2015 模块语法的 动态构造 个性,例如 import 和 export。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 遍及起来的。
为了更好阐明这个原理,我做了一个动画,全网首发的动画成果,简略解释一下,有两个模块四个办法,在模块 x 中,应用了 B 办法和从模块 Y 中导入的 C 办法,而 X 模块中本人的 A 和模块 Y 中的 D 办法,并没有应用,尽管定义了,因为没有在任何中央应用过,因而,在“摇树”过程中,就会被“摇掉”;
在 webpack 中如何应用呢?其实很简略,只有将 mode 工作模式改为 production 就会主动开启;
而如果想要感触这个树摇带来的触动酥麻酸爽的过程,咱们也能够应用手动配置的形式来自行抉择,首先须要将 mode 工作模式改为 none,意思就是不做任何优化,全副应用配置的形式,如何配置呢?增加 optimization.usedExports 和 optimization.minimize 选项,意思就是开启树摇及压缩
// mode 工作模式 | |
mode: 'none', // production、development、none | |
// production 生产环境,默认优化打包 | |
// none 不做任何操作 | |
// usedExports:true 开启优化(树摇但保留代码)// minimize:true 开启压缩 (删除未应用代码) | |
optimization:{ | |
usedExports:true, | |
minimize:true | |
// innerGraph: true, | |
} |
接下来,咱们再应用简略代码做比照:
index.js
import * as m1 from "./m1"; | |
console.log(m1.m2.nu1) |
m1.js
import * as m2 from './m2' | |
export function fun1(){console.log('1--11',m2.c); | |
} | |
export function fun2(){console.log('1--22') | |
} | |
export {m2} |
m2.js
export function fun3(){console.log('2--33'); | |
} | |
export function fun4(){console.log('2--44') | |
} | |
export const nu1 = 456 | |
export const nu2 = 789 |
雷同的代码,在 webpack 4 的打包后果中,咱们能看到不仅代码量大,而且还有 i=789 这个多余的代码,反观 webpack 5 的打包后果,简洁到难以置信;
模块联邦
多个独立的构建能够组成一个应用程序,这些独立的构建之间不应该存在依赖关系,因而能够独自开发和部署它们。
这通常被称作微前端
为了更好地阐明这个原理,我做了一个动画,寰球首发的动画成果
导出模块
const path = require('path') | |
const HtmlWebpackPlugin = require('html-webpack-plugin') | |
// const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin") | |
const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin; | |
………… | |
// 插件 | |
plugins: [ | |
new HtmlWebpackPlugin({template: './src/index.html'}), | |
new ModuleFederationPlugin({ | |
// 模块名字 | |
name: 'remote', // 导入时应用名称标注 | |
// 编译后的模块文件名,导入时应用 | |
filename: 'remoteEntry.js', | |
// 导出模块 关键字与模块名 | |
exposes: { | |
// "key 导入时应用的关键字" : "对应模块文件" | |
"./Us": './src/User.js' | |
} | |
}), | |
], |
导入模块
const path = require('path') | |
const HtmlWebpackPlugin = require('html-webpack-plugin') | |
const ModuleFederationPlugin = require("webpack").container.ModuleFederationPlugin; | |
………… | |
// 插件 | |
plugins: [ | |
new HtmlWebpackPlugin({template: './src/index.html'}), | |
new ModuleFederationPlugin({ | |
name:'user:55', | |
// 导入内部模块 | |
remotes:{ | |
// 导入别名:关键字 @地址 / 导出文件名 | |
remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js" | |
} | |
}) | |
], |
在 ModuleFederationPlugin 实例化的时候传入参数 options 的字段阐明:
// 模块名字 | |
name: 'remote', // 导入时应用名称标注 | |
// 编译后的模块文件名,导入时应用 | |
filename: 'remoteEntry.js', | |
// 导出模块 关键字与模块名 | |
exposes: { | |
// "key 导入时应用的关键字" : "对应模块文件" | |
"./Us": './src/User.js' | |
} | |
// 导入内部模块 | |
remotes:{ | |
// 导入别名:关键字 @地址 / 导出文件名 | |
remoteHost:"remote@http://127.0.0.1:3055/remoteEntry.js" | |
} |
还有就是 exposes 和 remotes 的字段小伙伴们也要留神,
- exposes 的裸露字段要写上 ./name
- remotes 的字段跟裸露模块的 name 保持一致,外面别名的定义也要统一
最初,两个利用同时启动,就会发现最终你要的利用就把其余利用的模块也引入进来了