webpack5学习进阶:Library、模块联邦、构建优化

webpack5学习进阶:Library、模块联邦、构建优化对它进行概要分析 以免引入性能问题

大家好,欢迎来到IT知识分享网。

一、Library

webpack 除了可以打包应用程序外,还可以打包 JavaScript 的 library;当我们想自己开发一个组件库、工具、框架的时候,也就是说我们想自己造轮子给别人用的时候,免不了要开发很多的模块,最终我们都可以借助 webpack 来进行打包;

1、如何构建 library
//index.js export const add = function(a,b){ 
    return a+b 

webpack.config.js

const path = require('path') module.exports={ 
    mode:"production", entry:"./src/index", output:{ 
    path:path.resolve(__dirname,"dist"), filename:"myTest.js", bibrary:{ 
    name:"myTest", type:"umd" }, clean:true, globalObject:"globalThis" //解决commonJS打包找不到self的问题 } } 

由于是生产环境下的打包,webpack 会自动进行 Tree Sharking ,将未被使用的包自动剔除;我们在 index.js 里面的代码没有被使用,所以直接进行打包, main.js 里面是空的;

那么我们如何才能让我们 index.js 文件作为一个 library 来进行打包呢?让代码不被 Tree Sharking ?
我们可以使用 output.library 来指定包名;这样我们的 library 就可以正常打包然后提供使用了;

注意: type 是为了设置使用我们的 library 时的引入方式;umd 支持:script 标签、CommonJS、AMD 这几种方式的引入;

//script标签 <script src="../dist/myTest.js"></script> <script> console.log(myTest.add(1,2)) </script> //CommonJS const { 
   add}= require("../dist/myTest") console.log(add.(1,2)) 

当然我们也可以使用 import 来进入文件,但是这样会更麻烦一点,需要下面的配置:

//webpack.config.js const path = require('path') module.exports = { 
    mode:'production', entry:{ 
    app1:'./src/app.js', }, experiments:{ 
    outputModule:true }, output:{ 
    path:path.resolve(__dirname,"dist"), filename:"app.js", library:{ 
    type:"module" }, clean:true, }, } //index.html <script type="module"> import { 
    add } from './dist/app.js' console.log(add) </script> 

在 webpack 配置中添加 experiments 的配置,然后删除 library 的 name 属性;在使用的时候需要把 import 放在 type 为 module 的 script 标签内部;

2、发布为 npm-package

执行命令行:

npm config get registry //获取注册地址,必须是 https://registry.npmjs.org/ npm adduser //新增用户,填写用户名、密码、邮箱信息 npm publish //发包 

每次发新的包,包的名称必须保持唯一性。

二、模块联邦(Module Federation)

多个独立的构建我们可以组成一个应用程序,这些独立的构件之间不存在任何的依赖关系,因此我们可以单独的开发和部署他们,这种通常可以称之为:微前端;

webpack 可以通过 dll 或者是 externals 来做到代码共享时的一个 common chunk;但是不同应用和项目之间这个共享任务就变得非常困难了,webpack5 提供的模块联邦可以让代码直接在项目之间利用 CDN 直接共享,不再需要本地安装 npm 包构建在发布了;

1、模块共享管理方式对比

1、npm:以前我们代码的共享是依靠 npm ,将依赖作为一个 labrary 安装到我们的项目里,进行 webpack 打包,构建上线;
2、UMD:我们还可以通过 UMD、将模块用 webpack umd 的模式打包,并且输出到其他的应用程序当中;(包的体积无法达到本地编译时的优化效果,库之间容易产生冲突)
3、微前端:(MFE )子应用独立打包模块实现解耦,但是无法抽取公共的依赖;整体应用打包,但是打包是速度太慢了;
4、模块联邦:webpack5 内置的一个核心特性,可以直接将一个线上的应用共享给其他应用使用,具备整体应用打包、公共依赖抽取的能力;

2、使用模块联邦

如果两个线上的项目(a、b),a 项目想访问 b 项目里的某一个模块,这个时候就需要使用到模块联邦了;模块联邦是一个独立的插件,不需要安装,可以在 webpack 里面获取到;

2.1、a 项目中暴露 header 组件
//a项目中 webpack.config.js const { 
    ModuleFederationPlugin }= require('webpack').container module.exports={ 
    mode:'production', entry:'./src/index.js', plugins:[ new ModuleFederationPlugin({ 
    name:'header', filename:'remoteEntry.js', remotes:{ 
   }, exports:{ 
    './header':'./src/header.js' }, shared:{ 
   } }) ] } 

