1.详解webpackpluginçåçåç¼åä¸ä¸ªplugin
2.手摸手写个webpack plugin
3.uglifyjs-webpack-plugin 中文文档
4.webpack之plugin详解
5.源码细读-深入了解terser-webpack-plugin的实现
详解webpackpluginçåçåç¼åä¸ä¸ªplugin
plugin解å³äºä»ä¹é®é¢ï¼
plugin解å³äºWebpackæ建çå½å¨æè¿ç¨ä¸çåè½å®å¶é®é¢ï¼å¯ä»¥å©ç¨pluginåä¸å°webpackæ建æµç¨ä¸çå个é¶æ®µå¹¶å«æåä¸äºä»£ç å¤çã
æ¯å¦ï¼æå åéè¦çæä¸ä¸ªhtmlæ件ï¼é£ä¹å°±å¯ä»¥ä½¿ç¨html-webpack-pluginãè¿æï¼å¨æå ä¹åædistæ件å é¤ï¼å°±å¯ä»¥ä½¿ç¨clean-webpack-pluginã
webpackæ¬èº«å°±æ¯ä¸ä¸ªæ建è¿ç¨çç¶ææºï¼å ¶èªèº«çæ ¸å¿åè½ä¹æ¯æ建å¨loaderåpluginçæºå¶ä¸çã
compileråcompilationå ·ä½æ¯å¹²ä»ä¹çï¼é¦å æ们æ¥çä¸ä¸ªwebpackèªå¸¦çæ件BannerPlugin代ç ï¼å ¶å®webpackçå¾å¤æ ¸å¿å ¬å¸å°±æ¯å©ç¨æ件æ¥å®ç°çã
æ件çæ ¼å¼
ä¸ä¸ªJavaScriptå½æ°æJavaScriptç±»;
å¨å®ååä¸å®ä¹çapplyæ¹æ³ï¼ä¼å¨å®è£ æ件æ¶è¢«è°ç¨ï¼å¹¶è¢«webpackcompilerè°ç¨ä¸æ¬¡;
æå®ä¸ä¸ªè§¦åå°webpackæ¬èº«çäºä»¶é©åï¼å³hooksï¼ç¨äºç¹å®æ¶æºå¤çé¢å¤çé»è¾;
classBannerPlugin{ constructor(options){ this.options=options;}apply(compiler){ constoptions=this.options;constbanner=this.banner;compiler.hooks.compilation.tap("BannerPlugin",compilation=>{ compilation.hooks.processAssets.tap({ name:"BannerPlugin"},()=>{ for(constchunkofcompilation.chunks){ for(constfileofchunk.files){ constdata={ chunk,filename:file};//çæ注éconstcomment=compilation.getPath(banner,data);//æ注éå å ¥å°æ件ä¸compilation.updateAsset(file,old=>{ constsource=options.footer?newConcatSource(old,"\n",comment):newConcatSource(comment,"\n",old);returnsource;}});}}}}}}ä»ä»£ç ä¸åºç°äºcompileråcompilationï¼é£å®ä»¬å°åºæ¯ä»ä¹å¢ï¼
compilercompiler模åæ¯Webpackææ ¸å¿ç模åãæ¯æ¬¡æ§è¡Webpackæ建çæ¶åï¼å¨Webpackå é¨ï¼ä¼é¦å å®ä¾åä¸ä¸ªCompiler对象ï¼ç¶åè°ç¨å®çrunæ¹æ³æ¥å¼å§ä¸æ¬¡å®æ´çç¼è¯è¿ç¨ãcompiler对象代表äºå®æ´çwebpackç¯å¢é ç½®ï¼æ件å¯ä»¥éè¿å®è·åå°webpackçé 置信æ¯ï¼å¦entryãoutputãmoduleçé ç½®ã
compileré©åcompileræå¾å¤é©åï¼ä¸é¢åªä»ç»å¸¸ç¨çå 个:é©åå?|Tapableç±»å|触åæ¶æº?|ä¼ å ¥callbackçåæ°?||--------------------|-----------------|------------------------------------------|---------------------------------||entryOption?|SyncBailHook?|å¨webpackä¸çentryé ç½®å¤çè¿ä¹å|contextï¼entry||afterPlugins|SyncHook?|åå§åå®å ç½®æ件ä¹å|compiler||environment?|SyncHook?|åå¤ç¼è¯ç¯å¢ï¼webpackpluginsé ç½®åå§åå®æä¹å|compiler||beforeRun|AsyncSeriesHook?|å¼å§æ£å¼ç¼è¯ä¹å?|compiler||run?|AsyncSeriesHook?|å¼å§ç¼è¯ä¹åï¼è¯»årecordsä¹åï¼|compiler||compile?|SyncHook?|ä¸æ¬¡compilationç¼è¯å建ä¹å?|compilationParams?||compilation?|SyncHook?|compilationå建æåä¹å?|compilationï¼compilationParams||emit|AsyncSeriesHook?|çæèµæºå°outputç®å½ä¹å?|compilation||done|AsyncSeriesHook?|compilationå®æä¹å|stats?||failed?|SyncHook?|compilation失败|
æ´ä¸ªCompilerå®æ´å°å±ç°äºWebpackçæ建æµç¨ï¼
åå¤é¶æ®µï¼makeä¹ååçäºæ é½å±äºåå¤é¶æ®µï¼è¿é¶æ®µçcalbackå ¥å以compiler为主ï¼
ç¼è¯é¶æ®µï¼è¿é¶æ®µä»¥compilationçé©å为主ï¼calbackå ¥å以compilation为主ï¼
产åºé¶æ®µï¼è¿é¶æ®µä»compilationå¼å§ï¼æååå°Compileré©åä¸ï¼calbackä¼ å ¥åæ°æ¯è·ç»æç¸å ³çæ°æ®ï¼å æ¬statsãerrorã
compilationå¨compilationé¶æ®µï¼æ¨¡åä¼è¢«å è½½(loaded)ãå°å(sealed)ãä¼å(optimized)ãåå(chunked)ãåå¸(hashed)åéæ°å建(restored)ï¼Compilation对象å å«äºå½åç模åèµæºãç¼è¯çæèµæºãååçæ件çãCompilation对象ä¹æä¾äºå¾å¤äºä»¶åè°ä¾æ件åæ©å±ï¼éè¿Compilationä¹è½è¯»åå°Compiler对象ã
Compilationé©å
å¨Compilationä¸å¤çç对象åå«æ¯moduleãchunkãassetsï¼ç±modulesç»æchunksï¼ç±chunksçæassetsï¼å¤ç顺åºæ¯ï¼moduleâmodulesâchunksâassetsï¼å ä»å个moduleå¼å§å¤çï¼æ¥æ¾ä¾èµå ³ç³»ï¼æåå®æå个moduleå¤çï¼å®æå ¨é¨modulesä¹åï¼å¼å§chunksé¶æ®µå¤çï¼æåå¨æ ¹æ®ä¼åé ç½®ï¼æéçæassetsã
æ以æ´ä¸ªCompilationççå½å¨æé©åè½ç¶æ¯è¾å¤ï¼ä½æ¯å¤§è§å¾ä¸æ¯å´ç»è¿ä¸ªé¡ºåºè¿è¡çï¼å ·ä½çé©åå¯ä»¥æ¥çwebpackå®ç½ã
Stats对象å¨Webpackçåè°å½æ°ä¸ä¼å¾å°stats对象ãè¿ä¸ªå¯¹è±¡å®é æ¥èªäºCompilation.getStats()ï¼è¿åçæ¯ä¸»è¦å«æmodulesãchunksåassetsä¸ä¸ªå±æ§å¼ç对象ã
modulesï¼è®°å½äºææ解æåç模åï¼
chunksï¼è®°å½äºææchunkï¼
assetsï¼è®°å½äºææè¦çæçæ件ã
æäºå¯¹compilercompilationçç解ï¼é£ç°å¨æ¥ççBannerPluginçå®ç°ï¼è¿ä¸ªæ件çåè½æ¯å¨æåçæçæ件ç头é¨å ä¸ä¸æ®µæ们èªå®ä¹ç注éï¼é£ä¹å®çæ§è¡æ¶æºè¯å®æ¯å¨ç¼è¯å®æä¹åï¼çææå æ件ä¹é´ï¼ä¹å°±æ¯å¨compiler.hooks.compilationè¿ä¸ªå¤§é©åä¸é¢çprocessAssetsé©åéé¢æ§è¡æ们çé»è¾ã
ç¼åpluginplugin:å¨æ件尾é¨æå ¥ä¸æ®µæ³¨éé¦å å建ä¸ä¸ªplugins/FootPlugin.jsï¼ä»£ç å¦ä¸:
const{ ConcatSource}=require('webpack-sources')classFootPlugin{ constructor(options){ this.options=options}apply(compiler){ compiler.hooks.compilation.tap('FootPlugin',compilation=>{ compilation.hooks.processAssets.tap('FootPlugin',()=>{ for(constchunkofcompilation.chunks){ for(constfileofchunk.files){ console.log('file--',file)//bundle.js//å®ä¹æ³¨éçå 容constcomment=`/*${ this.options.banner}*/`compilation.updateAsset(file,old=>{ //æ注éåæ§ä»£ç è¿è¡æ¼æ¥returnnewConcatSource(old,'\n',comment)})}}})})}}module.exports=FootPluginwebpack.config.js
constFootPlugin=require('./plugins/FootPlugin')module.exports={ plugins:[newwebpack.BannerPlugin({ banner:'欢è¿å¦ä¹ '}),newFootPlugin({ banner:'ç»æå¦ä¹ '})]}å¯ä»¥çå°å¨bundle.jsçå¼å¤´åç»å°¾é½æ对åºç注éã
plugin:æä»¶è¶ è¿ä¸å®å¤§å°æ¶ç»åºè¦åconst{ resolve}=require('path')constfs=require('fs')classBundleSizeWebpackPlugin{ constructor(options){ this.options=options}apply(compiler){ const{ sizeLimit}=this.optionsconsole.log('bundlesizeplugin')//å¨ç¼è¯å®æåï¼æ§è¡åè°ï¼æ¿å°æå åæ件路å¾ï¼ç¶å读åæ件信æ¯è·åæ件大å°ï¼ç¶åå®ä¹ä¸äºé»è¾compiler.hooks.done.tap('BundleSizePlugin',stats=>{ const{ path,filename}=stats.compilation.outputOptionsconstbundlePath=resolve(path,filename)const{ size}=fs.statSync(bundlePath)constbundleSize=size/if(bundleSize<sizeLimit){ console.log('safe:bundle-size',bundleSize,'\nsizelimit:',sizeLimit)}else{ console.warn('unsafe:bundle-size',bundleSize,'\nsizelimit:',sizeLimit)}})}}module.exports=BundleSizeWebpackPluginæ¬ç« å°è¿éå°±ç»æäºï¼æ们å¼å§ä»ç»äºwebpackçæ ¸å¿æ¦å¿µï¼æäºå¯¹webpackçåºæ¬é ç½®çäºè§£ï¼æ¥çå©ç¨css-loaderåstyle-loader对webpackçloaderæºå¶è¿è¡äºè¯¦ç»åæï¼æåï¼å¯¹webpackpluginçå·¥ä½æºå¶åæµç¨è¿è¡äºæ¢³çï¼å¹¶æåäºä¸¤ä¸ªpluginï¼è®©ä½ 对pluginä¸åè§å¾é¥ä¸å¯åãæäºè¿äºåç½®ç¥è¯ï¼å°±å¯ä»¥å¯¹æ们åç项ç®è¿è¡å·¥ç¨åçæ¹é äºãæå¾ ä½ çå¦ä¹ ã
åæï¼/post/手摸手写个webpack plugin
本周的任务是深入了解和编写webpack插件。插件是什么?它实际上是一个具有 apply 方法的JavaScript对象,更准确地说,就是一种函数。它可以是普通的函数,也可以是论坛 ios app源码特殊的函数,用于实现特定功能。
相比loader,插件可以解决一些loader无法处理的场景,比如在打包开始前进行环境配置、打包结束后发送通知邮件等。例如,HtmlWebpackPlugin插件可以帮助我们在dist文件夹下自动生成index.html文件,并在其中自动引入打包后的css和js脚本文件。安装并配置插件后,运行打包指令,可以看到生成的index.html文件自动引入了生成的main.js脚本文件。
接下来,macd背离画线源码我们深入探讨HtmlWebpackPlugin的源码,了解如何编写插件。通过观察源码,我们可以发现插件是通过apply方法在特定生命周期内执行操作。以HtmlWebpackPlugin为例,其在初始化阶段会利用Compiler提供的hook函数,实现生成html文件并引入资源的功能。
为了更深入理解插件的工作原理,我们可以执行yarn run webpack命令,跟踪webpack的运行过程,了解不同hook函数的调用时机和作用。例如,afterDone钩子函数会在打包完成后触发,用于执行发送通知邮件等操作。通过观察Compiler类的实现,我们可以理解如何在插件中访问和利用Compiler实例对象,以及如何在特定钩子函数的虚拟货币网站html源码回调中实现自定义逻辑。
接下来,我们以一句话需求为例,实现一个在webpack打包后发送通知邮件的插件。首先,我们需要安装nodemailer库以实现邮件发送功能。然后,根据需求编写插件代码,利用Compiler提供的hook函数,如afterDone,实现邮件发送逻辑。运行webpack后,我们可以看到通知邮件被成功发送。为了方便他人使用,我们还可以将自定义插件发布到npm仓库。
在插件开发中,还有一些重要的概念,如SyncHook和AsyncHook,空间列表源码带后台它们分别用于同步和异步操作。另外,了解如何在插件中正确使用这些概念,对于提高插件的可复用性和功能性至关重要。官方文档提供了关于编写插件的详细指导,建议开发者深入学习。
总之,通过本篇文章的学习,我们不仅掌握了webpack插件的基本概念和使用方法,还深入探讨了其原理和实战应用。希望这些知识能帮助开发者在实际项目中灵活运用插件,提升开发效率。
uglifyjs-webpack-plugin 中文文档
uglifyjs-webpack-plugin 的核心功能与配置
uglifyjs-webpack-plugin 是一个用于webpack项目的插件,它利用uglify-js进行JavaScript文件的压缩,以减小文件大小并提升网站性能。 要开始使用,首先确保你的小镇里的花源码项目环境满足要求:Node.js版本需在6.9.0及以上,Webpack版本需为4.0.0及以上。安装与配置
在项目中安装插件:javascript
npm install uglifyjs-webpack-plugin
接着,在webpack配置文件(webpack.config.js)中添加插件配置,如示例所示:
javascript
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js(?.*)?$/i,
use: {
// ...
plugins: [
new UglifyJsPlugin({
// 插件配置项
}),
],
},
},
],
},
// ...
};
配置选项包括:test:匹配需要压缩的JavaScript文件。
include:指定要包含在压缩过程中的文件。
exclude:指定要排除在压缩过程中的文件。
cache:选择启用或自定义缓存机制。
parallel:启用多进程并行压缩,提高构建速度。
sourceMap:选择是否启用源码映射,注意这会增加编译时间。
minify:自定义压缩函数,允许使用其他压缩工具。
extractComments:控制如何处理和提取注释。
condition:用于设置特定注释的提取条件。
filename:定义提取注释的文件名。
warningsFilter:过滤uglify-js产生的警告。
根据具体需求调整这些选项,例如,要启用缓存和多进程并行运行,可以这样配置:javascript
new UglifyJsPlugin({
cache: true,
parallel: true,
// 其他配置项...
}),
webpack之plugin详解
plugin在webpack中扮演着核心角色,它们是构建工具的扩展点,用于解决loader无法实现的其他功能。要使用plugin,通常先通过npm安装到本地,然后在配置文件(webpack.config.js)的头部引入,紧接着在plugins那一栏使用new关键字生成插件的实例并注入到webpack中。在webpack构建过程中,plugin会在特定的生命周期函数触发时执行定义的功能。这些生命周期函数可以类比为打包流程中的工序,当执行到特定工序时,plugin绑定的事件就会被触发。
例如,clean-webpack-plugin插件会在webpack重新打包前自动清空输出文件夹,而HtmlWebpackPlugin插件则会在打包结束后根据配置的模板路径自动生成一个html文件,并把打包生成的js路径自动引入到这个html文件中,大大提高了开发效率。
webpack程序架构中包含compiler和compilation两个核心概念。compiler是webpack的支柱引擎,负责控制程序的执行,其生命周期函数用于定义在不同阶段执行的事件。compiler会从左到右执行每一个生命周期函数定义的事件队列。compilation实例主要负责代码的编译和构建,每次代码编译(例如日常开发时按ctrl + s保存修改后的代码)都会生成一个新的compilation实例来执行构建任务。
在compilation的生命周期中,compiler进入make阶段后,compilation实例被创建,它依次执行一系列定义的钩子函数,包括加载相应的loader对代码进行编译、解析生成AST语法树、进行依赖分析、优化和封装等步骤。这些步骤构成了webpack完整的打包构建流程。
Tapable是一个用于事件发布订阅的第三方库,webpack中使用Tapable实现了事件的绑定和触发机制。通过使用Tapable提供的SyncHook和AsyncSeriesHook,可以定义同步和异步事件,这些事件会在特定的生命周期阶段被触发。
为了开发自定义插件,可以创建一个js文件并实现一个class,其中包含一个固定方法apply。apply函数的第一个参数是compiler,可以在apply函数内部编写插件逻辑。为了在特定生命周期阶段绑定事件,可以使用Tapable提供的hook,例如在emit阶段绑定事件。通过这样的方式,插件可以在webpack执行到特定时刻时执行特定功能。
使用自定义插件时,首先在webpack配置文件中引入插件,然后在plugins数组中使用new关键字注入插件实例。这样,当webpack执行到相应的事件节点时,插件定义的监听函数就会被触发。
源码细读-深入了解terser-webpack-plugin的实现
terser-webpack-plugin 是一个基于 webpack 的插件,它利用 terser 库对 JavaScript 代码进行压缩和混淆。其核心功能在于通过在 webpack 的运行时钩子 optimizeChunkAssets 中注册,实现了代码优化过程。在 apply 函数中,它获取 compilation 实例,并通过 tapPromise 注册一个异步任务,当 webpack 执行优化阶段时,每个 chunk 会触发这个任务,执行 minify 函数进行压缩处理。
optimise 函数是实际的任务处理入口,它负责具体的优化流程。函数内部,scheduleTask 负责并行处理,如果开启 parallel 模式,会利用jest-worker提供的线程池进行并发工作,线程池管理复杂,根据 node 版本不同采用 worker_threads 或 child_process。minify 函数则是压缩和混淆代码的核心操作,它直接使用 terser 库完成任务。
总的来说,terser-webpack-plugin 的优化流程包括在 webpack 的优化阶段对代码进行压缩,使用 Jest 的 worker 线程池进行并行处理,以及通过 terser 库的实际压缩操作。理解这些核心环节,可以帮助开发者更深入地掌握该插件的使用和工作原理。