awesome-interview/book2/engineer-babel/index.html

20 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-beta.5">
<title data-react-helmet="true">Babel 的原理 | HZFE - 剑指前端 Offer</title><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="og:url" content="https://hzfe.github.io/awesome-interview/book2/engineer-babel"><meta data-react-helmet="true" name="docusaurus_locale" content="en"><meta data-react-helmet="true" name="docusaurus_version" content="current"><meta data-react-helmet="true" name="docusaurus_tag" content="docs-default-current"><meta data-react-helmet="true" property="og:title" content="Babel 的原理 | HZFE - 剑指前端 Offer"><meta data-react-helmet="true" name="description" content="相关问题"><meta data-react-helmet="true" property="og:description" content="相关问题"><link data-react-helmet="true" rel="shortcut icon" href="/awesome-interview/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://hzfe.github.io/awesome-interview/book2/engineer-babel"><link data-react-helmet="true" rel="alternate" href="https://hzfe.github.io/awesome-interview/book2/engineer-babel" hreflang="en"><link data-react-helmet="true" rel="alternate" href="https://hzfe.github.io/awesome-interview/book2/engineer-babel" hreflang="x-default"><link rel="stylesheet" href="/awesome-interview/assets/css/styles.36d1aa8c.css">
<link rel="preload" href="/awesome-interview/assets/js/runtime~main.21038279.js" as="script">
<link rel="preload" href="/awesome-interview/assets/js/main.de89bd10.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div><a href="#" class="skipToContent_1oUP">Skip to main content</a></div><nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/awesome-interview/"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--light_3UqQ navbar__logo"><img src="/awesome-interview/img/badge.svg" alt="HZFE" class="themedImage_1VuW themedImage--dark_hz6m navbar__logo"><b class="navbar__title">剑指前端 Offer</b></a></div><div class="navbar__items navbar__items--right"><a href="https://github.com/hzfe/awesome-interview" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_3J9K"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div class="main-wrapper docs-wrapper docs-doc-page"><div class="docPage_31aa"><button class="clean-btn backToTopButton_35hR" type="button"><svg viewBox="0 0 24 24" width="28"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" fill="currentColor"></path></svg></button><aside class="docSidebarContainer_3Kbt"><div class="sidebar_15mo"><nav class="menu thin-scrollbar menu_Bmed menuWithAnnouncementBar_2WvA"><ul class="menu__list"><li class="menu__list-item"><a class="menu__link" href="/awesome-interview/">前言</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">模拟题一</a></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#">模拟题二</a><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/browser-render-mechanism">浏览器:浏览器渲染机制</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/browser-garbage">浏览器:垃圾回收机制</a></li><li class="menu__list-item"><a class="menu__link menu__link--active" aria-current="page" tabindex="0" href="/awesome-interview/book2/engineer-babel">工程化Babel 的原理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/frame-react-fiber">框架React Fiber 的作用和原理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/frame-react-hoc-hooks">框架HOC vs Render Props vs Hooks</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/js-inherite">基础ES5、ES6 如何实现继承</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/js-new">基础New 操作符的原理</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/css-preprocessor">样式:谈谈 CSS 预处理器</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/network-http-cache">网络HTTP 缓存机制</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/coding-throttle-debounce">编码:实现节流去抖函数</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/algorithm-reverse-linked-list">算法:反转链表</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/awesome-interview/book2/topic-multi-pics-site-optimize">综合:多图站点性能优化</a></li></ul></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#">模拟题三</a></li></ul></nav><button type="button" title="Collapse sidebar" aria-label="Collapse sidebar" class="button button--secondary button--outline collapseSidebarButton_1CGd"><svg width="20" height="20" aria-hidden="true" class="collapseSidebarButtonIcon_3E-R"><g fill="#7a7a7a"><path d="M9.992 10.023c0 .2-.062.399-.172.547l-4.996 7.492a.982.982 0 01-.828.454H1c-.55 0-1-.453-1-1 0-.2.059-.403.168-.551l4.629-6.942L.168 3.078A.939.939 0 010 2.528c0-.548.45-.997 1-.997h2.996c.352 0 .649.18.828.45L9.82 9.472c.11.148.172.347.172.55zm0 0"></path><path d="M19.98 10.023c0 .2-.058.399-.168.547l-4.996 7.492a.987.987 0 01-.828.454h-3c-.547 0-.996-.453-.996-1 0-.2.059-.403.168-.551l4.625-6.942-4.625-6.945a.939.939 0 01-.168-.55 1 1 0 01.996-.997h3c.348 0 .649.18.828.45l4.996 7.492c.11.148.168.347.168.55zm0 0"></path></g></svg></button></div></aside><main class="docMainContainer_3ufF"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_3FnS"><div class="docItemContainer_33ec"><article><div class="tocCollapsible_1PrD tocMobile_3Hoh"><button type="button" class="clean-btn tocCollapsibleButton_2O1e">On this page</button></div><div class="markdown"><header><h1>Babel 的原理</h1></header><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_31ik" id="相关问题"></a>相关问题<a class="hash-link" href="#相关问题" title="Direct link to heading">#</a></h2><ul><li>Babel 是什么</li><li>Babel 有什么用</li><li>压缩代码如何实现</li></ul><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_31ik" id="回答关键点"></a>回答关键点<a class="hash-link" href="#回答关键点" title="Direct link to heading">#</a></h2><p><code>JS 编译器</code> <code>AST</code> <code>插件系统</code></p><p>Babel 是 <strong>JavaScript 编译器</strong>:他能让开发者在开发过程中,直接使用各类方言(如 TS、Flow、JSX或新的语法特性而不需要考虑运行环境因为 Babel 可以做到按需转换为低版本支持的代码Babel 内部原理是将 JS 代码转换为 <strong>AST</strong>,对 AST 应用各种插件进行处理,最终输出编译后的 JS 代码。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_31ik" id="知识点深入"></a>知识点深入<a class="hash-link" href="#知识点深入" title="Direct link to heading">#</a></h2><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_31ik" id="1-ast-抽象语法树"></a>1. AST 抽象语法树<a class="hash-link" href="#1-ast-抽象语法树" title="Direct link to heading">#</a></h3><p><strong>简单定义</strong>:以树的形式来表现编程语言的语法结构。</p><p><img src="https://user-images.githubusercontent.com/17002181/124874255-1742bd80-dffa-11eb-9fcf-2a2f9e130334.png" alt="image"></p><p>利用在线 <a href="https://astexplorer.net/" target="_blank" rel="noopener noreferrer">playground</a> 调试,可以对 AST 有个直观感受:生成的树有多个节点,节点有不同的类型,不同类型节点有不同的属性。</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly js"><pre tabindex="0" class="prism-code language-js codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">const</span><span class="token plain"> custom </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;HZFE&quot;</span><span class="token punctuation" style="color:#393A34">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p><img src="https://user-images.githubusercontent.com/17002181/124893664-7fe76580-e00d-11eb-8937-a6b7719643f4.png" alt="image"></p><p>AST 是源代码的高效表示,能便捷的表示大多数编程语言的结构。适用于做代码分析或转换等需求。之所以用树来进行分析或转换,是因为树能使得程序中的每一节点恰好被访问一次(前序或后续遍历)。</p><p><strong>常见使用场景</strong>:代码压缩混淆功能可以借助 AST 来实现:分析 AST基于各种规则进行优化如 IF 语句优化;移除不可访问代码;移除 debugger 等),从而生成更小的 AST 树,最终输出精简的代码结果。</p><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_31ik" id="2-babel-编译流程"></a>2. Babel 编译流程<a class="hash-link" href="#2-babel-编译流程" title="Direct link to heading">#</a></h3><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithStickyNavbar_31ik" id="三大步骤"></a>三大步骤<a class="hash-link" href="#三大步骤" title="Direct link to heading">#</a></h4><p><img src="https://user-images.githubusercontent.com/17002181/124876479-9f29c700-dffc-11eb-9eef-a4bc85ebb6be.png" alt="image"></p><ol><li><p><strong>解析阶段</strong>Babel 默认使用 <strong>@babel/parser</strong> 将代码转换为 AST。解析一般分为两个阶段词法分析和语法分析。</p><ul><li><strong>词法分析</strong>:对输入的字符序列做标记化(tokenization)操作。</li><li><strong>语法分析</strong>:处理标记与标记之间的关系,最终形成一颗完整的 AST 结构。</li></ul></li><li><p><strong>转换阶段</strong>Babel 使用 <strong>@babel/traverse</strong> 提供的方法对 AST 进行深度优先遍历,调用插件对关注节点的处理函数,按需对 AST 节点进行增删改操作。</p></li><li><p><strong>生成阶段</strong>Babel 默认使用 <strong>@babel/generator</strong> 将上一阶段处理后的 AST 转换为代码字符串。</p></li></ol><h3><a aria-hidden="true" tabindex="-1" class="anchor anchor__h3 anchorWithStickyNavbar_31ik" id="3-babel-插件系统"></a>3. Babel 插件系统<a class="hash-link" href="#3-babel-插件系统" title="Direct link to heading">#</a></h3><p>Babel 的核心模块 @babel/core@babel/parser@babel/traverse 和 @babel/generator 提供了完整的编译流程。而具体的转换逻辑需要插件来完成。</p><p>在使用 Babel 时,我们可通过配置文件指定 plugin 和 preset。而 preset 可以是 plugin 和 preset 以及其他配置的集合。Babel 会递归读取 preset最终获取一个大的 plugins 数组,用于后续使用。</p><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithStickyNavbar_31ik" id="常见-presets"></a>常见 presets<a class="hash-link" href="#常见-presets" title="Direct link to heading">#</a></h4><ul><li>@babel/preset-env</li><li>@babel/preset-typescript</li><li>@babel/preset-react</li><li>@babel/preset-flow</li></ul><p>最常见的 @babel/preset-env 预设,包含了<a href="https://github.com/babel/babel/blob/master/packages/babel-compat-data/data/plugins.json" target="_blank" rel="noopener noreferrer">一组</a>最新浏览器已支持的 ES 语法特性,并且可以通过配置目标运行环境范围,自动按需引入插件。</p><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithStickyNavbar_31ik" id="编写-babel-插件"></a>编写 Babel 插件<a class="hash-link" href="#编写-babel-插件" title="Direct link to heading">#</a></h4><p>Babel 插件的写法是借助<strong>访问者模式</strong>Visitor Pattern对关注的节点定义处理函数。参考一个简单 Babel 插件例子:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly js"><pre tabindex="0" class="prism-code language-js codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token plain">module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method-variable function-variable method function property-access" style="color:#d73a49">exports</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token keyword control-flow" style="color:#00009f">return</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">pre</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 在 visitor 下挂载各种感兴趣的节点类型的监听方法</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> visitor</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/**</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * 对 Identify 类型的节点进行处理</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * @param {NodePath} path</span></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> */</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function maybe-class-name" style="color:#d73a49">Identifier</span><span class="token punctuation" style="color:#393A34">(</span><span class="token parameter">path</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">node</span><span class="token punctuation" style="color:#393A34">.</span><span class="token property-access">name</span><span class="token punctuation" style="color:#393A34">.</span><span class="token method function property-access" style="color:#d73a49">toUpperCase</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token function" style="color:#d73a49">post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>使用该 Babel 插件的效果如下:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly js"><pre tabindex="0" class="prism-code language-js codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// input</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// index.js</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">hzfe</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// .babelrc</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token string" style="color:#e3116c">&quot;plugins&quot;</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">&quot;babel-plugin-yourpluginname&quot;</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly js"><pre tabindex="0" class="prism-code language-js codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// output</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token constant" style="color:#36acaa">HZFE</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><h4><a aria-hidden="true" tabindex="-1" class="anchor anchor__h4 anchorWithStickyNavbar_31ik" id="深入-babel-转换阶段"></a>深入 Babel 转换阶段<a class="hash-link" href="#深入-babel-转换阶段" title="Direct link to heading">#</a></h4><p>在转换阶段Babel 的相关方法会获得一个插件数组变量,用于后续的操作。插件结构可参考以下接口。</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly ts"><pre tabindex="0" class="prism-code language-ts codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name maybe-class-name">Plugin</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> key</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">undefined</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">null</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> post</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> pre</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> visitor</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Object</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> parserOverride</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> generatorOverride</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p><strong>转换阶段</strong>Babel 会按以下顺序执行。详细逻辑可查看<a href="https://github.com/babel/babel/blob/a647b9ea6bdd510f0d80b58dbea66828016ffe00/packages/babel-core/src/transformation/index.ts#L76" target="_blank" rel="noopener noreferrer">源码</a></p><ol><li>执行所有插件的 pre 方法。</li><li>按需执行 visitor 中的方法。</li><li>执行所有插件的 post 方法。</li></ol><p>一般来说,写 Babel 插件主要使用到的是 visitor 对象,这个 visitor 对象中会书写对于关注的 AST 节点的处理逻辑。而上面执行顺序中的第二步所指的 visitor 对象,是整合自各插件的 visitor最终形成一个大的 visitor 对象,大致的数据结构可参考以下接口:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly ts"><pre tabindex="0" class="prism-code language-ts codeBlock_23N8 thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 书写插件时的 visitor 结构</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name maybe-class-name">VisitorInPlugin</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token maybe-class-name">ASTNodeTypeName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token operator" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> enter</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> exit</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// babel 最终整合的 visitor 结构</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token class-name maybe-class-name">VisitorInTransform</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token maybe-class-name">ASTNodeTypeName</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 不同插件对相同节点的处理会合并为数组</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> enter</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> exit</span><span class="token operator" style="color:#393A34">?</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token known-class-name class-name">Function</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>在对 AST 进行<strong>深度优先遍历</strong>的过程中,会创建 TraversalContext 对象来把控对 NodePath 节点的访问,访问时调用对节点所定义的处理方法,从而实现按需执行 visitor 中的方法。详细实现请看 <a href="https://github.com/babel/babel/tree/bc1b9537b00499f462aa3ac0d49e30314a66f413/packages/babel-traverse" target="_blank" rel="noopener noreferrer">babel-traverse</a> 中的源码。</p><h2><a aria-hidden="true" tabindex="-1" class="anchor anchor__h2 anchorWithStickyNavbar_31ik" id="参考资料"></a>参考资料<a class="hash-link" href="#参考资料" title="Direct link to heading">#</a></h2><ol><li><a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" target="_blank" rel="noopener noreferrer">AST</a></li><li><a href="https://github.com/jamiebuilds/babel-handbook" target="_blank" rel="noopener noreferrer">Babel-handbook</a></li><li><a href="https://github.com/estree/estree" target="_blank" rel="noopener noreferrer">estree</a></li><li><a href="https://en.wikipedia.org/wiki/Visitor_pattern" target="_blank" rel="noopener noreferrer">访问者模式</a></li></ol></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/awesome-interview/book2/browser-garbage"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« 浏览器:垃圾回收机制</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/awesome-interview/book2/frame-react-fiber"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">框架React Fiber 的作用和原理 »</div></a></div></nav></div></div><div class="col col--3"><div class="tableOfContents_35-E thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#相关问题" class="table-of-contents__link">相关问题</a></li><li><a href="#回答关键点" class="table-of-contents__link">回答关键点</a></li><li><a href="#知识点深入" class="table-of-contents__link">知识点深入</a><ul><li><a href="#1-ast-抽象语法树" class="table-of-contents__link">1. AST 抽象语法树</a></li><li><a href="#2-babel-编译流程" class="table-of-contents__link">2. Babel 编译流程</a></li><li><a href="#3-babel-插件系统" class="table-of-contents__link">3. Babel 插件系统</a></li></ul></li><li><a href="#参考资料" class="table-of-contents__link">参考资料</a></li></ul></div></div></div><div class="row"><div class="col"><div class="react-utterences"><div>Loading script...</div></div></div><div class="col col--3"></div></div></div></main></div></div></div>
<script src="/awesome-interview/assets/js/runtime~main.21038279.js"></script>
<script src="/awesome-interview/assets/js/main.de89bd10.js"></script>
</body>
</html>