模块联邦下属性的含义:
name:标识模块联邦的名字,提供给其他应用使用;
filename:远端入口,由于项目已经部署到线上,像访问需要有一个js文件的路径;
remotes:引用其他项目暴露的组件;
exports:暴露一些组件给其他项目使用,暴露以key-value 形式,key 是别的项目使用的时候基于这个路径拼接 url ,value 才是组件在当前项目下的路径;
shared:把模块中共享的第三方模块放在这里,在打包的时候会打包到一个单独的包里面;

2.2、b 项目中引入组件
//b项目中引入 webpack.config.js const { 
    ModuleFederationPlugin }= require('webpack').container module.exports={ 
    mode:'production', entry:'./src/index.js', plugins:[ new ModuleFederationPlugin({ 
    name:'footer', filename:'remoteEntry.js', remotes:{ 
    header:'header@http://xxxx/remoteEntry.js' }, exports:{ 
    './footer':'./src/footer.js' }, shared:{ 
   } }) ] } 

在 remotes 中引入 a 项目中暴露的组件,key 是 b 项目中引入组件的一个别名,value 是一个组合的字符串,分为三个部分:a 项目暴露模块联邦的 name、a 项目的服务域名加端口号、a 项目模块联邦的 filename;

2.3、b 项目使用组件

由于网络共享、模块导入是有延迟的,所以我们使用异步的方式来引入它;

//index.js import('header/header').then((header)=>{ 
    //在这里就可以直接使用 a 项目中的 header 组件了; }) 

这里 import 的 header/header 是什么意思呢? 第一个 header 是当前项目引入 其他项目的时候 在 remotes 中配置的 key,第二个 header 则是 a 项目中在暴露的时候 exports 中 配置的路径 key ;

注意:如果引入多个项目暴露出来的组件的话,我们可以使用 Promise.all 方法;

三、构建性能优化

webpack 的性能提升可以分为两类:1、提升项目性能,如网站的首屏加载时间,针对用户;2、提高打包速度,降低打包时间,针对开发者;每个版本的 webpack 构建优化点都是不一样的,所以建议参照官网的优化点进行优化;

1、通用环境

通用环境是指开发环境加生产环境;

1.1、更新到最新版本(webpack、node.js)

这两个工具在升级版本的时候会内置的提升性能;除此之外也可以把我们的 npm、 yarm 更新到最新版本;

1.2、将 loader 应用于最少数量的必要模块

精准解析需要解析的文件,可以大大提高打包速度;

1.3、引导 bootstrap

每个额外的 loader、plugin 都有其启动时间,尽量少的使用工具;

1.4、解析

1、减少 resolve.modules、resolve.extensions、resolve.mainFiles、resolve.descriptionFiles 中条目数量,因为他们会增加文件系统调用的次数;

2、如果不使用 symlinks (例如 npm link 、yarm link ),可以设置 resolve.symlinks:false

3、如果使用了自定义 rsolve.plugin 规则,但是没有指定 context 上下文,可以设置 resolve.cacheWithContext:false

1.5、小就是快

减少编译结果的整体大小,尽量保持 chunk 体积小:
1、使用数量更小、体积更新的 library
2、在多页面应用程序中使用 SplitChunkPlugin,并开启 async 模式
3、移除未引用的代码
4、只编译你当前正在开发的代码

1.6、持久化缓存

在 webpack 中,使用 chache 选项,在 package.json 中使用 postinstall 清除缓存目录;

1.7、自定义 plugin、loader

对它进行概要分析,以免引入性能问题

1.8、progress plugin

将 ProgressPlugin 从 webpack 中删除,可以缩短构建时间,ProgressPlugin 可以显示 webpack 打包的进度,这个只是一种方案,真实的性能提升效果不大(不建议删除);

1.9、dll

使用 DllPlugin 为更改不频繁的代码生成单独的编译结果,这样可以提高应用程序的编译速度,尽管增加看构建过程的复杂程度;

新建一个 webpack.dll.config.js 配置文件使用 webpack.DllPlugin 来打包 jquery;

const path = require('path') const webpack = require('webpack') module.exports={ 
    mode:'production', entry:{ 
    jquery:['jquery'] //这里引入的是jquery 模块 }, output:{ 
    filename:'[name].js', path:path.resolve(__dirname,'dll'), library:'[name]_[hash]' }, plugins:[ new wenbpack.DllPlugin({ 
    name:'[name]_[hash]', path:path.resolve(__dirname,'dll/manifest.json') }) ] } 

