当前位置: 首页 > 科技观察

为什么说90%的前端不能调试AntDesign源码呢?

时间:2023-03-14 08:39:43 科技观察

写过react项目的小伙伴应该都用过antd组件库,但是大部分同学都没有看过它的源码。但是,想要深入掌握antd组件库,仅仅熟悉参数是不够的,还必须深入到源码层面。那么今天就来分享一下如何调试antd的源码。而且我敢说90%的前端都不会debug源码。为什么?看到后面就知道了。首先,我们使用create-react-app创建一个react项目:yarncreatereact-appantd-react-test创建成功后,进入项目,运行devserver。浏览器访问可以看到渲染后的页面:然后我们安装antd,在入口组件中导入styles和Button组件:页面会显示这个Button:如何调试这个Button组件的源码?可以这样进行:首先,创建一个VSCode调试配置:指定调试的URL,然后开始调试。在组件中打个断点,代码就到此为止了:可以看到调用栈中的上一帧是renderWithHooks,也就是react源码中调用function组件的地方。点击调用栈,会看到:它调用了App的功能组件,传入参数,得到渲染后的children进行后续处理。所有的函数组件都是在这里调用的,antd的所有组件也是函数组件,所以我们这里加个断点,当调用到名为Button的函数组件时停止?这种条件断点可以用来在一定条件下打断:右键选择添加条件断点:输入打断的条件:只有当组件名包含Button时才打断。然后刷新:你会看到App组件明明是一个函数组件,但是这里并没有坏掉,而是InternalButton这里坏掉了。这就是条件断点的作用。这个InternalButton就是antd中的Button组件。stepinto函数:你会发现这确实是Button组件的源码,只是编译过了。比如jsx编译成React.createElement:这样可以调试Button组件的源码,但是很别扭。能直接调试Button组件对应的tsx源码吗?是的,这将使用sourcemap。我们要下载antd的源码(我下载的时候是4.23):gitclone--depth=1--single-branchgit@github.com:ant-design/ant-design.git下载的时候加一个-single-branch是下载单个分支,--depth=1是下载单个commit,所以速度会快几十倍,是一个很有用的提速技巧。下载antd并安装依赖后,我们开始构建。但是你会发现package.json里面有build命令和dist命令,应该执行哪一个呢?这就需要了解antd的几个入口了。进入react项目的node_modules,找到antd的package.json看一下,会发现它有三种入口:main是commonjs的入口,也就是require的时候会经过这个('蚂蚁')。module是esm的入口,即importxxfrom'antd'时,会经过这个。unpkg是UMD的入口,即通过script标签或者commonjs的方式引入即可使用。分别对应lib、es、dist目录。所以antd项目中dist命令单独生成UMD代码,build命令生成这三个代码。三种形式的代码都有,这里我们选择构建UMD形式,因为它会和webpack捆绑在一起,而另外两种是用gulp构建的。我对webpack比较熟悉。执行npmrundist,将构建dist目录。下面是UMD的代码:你会发现默认build会生成sourcemap。其实大家可以去react测试项目看看,npm下载的antd包里面也有sourcemap:源码可以直接用dist入口代码调试吗?试一试:把导入组件的地方改成dist目录,也就是使用UMD形式的入口。再次运行调试:你会发现代码确实比之前更像源码了。之前是这样的:现在是这样的:也就是没有babelruntime的代码,明明是源码。但是你回头看看:以前是这样的:现在是这样的:还是React.createElement,不是jsx,也没有ts代码。说明它不是原始源代码。为什么会出现既是源码又不是源码的情况呢?因为它的编译过程是这样的:代码先通过tsc编译,然后通过babel编译,最后通过webpack打包成bundle.js。tsc和babel编译都会生成sourcemap,webpack也会生成sourcemap。默认情况下,webpack的sourcemap只会根据上一个loader的sourcemap生成。所以我们上面使用sourcemap之后,只能涉及到babel处理之前的代码,比如ts语法和jsx代码都没有了。因为没有上层ts-loader关联的sourcemap,自然不可能直接映射回源码。所以如果想映射回原来的tsx源码,只需要关联每一级loader的sourcemap即可。这是可配置的,它是devtool。devtool可以设置source-map,也就是生成一个sourcemap,但是这个不会和loader的sourcemap关联起来。您还可以设置cheap-module-source-map,这意味着与加载程序相关联的source-map。(那个便宜的是只保留行的sourcemap,生成速度会更快)思路清晰了,我们改一下编译配置:antd的编译工具链在@ant-design/tools包里,来自antd/node_modules/@antd-design/tools/lib/getWebpackConfig.js可以找到webpack的配置:搜索ts-loader,会看到这样的配置:确实,正如我们分析的,tsx会经过ts-loader和babel-loader处理。搜索devtool,会发现它的配置是source-map:这就是为什么antd有sourcemap,但是不能关联tsx源码的原因。然后让我们更改它:将devtool更改为cheap-module-source-map。并更改babel配置,将sourceMap设置为true,让它生成sourcemap。ts也需要生成sourcemap,但是在根目录下的tsconfig.json里改了:改完这三点后,再运行npmrundist。dist目录下会生成一个新的antd.js和antd.js.map。复制到react项目的node_modules/antd/dist下,覆盖之前的。清除babel-loader的缓存:再次运行开发服务器。注意这里使用了dist下的代码:然后跑到断点处,进入组件源码,你会进入一个新的世界:ts类型,jsx语法,熟悉的感觉又回来了,这不就是antd组件源码吗!可以断点调试antd的参数是怎么处理的,什么参数后面会有什么逻辑等等,这个完全不影响正常开发,就是把antd换成importfromantd/dist/antd,改一下就好了发育回来。现在开发antd组件还需要看文档吗?直接看源码岂不是更好吃!有的同学可能会担心node_modules下的修改不会被保存。这个不是问题,可以执行npxpatch-packageantd,会生成一个补丁文件:补丁文件记录了你对antd包的修改,可以上传到git仓库,其他小伙伴拉下来然后执行npxpatch-package将自动应用这些更改。至此,我们已经成功调试了antd组件的tsx源码。为什么说90%的前端都不会debug它的源码呢?主要是涉及的技术比较多:VSCodeChromeDebugger调试网页,这个知道的人不多。在react源码中,renderWithHooks是调用函数组件的地方。条件断点可以在条件满足时打断antd的esm、commonjs、UMD。这种入口sourcemap有什么作用呢?虽然经常接触,但是还是有很多前端没有用过webpack的cheap-module-source-map这个意思。为什么需要关联loader的sourcemap,调试antd的组件源码?这些技术需要综合运用。难度还是比较高的。综上所述,antd是react的主流组件库。我们经常使用它但可能没有调试过它的源代码。我们可以在renderWithHooks中调用函数组件的地方打条件断点,当调用到我们要调试的组件时停止,这样我们就可以进入定义组件的地方了。但是这样调试出来的并不是原来的源码,没有jsx和ts语法。要调试原始tsx源代码需要使用sourcemap。Antd有3个入口:es目录对应esm入口,lib目录对应commonjs入口,dist目录对应UMD入口。下载antd代码,执行npmrundist生成UMD形式的代码。要将sourcemap映射到tsx源代码,需要将devtool设置为cheap-module-source-map,然后开启babel-loader和ts-loader的sourcemap。覆盖antd的dist下的product,然后调试就可以直接调试antd组件的tsx源码了。除了用antd组件写业务逻辑,你还对哪些组件感兴趣?可以顺便查看一下它的源码。不好吃吗?