1.å¦ä½å¨WebStorm 2017ä¸è°è¯Vue.js + webpack
2.webpack 4 源码主流程分析(十一):文件的码调生成
3.放弃 console.log 吧!用 Debugger 你能读懂各种源码
4.源码细读-深入了解terser-webpack-plugin的码调实现
5.webpack之devtool详解
6.webpack的devtool 配置
å¦ä½å¨WebStorm 2017ä¸è°è¯Vue.js + webpack
æ人è§å¾vue项ç®é¾è°è¯ï¼æ¯å 为ç¨äºwebpackãææ代ç æå¨äºä¸èµ·ï¼è¿å äºå¾å¤æ¡æ¶ä»£ç ï¼æ ¹æ¬ä¸ç¥éæä¹ä¸æãæ以vue+webpackè°è¯è¦ä»webpackå ¥æã
1.æ们å ä»ä¸è¬æ åµå¼å§è¯´ã
-sourcemap
webpacké ç½®æä¾äºdevtoolè¿ä¸ªé项ï¼å¦æ设置为 â#source-mapâï¼åå¯ä»¥çæ.mapæ件ï¼å¨chromeæµè§å¨ä¸è°è¯çæ¶åå¯ä»¥æ¾ç¤ºæºä»£ç ã
devtool: '#source-map'
2.ç¶èè¿ä¸ªè®¾ç½®å®é ä¸æ²¡è¿ä¹ç®åãwebpackå®æ¹ç»åºäº7个é 置项ä¾éæ©:
.devtoolä»ç»
è¿éä¸åçé ç½®æäºä¸åçææï¼æ¯å¦æ¯å¦ä¿ç注éãä¿çè¡ä¿¡æ¯çï¼å ·ä½æ¯ä¸æ¡ä»ä¹ææè¿éä¸è¯¦è§£éï¼æå ´è¶£çç«¥éå¯ä»¥åèè¿ç¯æç«
å®æ¹é»è®¤çæ¯ç¨ â#cheap-module-eval-source-mapâ
devtool: '#cheap-module-eval-source-map'
设置好ä¹åï¼å¨vue项ç®è°è¯çæ¶åï¼ä»£ç éé¢æ 注debuggerçæ¶åå°±è½çå°å¯¹åºç代ç äºï¼é常æ¹ä¾¿ã
.debugger
æè ï¼ç´æ¥æ¾å°å¯¹åºçæ件ãå¨chromeç¨ âctrl(command) + pâï¼è¾å ¥æ件åï¼å¯ä»¥æ¾å°å¯¹åºçæºä»£ç ã
command+p
ææç¹ï¼
æç¹
éè¦æ³¨æçæ¯ï¼è¿éæç¹ä¼æå¨ä¸ä¸è¡ãåæ¶ä¸è¡ä»£ç è¿è¡å¨å®çä¸ä¸è¡æç®æ§è¡ã
.-vue-cli
vue家ç项ç®èææ¶ï¼æ¨è使ç¨ãvue-cliè家å¨è¿é
vue-cliå¯ä»¥å¸®æ们èªå¨æ建项ç®ï¼é¦å npmå ¨å±å®è£
npm install -g vue-cli
ç¶åå建ä¸ä¸ªæ°ç项ç®
vue init webpack my-project
ä¸è·¯å车ï¼æå®ã(æ´å¤é 置项请åèä¸é¢ç»åºçvue-clié¾æ¥)
è¿éä»ç½ä¸ä¸è½½äºä¸ä¸ªå¸¦webpackçvue项ç®(è·ä¹åè®°å¾npm installä¸ä¸)
.vue-cli webpack
ä»bulidæ件夹éé¢å°±å¤§æ¦è½çåºï¼
•webpack.dev.conf: å¼å模å¼ç¨
•webpack.prod.conf: ç产模å¼ç¨
å ¶ä¸ï¼å¼å模å¼æä¾äºdevtool为â#cheap-module-eval-source-mapâï¼ç产模å¼æ ¹æ®configæ件夹ä¸çproductionSourceMapåéæ§å¶æ¯å¦ä½¿ç¨ã
è¥ä¸ºtrueï¼ådevtool为â#source-mapâ
å ¶ä»ä½¿ç¨æ¹æ³ä¸è´ãé常æ¹ä¾¿ã
3.线ä¸è°è¯
å¹³æ¶å¼åçæ¶åï¼æ们ç¨webpackççå è½½ï¼å¯ä»¥çå»æè½½è°è¯çæ¥éª¤ï¼é常æ¹ä¾¿ãä½æ¯åå¸åé¨ç½²å°æå¡å¨ä¸ï¼å°±å¤±å»äºè¿ä¸ªæ¬å°ä¼å¿ã
å¦æ使ç¨æè½½æ件æ¹å¼ä¼æ¯è¾éº»ç¦ãç±äºwebpackæåºæ¥çæ件æçæ¬å·è¿äºä¿¡æ¯ï¼èä¸åå¸ä¸ä¸ªå ç代ç éå¯è½éè¦çå¾ ä¸çï¼è¿ä¸ªæ¹æ¡ä¸å®é ãä½æ¯å¦ææè½½çæ¯çå è½½å°ç«¯å£ä¸çæ件çè¯ï¼è¿ä¸ªé®é¢å°±å¾å¥½åäºã
-çå è½½
å¨æ¤ä¹åï¼å æ¥åæä¸ä¸webpackççå è½½åçã
对项ç®æå å¯ä»¥åç°è¿ä¹ä¸ä¸ªæ件ï¼__webpack_hmr
__webpack_hmr
è¿æ¯webpackçå è½½çæå¡å¨æ¨éäºä»¶ï¼eventsourceç±»åï¼åè½åwebsocketæç¹ç±»ä¼¼ã大è´ä½ç¨æ¯å»ºç«ä¸ä¸ªä¸ä¼åæ¢çstreamæµé¾æ¥ï¼æå¡å¨åéæ´æ°æ°æ®åæ¥appendå°æµçæ«ç«¯ï¼å端读åææ°appendçæ°æ®ï¼ç¶åå¨æçæ´æ°é¡µé¢ä¸çä¸è¥¿ã
æ¥ä¸æ¥æ们è§å¯ä¸ä¸ææå°çæ´æ°æ°æ®æåªäºãé便æ´æ°ä¸ä¸ªæ件ï¼è§¦åçå è½½ï¼åæ个å ï¼åç°æ两个.hot-update.jsonåä¸ä¸ª.hot-update.jsæ件
çå è½½æ´æ°æ件
è¿äºå ·ä½åäºäºå¥æä¸ç¥éï¼è¿éå°±ä¸æ·±ç©¶äºãåºè¯¥æ¯æ ¹æ®jsonéé¢çæ°æ®ï¼è¾¾å°ä¸ä¸ªåç¡®æ´æ°çææã
æ以çæ´æ°å ¶å®å°±æ¯çå¬æå¡å¨ä¸çæ°æ®ï¼æä¿®æ¹çè¯æå¡å¨åéæ°æ®è¿æ¥ï¼å端ææ°æ®æ¿æ¥åæ¿æ¢å°é¡µé¢ä¸è¿ä¹ä¸ä¸ªè¿ç¨ã
-AutoResponder
æ¥ä¸æ¥è°è°çº¿ä¸æè½½æµè¯ï¼è¿éæ¨èä¸æ¬¾è½¯ä»¶ï¼fiddler
fiddleræä¸ä¸ªåè½å«åAutoResponderï¼å®å¯ä»¥å°ä¸ä¸ªå°åæåå¦ä¸ä¸ªå°åãä¹æ以ç¨è¿ä¸ªè½¯ä»¶ï¼æ¯å 为å®è½å¹é æ£åï¼é常æ¹ä¾¿ã
AutoResponder
ä¸ä¸è说å°ï¼webpackçå è½½ç¨å°äºè¿å ç±»æ件
•__webpack_hmr
•xxxxxxxxxxx.hot-update.json
•xxxxxxxxxxx.hot-update.js
webpack 4 源码主流程分析(十一):文件的生成
本文深入分析了 Webpack 4 中文件生成的具体流程。在资源写入文件阶段,码调通过一系列优化和处理,码调最终返回到 Compiler.js 的码调 compile 方法,其中 Compiler 的码调源码燕窝批发属性 _lastCompilationFileDependencies 和 _lastCompilationContextDependencies 被赋予了 fileDependencies 和 contextDependencies。紧随其后的码调是创建目标文件夹的过程,该操作通过 outputPath 属性配置,码调结合 mkdirp 函数完成。码调
在创建目标文件并写入阶段,码调通过 asyncLib.forEachLimit 方法并行处理每个文件资源,码调实现路径拼接、码调源码转换为 buffer,码调最后写入真实路径的码调文件。对于不同类型的码调 source 实例,如 CachedSource、ConcatSource 和 ReplaceSource,其处理逻辑各不相同,但最终目标都是获取替换后的字符串并合并返回 resultStr。所有文件创建写入完成后,执行回调,触发Compiler.afterEmit:hooks,进一步设置 stats 并打印构建信息。
至此,构建流程全部结束。通过本文的分析,我们可以更直观地了解 Webpack 4 中文件生成的具体实现细节,为深入理解 Webpack 的工作原理和优化提供理论支持。本章小结,下章将解析打包后的文件,敬请期待。
放弃 console.log 吧!用 Debugger 你能读懂各种源码
很多同学不清楚为什么要使用debugger进行调试,难道console.log不行吗?
即使学会了使用debugger,还是显卡bios的源码有很多代码看不懂,如何调试复杂的源码呢?
这篇文章将为你讲解为什么要使用这些调试工具:console.log vs Debugger。
相信绝大多数同学都会使用console.log进行调试,将想查看的变量值打印在控制台。
这种方法可以满足基本需求,但遇到对象打印时就无法胜任了。
比如,我想查看webpack源码中的compilation对象的值,我尝试打印了一下:
但你会发现,当对象的值也是对象时,它不会展开,而是打印一个[Object] [Array]这样的字符串。
更严重的是,打印的内容过长会超过缓冲区的大小,在terminal中显示不全:
而使用debugger来运行,在这里设置一个断点查看,就没有这些问题了:
有些同学可能会说,那打印一个简单的值时使用console.log还是很方便的。
比如这样:
真的吗?
那还不如使用logpoint:
代码执行到这里就会打印:
而且没有污染代码,使用console.log的话,调试完成后这个console也不得不删除掉。
而logpoint不需要,它就是一个断点的设置,不在代码中。
当然,最重要的是debugger调试可以看到调用栈和作用域!
首先是调用栈,它就是代码的执行路线。
比如这个App的函数组件,你可以看到渲染这个函数组件会经历workLoop、beginWork、renderWithHooks等流程:
你可以点击调用栈的每一帧,查看都执行了什么逻辑,用到了什么数据。比如可以看到这个函数组件的科技强国网页源码fiber节点:
再就是作用域,点击每一个栈帧就可以看到每个函数的作用域中的变量:
使用debugger可以看到代码的执行路径,每一步的作用域信息。而你使用console.log呢?
只能看到那个变量的值而已。
得到的信息量差距不是一点半点,调试时间长了,别人会对代码的运行流程越来越清晰,而你使用console.log呢?还是老样子,因为你看不到代码执行路径。
所以,不管是调试库的源码还是业务代码,不管是调试Node.js还是网页,都推荐使用debugger打断点,别再用console.log了,即使想打印日志,也可以使用LogPoint。
而且在排查问题的时候,使用debugger的话可以加一个异常断点,代码跑到抛异常的地方就会断住:
可以看到调用栈来理清出错前都走了哪些代码,可以通过作用域来看到每一个变量的值。
有了这些,排查错误就变得轻松多了!
而你使用console.log呢?
什么也没有,只能自己猜。
Performance
前面说debugger调试可以看到一条代码的执行路径,但是代码的执行路径往往比较曲折。
比如那个React会对每个fiber节点做处理,每个节点都会调用beginWork。处理完之后又会处理下一个节点,再次调用beginWork:
就像你走了一条小路,然后回到大路之后又走了另一条小路,使用debugger只能看到当前这条小路的执行路径,看不到其他小路的路径:
这时候就可以结合Performance工具了,使用Performance工具看到代码执行的全貌,然后用debugger来深入每一条代码执行路径的sourceforge 怎么下载源码细节。
SourceMap
sourcemap非常重要,因为我们执行的都是编译打包后的代码,基本是不可读的,调试这种代码也没有什么意义,而sourcemap就可以让我们直接调试最初的源码。
比如vue,关联了sourcemap之后,我们能直接调试ts源码:
nest.js也是:
不使用sourcemap的话,想搞懂源码,但你调试的是编译后的代码,怎么读懂呢?
读懂一行
前面说的debugger、Performance、SourceMap只是调试代码的工具,那会了调试工具,依然读不懂代码怎么办呢?
我觉得这是不可能的。
为什么这么说呢?
就拿react源码来说:
switch case能读懂吧。三目运算符能读懂吧。函数调用能读懂吧。
每一行代码都能读懂,而全部的代码不就是由这一行行代码组成的么?
加上我们可以单步执行来知道代码执行路径。
为啥每行代码都能读懂,连起来就读不懂了呢?
那应该是代码太多了,而你花的时间不够而已。
先要读懂一行,一个函数,读懂一个小功能的实现流程,慢慢积累,之后了解的越来越多之后,你能读懂的代码就会越多。
总结
这篇文章讲了为什么要使用调试工具,如何读懂复杂代码。
console.log的弊端太多了,大对象打印不全,会超过terminal缓冲区,vb按钮美化源码对象属性不能展开等等,不建议大家使用。即使要打印也可以使用LogPoint。
使用debugger可以看到调用栈,也就是代码的执行路径,每个栈帧的作用域,可以知道代码从开始运行到现在都经历了什么,而console.log只能知道某个变量的值。
此外,报错的时候也可以通过异常断点来梳理代码执行路径来排查报错原因。
但debugger只能看到一条执行路径,可以使用Performance录制代码执行的全流程,然后再结合debugger来深入其中一条路径的执行细节。
此外,只有调试最初的源码才有意义,不然调试编译后的代码会少很多信息。可以通过SourceMap来关联到源码,不管是Vue、React的源码还是Nest.js、Babel等的源码。
会了调试之后,就能调试各种代码了,不存在看不懂的源码,因为每一行代码都是基础的语法,都是能看懂的,如果看不懂,只可能是代码太多了,你需要更多的耐心去读一行行代码、一个个函数、理清一个个功能的实现,慢慢积累就好了。
掌握基于debugger、Performance、SourceMap等调试代码之后,各种网页和Node.js代码都能调试,各种源码都能读懂!
源码细读-深入了解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 库的实际压缩操作。理解这些核心环节,可以帮助开发者更深入地掌握该插件的使用和工作原理。
webpack之devtool详解
Webpack的Devtool详解 Webpack的Devtool是开发者在开发和调试过程中重要的工具之一,它可以帮助开发者更好地理解和调试代码。Devtool提供了多种不同的配置选项,用于生成源代码映射,以便于开发者在浏览器控制台中直接查看源代码,从而更有效地定位和解决代码中的问题。 一、什么是Devtool? Webpack的Devtool是一个配置选项,允许开发者在构建过程中生成源代码映射。源代码映射是一种文件,它将编译后的代码映射回原始源代码,以便于开发者调试。Devtool的不同配置选项会生成不同类型的源代码映射,适用于不同的开发场景。 二、Devtool的主要配置选项 1. eval模式:这是最简单的源代码映射形式,它直接在控制台输出源代码。这种模式下,不需要生成额外的文件,但生成的源代码映射相对较小且不持久。 2. source-map模式:在这种模式下,Webpack会生成一个独立的.map文件来存储源代码映射信息。这种模式的源代码映射比较详细,但会增加构建时间。 3. inline-source-map模式:与source-map模式类似,但源代码映射信息会直接嵌入到构建后的文件中。这种模式便于传输和分发构建后的文件,但同样会增加文件大小。 4. cheap-module-eval-source-map模式:适用于模块化的项目,能够提供模块级别的调试信息。它在开发和调试阶段很有用,但生成的源代码映射相对较小。 三、如何选择适合的Devtool配置? 选择Devtool的配置取决于项目的需求和开发阶段。在开发阶段,为了快速迭代和调试代码,可以选择生成更详细的源代码映射;而在生产环境,为了优化性能和文件大小,可以选择生成较小的源代码映射或者不使用源代码映射。常见的做法是在开发阶段使用如eval或cheap-module-eval-source-map等详细的配置选项,而在生产环境使用source-map或inline-source-map等更精简的配置选项。 总之,Webpack的Devtool是开发者在开发和调试过程中的重要工具,通过合理配置Devtool,可以大大提高开发效率和代码质量。webpack的devtool 配置
devtool配置与代码调试紧密相关,旨在优化调试体验。在前端开发中,源代码经过合并、压缩、转换后,运行的是转换后的代码,这给调试带来了挑战。因此,chrome浏览器率先引入了source map技术,其他浏览器也纷纷跟进,如今几乎所有新版浏览器都支持source map。
source map本质上是一个配置,它不仅记录了所有源码内容,还记录了源码与转换后代码之间的对应关系,便于开发人员直接定位到源代码中的错误。浏览器处理source map的原理在于解析这个映射关系,从而显示正确的源代码位置信息。
最佳实践包括:在开发环境中使用source map作为调试工具,避免在生产环境中使用,以防止额外的网络传输和潜在的代码暴露风险。如果在生产环境中使用source map用于调试,需采取措施确保网络传输和代码安全。
在webpack中,devtool配置可以优化调试体验。使用正确的devtool选项,能够提供不同级别的源码映射,以适应开发与生产环境的需求。例如,"eval"配置选项在开发环境中提供快速构建,同时保留了正确的行号映射,而"cheap"配置在开发环境中提供了较低开销的映射,忽略了列映射信息。
在生产环境中,通常选择不生成source map,以优化性能。然而,如果需要生成source map,可以选择将它作为单独的文件输出,并在bundle中添加引用注释,以便开发工具查找。此外,还存在一些特定场景的配置选项,如仅生成用于错误堆栈跟踪的source map,或不包含sourcesContent的source map,以保护源代码安全。
Webpack 性能优化 二次编译速度提升3倍!
本文作者为 奇舞团前端开发工程师 Rien.
本文主要记录 webpack 的一次性能优化。
随着业务复杂度增加,项目体积庞大,webpack 编译时间延长。项目二次编译时间在 5s 到 6s 之间,影响迭代速度。优化手段包括但不限于环境分离、并行编译等。
首先,优化 sourcemap 配置。使用 webpack.ProgressPlugin 分析发现,耗时主要在生成 sourcemap 文件阶段。默认配置为 source-map,实际并无此需求。通过对比不同 sourcemap 配置,发现 eval-cheap-module-source-map 适用于开发环境,可以大大减少这一阶段耗时,同时对开发体验和错位定位影响较小。生产环境则可使用 none 或 nosources-source-map,前者不会暴露源码,后者生成的 sourcemap 文件体积更小。
接下来,升级 Html-webpack-plugin。优化后,二次编译时间显著提升。然而,通过分析发现,html-webpack-plugin 耗时异常,改为最新版本后,耗时从秒级降至毫秒级。
在排查过程中,发现编译慢是由 eslint-loader 导致。项目初期,代码量较小,后因需求迭代,部分功能模块代码量巨大。eslint-loader 对整个文件进行校验,耗时较长。移除 eslint-loader 后,在部分大文件改动时,编译时间得到提升。为弥补代码规范问题,建议在本地开发时使用 vscode eslint 插件进行代码校验。
通过上述优化,二次编译时间大幅度提升,改善了开发效率和体验,提升近 3 倍。