在 package.json 把它作为一个 npm 脚本执行,配置 dll 运行命令来执行 jquery 的 dll 编译打包;

"script":[ "dll":"webpack --config ./webpack.dll.config.js" ] 

然后执行 npm run dll 就可以执行打包,打包完成之后在项目中生成一个 dll 文件夹,里面是 jquery 相关的代码以及 manifest.json 文件;这个 json 文件让我们可以在项目中引入并使用 jquery;我们项目中使用:webpack.config.js

const path = require('path') const webpack = require('webpack') const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin') module.exports = { 
    plugins:[ new webpack.DllReferencePlugin({ 
    manifest:path.resolve(__dirname,'./dll/manifest.json') //引入dll打包生成的manifest.json }), new AddAssetHtmlPlugin({ 
    filepath:path.resolve(__dirname,'./dll/jquery.js'), publicPath:'./' }) ] } 

打包使用 jquery 之前还需要借助插件 add-asset-html-webpack-plugin ,将 dll 打包后的 js 引入到打包后的 html 文件中;然后项目打包,生成的 dist 文件夹下会生成一个 jquery 文件,并在 html 文件中引入;

1.10、worker 池

thread-loader 可以将非常消耗资源的 loader 分流给一个 worker pool;npm i thread-loader -D 提升打包速度;

module:{ 
    rules:[ { 
    test:/\.js$/, exclude:/node_modules/, use:[ { 
    loader:'babel-loader', options:{ 
    presets:['@babel-preset-env'] } }, { 
    loader:'thread-loader', options:{ 
    workers:2 } } ] } ] } 

想要将 babel-loader 放到一个 worker pool 中,需要在 babel-loader 运行前先执行 thread-loader;注意 thread-loader 自身也有时间消耗,只能用于一些十分耗时的包才会有优化效果(谨慎使用);

2、开发环境
2.1、增量编译

使用 webpack 的 watch model 监听模式,内置的会更优化;watch model 会记录时间戳并将此信息传递给 conpilation 让缓存失效;在某些配置环境中,watch model 会回退到 poll model 轮询模式,监听文件过多会导致大量的 CPU 负载,这时可以使用 watchOptions.poll 来增加轮询的间隔时间;

2.2、在内存中编译

下面几个工具都是通过内存编译合 serve 资源资源来提高性能:
webpack-dev-server
webpack-hot-middleware
webpaclk-dev-middleware

2.3、stats.toJson 加速

webpack 4 默认使用 stats.toJson() 输出大量的数据,这个方法尽量避免使用,除非要做增量的统计;webpack-dev-server 在 3.1.3 版本修复了这一问题:最小化每一个增量构建中,从 stats 中获取数据;

2.4、devtool

不同的 devtool 配置,会导致性能上的差异:最佳选中是 eval-cheap-module-source-map ;

2.5、避免在生产环境中才用到的工具

有些 plugin、loader 、utility 是只有生产环境才有作用,所以尽量排除这些工具:TerserPlugin、miniify、mangle等;

2.6、最小化 entry chunk

确保在生成 entry chunk 时尽量减少体积来提高性能可以配置:

optimization:{ 
    runtimeChunk:true } 
2.7、避免额外的优化步骤

webpack 通过执行额外的算法任务来优化输出结果的体积合加载性能,这些只适用小型代码库,如果是大型代码库就会非常消耗性能:一般情况下要关闭掉下面这三个

optimization:{ 
    removeAvailableModules:false, removeEmptyChunks:false, splitChunks:false } 
2.8、输出结果不携带路径信息

webpack 会在输出的 bundle 中生成路径信息,然而在打包数千个模块的项目中,会导致垃圾回收性能压力,可以设置关闭:

output:{ 
    pathinfo:false } 
2.9、node 版本问题

尽量不要使用 node.js v8.9.10-v9.11.1 版本,因为它的 ES2015 Map 和 Set 实现存在性能回退,webpack使用的话会影响编译时间;

2.10、TypeScript loader

在使用 TS loader 的时候尽量加一个配置项 transpileOnly 选项,来缩短使用 ts-loader 的构建时间,这个选项会关闭类型检查;

module:{ 
    rules:[ { 
    test:/\.js$/, use:[ { 
    loader:'ts-loader', options:{ 
    transpileOnly:true } } ] } ] } 
3、生产环境
3.1、不启用 sourceMap

source map 非常消耗资源,开发环境不要设置 source map;

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/145701.html

(0)
上一篇 2024-11-25 19:00
下一篇 2024-11-25 19:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信