1:剔除npm包里面针对Node.js模块自动引用的Polyfills
v4编译引入npm包,有些npm包里面包含针对nodejs的polyfills,实际前端浏览器是不需要的
例如:
// index.js
import CryptoJS from 'crypto-js';
const md5Password = CryptoJS.MD5('123123');
console.log(md5Password);
v4 引入crypto-js模块会自动引入polyfill: crypto-browserify, 但部分代码是不需要的,v5 默认会自动剔除
v5编译中,会出现polyfill添加提示,如果不需要node polyfille,按照提示 alias 设置为 false 即可
// webpack.config.js
resolve: {
// 1.不需要node polyfilss
alias: {
crypto: false
},
// 2.手动添加polyfills
// fallback: {
// "crypto": require.resolve('crypto-browserify')
// }
}
2:长期缓存优化,
以前v4是根据代码的结构生成chunkhash,现在v5根据完全内容生成chunkhash,比如改了内容的注释或者变量则不会引起chunkhash的变化,让浏览器继续使用缓存
1:moduleId改为根据上下文模块路径计算,chunkId根据chunk内容计算
2: 为module,chunk 分配确定的(3或5位)数字ID,这是包大小和长期缓存之间的一种权衡
3:持久化缓存
1:第一次构建是一次全量构建,它会利用磁盘模块缓存(以空间换时间),使得后续的构建从中获利。
2:后续构建具体流程是:读取磁盘缓存 -> 校验模块 -> 解封模块内容。
v5 默认情况,缓存配置是memory,修改设置为filesystem, 将缓存写入硬盘
// webpack.config.js
module.exports = {
cache: {
// 1. 将缓存类型设置为文件系统
type: 'filesystem', // 默认是memory
// 2. 将缓存文件夹命名为 .temp_cache,
// 默认路径是 node_modules/.cache/webpack
cacheDirectory: path.resolve(__dirname, '.temp_cache')
}
}
4: 模板联邦
跨项目间的chunk可以相互共享
1:UMD 模块
<script src="https://unkpg.com/lodash.js"></script>
2: 微前端:多个项目共存于一个页面,有点类似iframe,共享的对象是项目级的,页面级的
子应用间的chunk以及对象可通过全局事件共享,但是公共包在项目安置以及打包编译很难放
子应用独立打包,模块解耦了,但公共的依赖不易维护处理
整体应用一起打包,能解决公共依赖;但庞大的多个项目又使打包变慢,后续也不好扩展
3:v5 的模块共享
这个方案是直接将一个应用的 bundle,应用于另一个应用,动态分发 runtime 子模块给其他应用。
模块联邦的使用方式如下:
module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
// 1. name 当前应用名称,需要全局唯一
name: "app_one_remote",
// 2. remotes 可以将其他项目的 name 映射到当前项目中
remotes: {
app_two: "app_two_remote",
app_three: "app_three_remote"
},
// 3. exposes 表示导出的模块,只有在此申明的模块才可以作为远程依赖被使用
exposes: {
AppContainer: "./src/App"
},
// 4. shared可以让远程加载的模块对应依赖改为使用本地项目的 React或ReactDOM。
shared: ["react", "react-dom", "react-router-dom"]
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"]
})
]
};
比如设置了remotes: { app_two: "app_two_remote" },在代码中就可以直接利用以下方式直接从对方应用调用模块
import { Search } from "app_two/Search";
app_two/Search来自于app_two 的配置:
// app_two的webpack 配置
export default {
plugins: [
new ModuleFederationPlugin({
name: "app_two",
library: { type: "var", name: "app_two" },
filename: "remoteEntry.js",
exposes: {
Search: "./src/Search"
},
shared: ["react", "react-dom"]
})
]
};
正是因为 Search在exposes被导出,我们因此可以使用 [name]/[exposes_name] 这个模块,这个模块对于被引用应用来说是一个本地模块。
4:构建优化 — 更好的Tree Shacking
v4 有些场景是不能将无用代码剔除的
1: 对于模块引入嵌套场景,如下b 是不会出现在生产代码里面的
// one.js
export const a = 1;
export const b = 2;
// two.js
import * as inner from "./inner";
export { inner }
// three.js
import * as module from "./module";
console.log(module.inner.a);
2:只有 test 方法使用了 someting 。最终可以实现标记更多没有使用的导出项
import { something } from "./something";
function usingSomething() {
return something;
}
export function test() {
return usingSomething();
}
3: Commondjs。现在Webpack不仅仅支持 ES module 的 tree Shaking,commonjs规范的模块开始支持了
更细致的讲解参考:
https://zhuanlan.zhihu.com/p/264826929
https://blog.csdn.net/P6P7qsW6ua47A2Sb/article/details/110015183
webpack dll: 将第三方库打包成dll.js ,这样修改应用代码只会构建应用的chunk,无关dll.js,加快速度,且浏览器缓存利好
https://www.cnblogs.com/skychx/p/webpack-dllplugin.html
hard-source-wepack-plugin:
https://segmentfault.com/a/1190000022453801
webpack 常用知识点
https://juejin.cn/post/6844904007362674701