<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ESBuild & SWC淺談: 新一代構(gòu)建工具

          共 6960字,需瀏覽 14分鐘

           ·

          2022-05-14 01:13

          首先, ESBuild & swc是什么?

          • ESBuild[1]是基于Go語(yǔ)言開(kāi)發(fā)的JavaScript Bundler, 由Figma前CTO Evan Wallace開(kāi)發(fā), 并且也被Vite用于開(kāi)發(fā)環(huán)境的依賴解析和Transform.
          • SWC[2]則是基于Rust的JavaScript Compiler(其生態(tài)中也包含打包工具spack), 目前為Next.JS/Parcel/Deno等前端圈知名項(xiàng)目使用.

          為什么要關(guān)注這兩個(gè)工具?

          • 因?yàn)?..

            • 4261180370da44d33f46a44330259bbe.webp
          • 大家可能在日常工作中遇到過(guò), 項(xiàng)目的構(gòu)建時(shí)間隨著項(xiàng)目體積和復(fù)雜度逐漸遞增, 有的時(shí)候本地編輯一個(gè)項(xiàng)目要等上個(gè)大幾分鐘(此處@Webpack)

            • 630404b779c558f139a03cdfc3fd06a4.webp
          • 這個(gè)是ESBuild官網(wǎng)對(duì)于其打包10份three.js的速度對(duì)比

            • f9981571e9febd7899624f3b2670fc9e.webp
          • SWC則宣稱其比Babel快20倍(四核情況下可以快70倍)
          c3199500a2c89757b1dad537926db0a5.webp
          • 那么ESBuild & SWC是真的有這么快? 還是開(kāi)發(fā)者的自說(shuō)自話? 我們通過(guò)實(shí)驗(yàn)來(lái)檢驗(yàn)一下, 先看ESBuild

            • 用ESBuild打包一下
              #?編譯
              >?build-esb
              >?esbuild?./src/app.jsx?--bundle?--outfile=out_esb.js?--minify

              #?構(gòu)建產(chǎn)物的大小和構(gòu)建時(shí)間
              out_esb.js??27.4kb
              ??Done?in?13ms

              #?運(yùn)行產(chǎn)物
              node?out_esb.js?
              "">Hello,?world!
            • 用Webpack打包一下
              #?編譯
              >?build-wp
              >?webpack?--mode=production

              #?構(gòu)建產(chǎn)物
              asset?out_webpack.js?25.9?KiB?[compared?for?emit]?[minimized]?(name:?main)?1?related?asset
              modules?by?path?./node_modules/react/?8.5?KiB
              ??./node_modules/react/index.js?189?bytes?[built]?[code?generated]
              ??./node_modules/react/cjs/react.production.min.js?8.32?KiB?[built]?[code?generated]
              modules?by?path?./node_modules/react-dom/?28.2?KiB
              ??./node_modules/react-dom/server.browser.js?227?bytes?[built]?[code?generated]
              ??./node_modules/react-dom/cjs/react-dom-server.browser.production.min.js?28?KiB?[built]?[code?generated]
              ./src/app.jsx?254?bytes?[built]?[code?generated]
              ./node_modules/object-assign/index.js?2.17?KiB?[built]?[code?generated]

              #?構(gòu)建時(shí)間
              webpack?5.72.0?compiled?successfully?in?1680?ms

              npm?run?build-wp??2.79s?user?0.61s?system?84%?cpu?4.033?total

              #?運(yùn)行
              node?out_webpack.js??
              "">Hello,?world!
            • 讓我們先寫(xiě)一段非常簡(jiǎn)單的代碼

              import?*?as?React?from?'react'
              import?*?as?ReactServer?from?'react-dom/server'

              const?Greet?=?()?=>?

              Hello,?world!


              console.log(ReactServer.renderToString())
            • 然后我們來(lái)通過(guò)Webpack & ESBuild構(gòu)建它

          • 再來(lái)看看swc的編譯效率

            • 又是一段簡(jiǎn)單的ES6代碼
              //?一些變量聲明
              const?PI?=?3.1415;
              let?x?=?1;

              //?spread
              let?[foo,?[[bar],?baz]]?=?[1,?[[2],?3]];
              const?node?=?{
              ??loc:?{
              ????start:?{
              ??????line:?1,
              ??????column:?5
              ????}
              ??}
              };
              let?{?loc,?loc:?{?start?},?loc:?{?start:?{?line?}}?}?=?node;

              //?arrow?function
              var?sum?=?(num1,?num2)?=>?{?return?num1?+?num2;?}

              //?set
              const?s?=?new?Set();
              [2,?3,?5,?4,?5,?2,?2].forEach(x?=>?s.add(x));

              //?class
              class?Point?{
              ??constructor(x,?y)?{
              ????this.x?=?x;
              ????this.y?=?y;
              ??}

              ??toString()?{
              ????return?'('?+?this.x?+?',?'?+?this.y?+?')';
              ??}
              }
            • 先用Babel轉(zhuǎn)譯一下
              yarn?compile-babel
              yarn?run?v1.16.0
              warning?package.json:?No?license?field
              $?babel?src/es6.js?-o?es6_babel.js
              ???Done?in?2.38s.
            • 再用swc轉(zhuǎn)譯一下
              yarn?compile-swc??
              yarn?run?v1.16.0
              warning?package.json:?No?license?field
              $?swc?src/es6.js?-o?es6_swc.js
              Successfully?compiled?1?file?with?swc.
              ???Done?in?0.63s.
            • 兩者的產(chǎn)物對(duì)比
              //?es6_babel
              "use?strict";

              function?_classCallCheck(instance,?Constructor)?{?if?(!(instance?instanceof?Constructor))?{?throw?new?TypeError("Cannot?call?a?class?as?a?function");?}?}

              function?_defineProperties(target,?props)?{?for?(var?i?=?0;?i?false;?descriptor.configurable?=?true;?if?("value"?in?descriptor)?descriptor.writable?=?true;?Object.defineProperty(target,?descriptor.key,?descriptor);?}?}

              function?_createClass(Constructor,?protoProps,?staticProps)?{?if?(protoProps)?_defineProperties(Constructor.prototype,?protoProps);?if?(staticProps)?_defineProperties(Constructor,?staticProps);?Object.defineProperty(Constructor,?"prototype",?{?writable:?false?});?return?Constructor;?}

              var?PI?=?3.1415;
              var?x?=?1;
              var?foo?=?1,
              ????bar?=?2,
              ????baz?=?3;
              var?node?=?{
              ??loc:?{
              ????start:?{
              ??????line:?1,
              ??????column:?5
              ????}
              ??}
              };
              var?loc?=?node.loc,
              ????start?=?node.loc.start,
              ????line?=?node.loc.start.line;

              var?sum?=?function?sum(num1,?num2)?{
              ??return?num1?+?num2;
              };

              var?s?=?new?Set();
              [2,?3,?5,?4,?5,?2,?2].forEach(function?(x)?{
              ??return?s.add(x);
              });

              var?Point?=?/*#__PURE__*/function?()?{
              ??function?Point(x,?y)?{
              ????_classCallCheck(this,?Point);

              ????this.x?=?x;
              ????this.y?=?y;
              ??}

              ??_createClass(Point,?[{
              ????key:?"toString",
              ????value:?function?toString()?{
              ??????return?'('?+?this.x?+?',?'?+?this.y?+?')';
              ????}
              ??}]);

              ??return?Point;
              }();

              //?es6?swc
              function?_classCallCheck(instance,?Constructor)?{
              ????if?(!(instance?instanceof?Constructor))?{
              ????????throw?new?TypeError("Cannot?call?a?class?as?a?function");
              ????}
              }
              function?_defineProperties(target,?props)?{
              ????for(var?i?=?0;?i?????????var?descriptor?=?props[i];
              ????????descriptor.enumerable?=?descriptor.enumerable?||?false;
              ????????descriptor.configurable?=?true;
              ????????if?("value"?in?descriptor)?descriptor.writable?=?true;
              ????????Object.defineProperty(target,?descriptor.key,?descriptor);
              ????}
              }
              function?_createClass(Constructor,?protoProps,?staticProps)?{
              ????if?(protoProps)?_defineProperties(Constructor.prototype,?protoProps);
              ????if?(staticProps)?_defineProperties(Constructor,?staticProps);
              ????return?Constructor;
              }
              var?PI?=?3.1415;
              var?x?=?1;
              var?foo?=?1,?bar?=?2,?baz?=?3;
              var?node?=?{
              ????loc:?{
              ????????start:?{
              ????????????line:?1,
              ????????????column:?5
              ????????}
              ????}
              };
              var?loc?=?node.loc,?start?=?node.loc.start,?_loc?=?node.loc,?line?=?_loc.start.line;
              var?sum?=?function(num1,?num2)?{
              ????return?num1?+?num2;
              };
              var?s?=?new?Set();
              [
              ????2,
              ????3,
              ????5,
              ????4,
              ????5,
              ????2,
              ????2
              ].forEach(function(x1)?{
              ????return?s.add(x1);
              });
              var?Point?=?/*#__PURE__*/?function()?{
              ????"use?strict";
              ????function?Point(x2,?y)?{
              ????????_classCallCheck(this,?Point);
              ????????this.x?=?x2;
              ????????this.y?=?y;
              ????}
              ????_createClass(Point,?[
              ????????{
              ????????????key:?"toString",
              ????????????value:?function?toString()?{
              ????????????????return?"("?+?this.x?+?",?"?+?this.y?+?")";
              ????????????}
              ????????}
              ????]);
              ????return?Point;
              }();


              //#?sourceMappingURL=es6_swc.js.map
          • 從上面的數(shù)據(jù)可以看出

            • 在打包代碼的對(duì)比, ESBuild的速度(20ms)遠(yuǎn)快于Webpack(1680ms)
            • 在編譯代碼的對(duì)比, swc也對(duì)babel有比較明顯的性能優(yōu)勢(shì)(0.63s vs 2.38s).
            • 需要額外說(shuō)明的是, 用作實(shí)例的代碼非常簡(jiǎn)單, 并且在對(duì)比中也沒(méi)有充分使用各個(gè)構(gòu)建工具所有的構(gòu)建優(yōu)化策略, 只是對(duì)比最基礎(chǔ)的配置下幾種工具的速度, 這個(gè)和各個(gè)工具所羅列的benchmark數(shù)據(jù)會(huì)有差異, 并且構(gòu)建速度也和硬件性能/運(yùn)行時(shí)狀態(tài)有關(guān).
          • ESBuild/swc這么快? 那是不是可以直接把Webpack/Babel扔掉了? 也別急, 目前的ESBuild和Swc可能還不能完全替代Webpack. 但是通過(guò)這篇分享我們也許可以對(duì)它們有一個(gè)更全面的認(rèn)知, 也可以探索后邊在工作中使用這些新一代前端工具的機(jī)會(huì)

          ESBuild/swc在前端生態(tài)中的定位

          • 在當(dāng)今的前端世界里, 新工具層出不窮, 有的時(shí)候不同的工具太多以至于有段時(shí)間我完全分不清這些工具各自的功能是什么, 所以我們先來(lái)研究一下ESBuild/swc在當(dāng)今前端工程體系中的角色.
          ebdfb5252bf0bbdaaf7415ad032c6fc2.webp
          • 從上面的截圖中選擇幾個(gè)我們?nèi)粘=佑|最頻繁的前端工程化工具:

            • Loader: 因?yàn)榍岸隧?xiàng)目中包含各種文件類型和數(shù)據(jù), 需要將其進(jìn)行相應(yīng)的轉(zhuǎn)換變成JS模塊才能為打包工具使用并進(jìn)行構(gòu)建. JS的Compiler和其他類型文件的Loader可以統(tǒng)稱為Transfomer.
            • Plugin: 可以更一步定制化構(gòu)建流程, 對(duì)模塊進(jìn)行改造(比如壓縮JS的Terser)
            • 還有一些前端構(gòu)建工具是基于通用構(gòu)建工具進(jìn)行了一定封裝或者增加額外功能的, 比如CRA/Jupiter/Vite/Umi
            • Task Runner 任務(wù)運(yùn)行器: 開(kāi)發(fā)者設(shè)置腳本讓構(gòu)建工具完成開(kāi)發(fā)、構(gòu)建、部署中的一系列任務(wù), 大家日常常用的是npm/yarn的腳本功能; 在更早一些時(shí)候, 比較流行Gulp/Grunt這樣的工具

            • Package Manager 包管理器: 這個(gè)大家都不會(huì)陌生, npm/Yarn/pnmp幫開(kāi)發(fā)者下載并管理好依賴, 對(duì)于現(xiàn)在的前端開(kāi)發(fā)來(lái)說(shuō)必不可少.

            • Compiler/Transpiler 編譯器: 在市場(chǎng)上很多瀏覽器還只支持ES5語(yǔ)法的時(shí)候, Babel這樣的Comipler在前端開(kāi)發(fā)中必不可少; 如果你是用TypeScript的話, 也需要通過(guò)tsc或者ts-loader進(jìn)行編譯.

            • Bundler 打包工具: 從開(kāi)發(fā)者設(shè)置的入口出發(fā), 分析模塊依賴, 加載并將各類資源最終打包成1個(gè)或多個(gè)文件的工具.

          6372e1660085de2fcb9cc35001872040.webp
          • ESBuild的定位是Bundler, 但是它也是Compiler(有Transform代碼的能力)
          36ba5c076799d20addcb9317d4f31c55.webp
          • swc自稱其定位為Compiler + Bundler, 但是目前spack還不是很好用
          760a48416eae29011e03d994b7fbdfdf.webp

          ESBuild/SWC為何這么快?

          • 思考一下, Go & Rust這兩個(gè)語(yǔ)言和JavaScript相比有什么差異?

          ESBuild的實(shí)現(xiàn)(參考ESBuild FAQ[3])

          • 由Go實(shí)現(xiàn)并編譯成本地代碼: 多數(shù)Bundler都是由JavaScript實(shí)現(xiàn)的, 但是CLI應(yīng)用對(duì)于JIT編譯語(yǔ)言來(lái)說(shuō)是性能表現(xiàn)最不好的。每次運(yùn)行Bundler的時(shí)候, JS虛擬機(jī)都是以第一次運(yùn)行代碼的視角來(lái)解析Bundler(比如Webpack)的代碼, 沒(méi)有優(yōu)化信息. 當(dāng)ESBuild在解析JavaScript的時(shí)候, Node還在解析Bundler的JS代碼
          • 重度使用并行計(jì)算: Go語(yǔ)言本身的設(shè)計(jì)就很重視并行計(jì)算, 所以ESBuild對(duì)這一點(diǎn)會(huì)加以利用. 在構(gòu)建中主要有三個(gè)環(huán)節(jié): 解析(Parsing), 鏈接(Linking)和代碼生成(Code generation), 在解析和代碼生成環(huán)節(jié)會(huì)盡可能使用多核進(jìn)行并行計(jì)算
          • ESBuild 中的一切代碼從零實(shí)現(xiàn): 通過(guò)自行實(shí)現(xiàn)所有邏輯來(lái)避免第三方庫(kù)帶來(lái)的性能問(wèn)題, 統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)可以減少數(shù)據(jù)轉(zhuǎn)換開(kāi)銷, 并且可以根據(jù)需要改變架構(gòu), 當(dāng)然最大的缺點(diǎn)就是工作量倍增.

            • 令人想到了SpaceX這家公司, 大量零部件都是自己內(nèi)部生產(chǎn), 有效降低生產(chǎn)成本070a0ec982ff1b832a3ef5f949fe1a2c.webp
          • 對(duì)內(nèi)存的高效使用: ESBuild在實(shí)現(xiàn)時(shí)盡量減少數(shù)據(jù)的傳遞以及數(shù)據(jù)的轉(zhuǎn)換, ESBuild盡量減少了對(duì)整體AST的傳遞, 并且盡可能復(fù)用AST數(shù)據(jù), 其他的Bundler可能會(huì)在編譯的不同階段往復(fù)轉(zhuǎn)換數(shù)據(jù)格式(string -> TS -> JS -> older JS -> string...). 在內(nèi)存存儲(chǔ)效率方面Go也比JavaScript更高效.

          swc的實(shí)現(xiàn)

          • swc的官方文檔和網(wǎng)站并沒(méi)有對(duì)swc內(nèi)部實(shí)現(xiàn)的較為具體的解釋, 根據(jù)其博客[4]中的一些分析, babel緩慢的主要原因還是來(lái)自于其單線程的特性

          一點(diǎn)總結(jié)

          • 從ESBuild和swc的官方資源中, 共同提到的一點(diǎn)就是利用好并行計(jì)算。JS因?yàn)樵谠O(shè)計(jì)之初的目標(biāo)就是服務(wù)好瀏覽器場(chǎng)景, 所以單線程 & 事件驅(qū)動(dòng)并不適合用來(lái)進(jìn)行CPU密集的計(jì)算, 而ESBuild/Rust也正是在這一點(diǎn)上對(duì)基于Node的構(gòu)建工具擁有系統(tǒng)性的速度優(yōu)勢(shì)。

          如何用ESBuild/swc提效?

          • 現(xiàn)在我們知道ESBuild/Rust是做什么的, 并且有什么特點(diǎn), 我們可以在工作中如何利用ESBuild/swc去改善我們的開(kāi)發(fā)體驗(yàn)?zāi)?

          使用ESBuild

          • ESBuild在API層面上非常簡(jiǎn)潔, 主要的API只有兩個(gè): Transform和Build, 這兩個(gè)API可以通過(guò)CLI, JavaScript, Go的方式調(diào)用

            • Transform主要用于對(duì)源代碼的轉(zhuǎn)換, 接受的輸入是字符串, 輸出的是轉(zhuǎn)換后的代碼
              #?用CLI方式調(diào)用,?將ts代碼轉(zhuǎn)化為js代碼
              echo?'let?x:?number?=?1'?|?esbuild?--loader=ts?=>?let?x?=?1;
            • Build主要用于構(gòu)建, 接受的輸入是一個(gè)或多個(gè)文件
              //?用JS模式調(diào)用build方法
              require('esbuild').buildSync({
              ??entryPoints:?['in.js'],
              ??bundle:?true,
              ??outfile:?'out.js',
              })
          • ESBuild的內(nèi)容類型(Content Type)包括了ES在打包時(shí)可以解析的文件類型, 這一點(diǎn)和Webpack的loader概念類似, 下面的例子是在打包時(shí)用JSX Loader解析JS文件.
          require('esbuild').buildSync({
          ??entryPoints:?['app.js'],
          ??bundle:?true,
          ??loader:?{?'.js':?'jsx'?},
          ??outfile:?'out.js',
          })
          • ESBuild也包含插件系統(tǒng), 可以在構(gòu)建過(guò)程中(Transform API無(wú)法使用插件)通過(guò)插件更改你的構(gòu)建流程
          //?來(lái)自于官網(wǎng)的插件示范
          let?envPlugin?=?{
          ??name:?'env',
          ??setup(build)?{
          ????//?Intercept?import?paths?called?"env"?so?esbuild?doesn't?attempt
          ????//?to?map?them?to?a?file?system?location.?Tag?them?with?the?"env-ns"
          ????//?namespace?to?reserve?them?for?this?plugin.
          ????build.onResolve({?filter:?/^env$/?},?args?=>?({
          ??????path:?args.path,
          ??????namespace:?'
          env-ns',
          ????}))

          ????//?Load?paths?tagged?with?the?"env-ns"?namespace?and?behave?as?if
          ????//?they?point?to?a?JSON?file?containing?the?environment?variables.
          ????build.onLoad({?filter:?/.*/,?namespace:?'
          env-ns'?},?()?=>?({
          ??????contents:?JSON.stringify(process.env),
          ??????loader:?'
          json',
          ????}))
          ??},
          }

          //?使用插件
          require('
          esbuild').build({
          ??entryPoints:?['
          app.js'],
          ??bundle:?true,
          ??outfile:?'
          out.js',
          ??plugins:?[envPlugin],
          }).catch(()?=>?process.exit(1))
          • 在其他工具中使用ESBuild

            • 如果你覺(jué)得目前完全使用ESBuild還不成熟, 也可以在Webpack體系中使用ESBuild的loader來(lái)替代babel用于進(jìn)行代碼轉(zhuǎn)換, 除此之外, esbuild-loader[5]還可以用于JS & CSS的代碼最小化.
              const?{?ESBuildMinifyPlugin?}?=?require('esbuild-loader')

              module.exports?=?{
              ????rules:?[
              ??????{
              ????????test:?/.js$/,
              ????????//?使用esbuild作為js/ts/jsx/tsx?loader
              ????????loader:?'esbuild-loader',
              ????????options:?{
              ??????????loader:?'jsx',??
              ??????????target:?'es2015'
              ????????}
              ??????},
              ????],
              ????//?或者使用esbuild-loader作為JS壓縮工具
              ????optimization:?{
              ??????minimizer:?[
              ????????new?ESBuildMinifyPlugin({
              ??????????target:?'es2015'
              ????????})
              ??????]
              ????}
              }
          • 注意點(diǎn)

            • ESBuild不能轉(zhuǎn)ES5代碼和一些其他語(yǔ)法, 詳情可參考https://esbuild.github.io/content-types/#javascript-caveats

          使用Vite

          • 要說(shuō)2021年前端圈關(guān)注度較高的新工具, Vite可以說(shuō)是名列前茅, 那么Vite和ESBuild/swc有什么關(guān)系呢?
          06f685b176bd1b88749f891d2aae85cf.webp
          • Vite的核心理念是使用ESM+編譯語(yǔ)言工具(ESBuild)加快本地運(yùn)行
          dcb84105cd1f91ce4ef6626de812179d.webp
          • Vite在開(kāi)發(fā)環(huán)境使用了ESBuild進(jìn)行預(yù)構(gòu)建, 在生產(chǎn)環(huán)境使用了Rollup打包, 后續(xù)也有可能使用ESBuild進(jìn)行生產(chǎn)環(huán)境的構(gòu)建.
          a1eaad5aaa4b9be59cad8586e825f481.webp
          • 支持ES5需要引入插件 https://github.com/vitejs/vite/tree/main/packages/plugin-legacy

          使用swc

          • Comilation

            • Transform: 代碼轉(zhuǎn)換API, 輸入源代碼 => 輸出轉(zhuǎn)換后的代碼
            • Parse: 對(duì)源代碼進(jìn)行解析, 輸出AST
            • Minify: 對(duì)代碼進(jìn)行最小化
            • 可以使用swc命令行工具(swc/cli)配合配置文件[6]對(duì)文件進(jìn)行編譯

              #?Transpile?one?file?and?emit?to?stdout
              npx?swc?./file.js

              #?Transpile?one?file?and?emit?to?`output.js`
              npx?swc?./file.js?-o?output.js

              #?Transpile?and?write?to?/output?dir
              npx?swc?./my-dir?-d?output
            • swc的核心部分swc/core主要有三種API

            • swc也推出了swc/wasm模塊, 可以讓用戶在瀏覽器環(huán)境使用wasm進(jìn)行代碼轉(zhuǎn)換

            • 如果你想在Webpack體系下使用swc(替代babel), 也可以使用swc-loader

              14466bef576ad1b45110f179325725f1.webp
          • Bundle

            • ??swc也支持進(jìn)行打包功能, 但是目前功能還不很完備, 并且在使用中也有不少Bug. 筆者目前在本地嘗試用spack打包一個(gè)簡(jiǎn)單的React應(yīng)用目前還不成功, 還做不到開(kāi)箱即用
            • 5c77ae9ed638a1d45b7f1d51a9a8feb6.webp
            • 目前swc的Bundle工具叫spack, 后續(xù)會(huì)改名為swcpack.
            • 打包可以通過(guò)spack.config.js[7]文件進(jìn)行配置

          一點(diǎn)點(diǎn)總結(jié)和思考

          全文總結(jié)

          • ESBuild/swc是用編譯型語(yǔ)言編寫(xiě)的新一代前端工具, 對(duì)JS編寫(xiě)的構(gòu)建工具有系統(tǒng)級(jí)的速度優(yōu)勢(shì)
          • ESBuild可以用于編譯JS代碼和模塊打包, swc號(hào)稱也都可以支持兩者但是其打包工具還處于早期開(kāi)發(fā)階段
          • 目前這兩個(gè)工具還不能完全替代Webpack等主流工具這些年發(fā)展出的龐大生態(tài)
          • 當(dāng)已有的基礎(chǔ)設(shè)施穩(wěn)定并且替換成本較大時(shí), 可以嘗試漸進(jìn)式的利用新工具(loader)或者Vite這種基于ESBuild二次封裝的構(gòu)建工具

          延伸思考

          • 持續(xù)關(guān)注前端生態(tài)新發(fā)展, 利用好開(kāi)源社區(qū)提升研發(fā)效率和體驗(yàn)的新工具.
          • 在使用新工具的同時(shí), 了解或參與到其背后的技術(shù)原理, Go可以作為服務(wù)端語(yǔ)言, Rust可以作為系統(tǒng)編程語(yǔ)言, 學(xué)習(xí)新語(yǔ)言能打開(kāi)新天地, 豈不美哉?

          ??感謝收看??

          dfe36edc71c2f2733e9d599052ba24e9.webp

          參考資料

          • ESBuild https://esbuild.github.io/
          • SWC https://swc.rs/
          • Vite https://cn.vitejs.dev/
          • https://blog.logrocket.com/using-spack-bundler-in-rust-to-speed-up-builds/
          • https://datastation.multiprocess.io/blog/2021-11-13-benchmarking-esbuild-swc-typescript-babel.html
          • https://blog.logrocket.com/webpack-or-esbuild-why-not-both/

          參考資料

          [1]

          ESBuild: https://esbuild.github.io/

          [2]

          SWC: https://swc.rs/

          [3]

          FAQ: https://esbuild.github.io/faq/

          [4]

          博客: https://swc.rs/blog/perf-swc-vs-babel

          [5]

          esbuild-loader: https://github.com/privatenumber/esbuild-loader

          [6]

          配置文件: https://swc.rs/docs/configuration/swcrc

          [7]

          spack.config.js: https://swc.rs/docs/configuration/bundling


          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美xxx亚洲 | 欧美一级A片免费 | 伊人天天操| 国产高清黄色电影 | 国产一区二区三区18 |