webpack5
1、不再为Node.js模块自动引入Polyfills
在 Webpack 4 或之前的版本中,任何项目引用 Node.js 内置模块都会自动添加 Polyfills,Polyfills是一个语法检查的模版工具。不过,Webpack 5不再为 Node.js 内置模块自动添加 Polyfills,Webpack 5会投入更多的精力到前端模块的兼容性工作中
如果你的代码中有引用这些 Node.js 的模块,当需要升级到 Webpack 5版本时, 请将尽量使用前端的模块,或者自行手动添加适合的 Polyfills。
module.exports = {
resolve:{
/* fallback:{
'crypto':require.resolve('crypto-browserify'),
'stream':require.resolve('stream-browserify'),
'buffer':require.resolve('buffer')
}, */
fallback:{
'crypto':false,
'stream':false,
'buffer':false
}
},
}
2、moduleId和ChunkId优化
Webpack 5新增了长期缓存的算法,这些算法在生产模式下是默认启用的,语法格式如下。
module.exports = {
optimization: {
moduleIds: 'deterministic' //natural named size
chunkIds: 'deterministic' //natural named size total-size,开发默认named,生产默认deterministic
}
};
该算法以确定性的方式为模块和分块分配短的(3 位)数字 ID,这是包大小和长期缓存之间的一种权衡。由于这些配置将使用确定的 ID 和名称,这意味着生成的缓存失效不再更频繁。
3、资源模块
Webpack 5 现在已经对表示资源的模块提供了内置支持。这些模块可以向输出文件夹发送一个文件,或者向 Javascript 包注入一个 DataURI。 无论哪种方式,它们都会给出一个 URL 来让程序正常工作。不需要单独安装raw-loader、url-loader、file-loader
module.exports = {
module:{
rules:[
{
test:/\.png$/,
type: 'asset/resource' //对标file-loader
},
{
test:/\.ico$/,
type: 'asset/inline' //对标url-loader 模块的大小<limit base64字符串
},
{
test:/\.txt$/,
type:'asset/source' //对标raw-loader
},
{
test:/\.jpg$/,
type:'asset', //对标raw-loader
parser:{
dataUrlCondition:{
maxSize: 4*1024
}
}
},
]
}
4、性能优化
持久化缓存
module.exports = {
cache:{
//不要再使用cnpm来安装模块
type: 'filesystem', //memory filesystem
cacheDirectory: path.resolve(__dirname, 'node_modules/.cache/webpack'), //filesystem时自定义缓存路径
}
}
5、构建优化
tree-shaking
Webpack5能够跟踪对导出的嵌套属性的访问,因此可以改善重新导出命名空间对象时的 Tree Shaking(清除未使用的导出和混淆导出)。
Webpack 5 有一个新的选项 optimization.innerGraph,在生产模式下是默认启用的,它可以对模块中的标志进行分析,找出导出和引用之间的依赖关系。
要获得未使用的导出信息,需要使用 optimization.usedExports。要删除无副作用的模块,需要使用optimization.sideEffects
module.exports = {
optimization:{
usedExports: true, //标使用到的导出
}
}
package.json配置
"sideEffects": [
"*.css",
"@babel/polyfill"
],
6、模块联邦 module federation
从开发者的角度来看,模块可以从指定的远程构建中导入,并以最小的限制来使用
remote端
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
...
new ModuleFederationPlugin({
name: 'remoteVar',// remote向外暴露的全局变量名
filename: 'remoteEntry.js',//构建出来的文件名
exposes:{
'./NewsList': './src/NewsList'
},
shared:['react', 'react-dom']
})
]
}
host端
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
...
new ModuleFederationPlugin({
remotes:{
remote: 'remoteVar@http://localhost:8080/remoteEntry.js'
},
shared:['react','react-dom']
})
]
}
const RemoteNewList = React.lazy(()=>import('remote/NewsList'));
const App = ()=>(
<div>
<React.Suspense fallback="Loading NewsList">
<RemoteNewList/>
</React.Suspense>
</div>
)
因此可以使用 [name]/[exposes_name] 这个模块,这个模块对于被引用应用来说是一个本地模块
通过 shared 选项 —— remotes 将会首先依赖来自 host 的依赖,如果 host 没有依赖,它将会下载自己的依赖。没有代码层面的冗余,而只有内置的冗余
Webpack 5 Module Federation: JavaScript 架构的变革者