JavaScript 新一代構(gòu)建工具對(duì)比

本文譯自:https://css-tricks.com/comparing-the-new-generation-of-build-tools/
在過(guò)去的一年里,出現(xiàn)了一批新的開(kāi)發(fā)者工具,它們正在緊跟過(guò)去幾年主導(dǎo)前端開(kāi)發(fā)的工具,包括 webpack、Babel、Rollup、Parcel、create-react-app。
這些新的工具并不是為了完成完全相同的功能而設(shè)計(jì)的,每個(gè)工具都有不同的目標(biāo)和功能。盡管存在差異,但這些工具有一個(gè)共同的目標(biāo):改善開(kāi)發(fā)者體驗(yàn)。
概覽
esbuildSnowpackVitewmrFeature comparisonWrapping up
具體來(lái)說(shuō),我想對(duì)每一個(gè)進(jìn)行評(píng)估,概述它們的作用,為什么我們需要它們,以及它們的使用案例。比較并不總是公平的,我們?cè)谶@篇文章中看到的東西也不是直接的競(jìng)爭(zhēng)對(duì)手。事實(shí)上,Snowpack 和 Vite 在某些任務(wù)中都使用了 esbuild。我們的目標(biāo)更多的是為了更好地了解運(yùn)行任務(wù)的開(kāi)發(fā)者工具的格局,讓我們的工作更輕松。通過(guò)這種方式,我們就能看到有哪些選擇,以及它們是如何配合的,這樣我們就能在需要的時(shí)候做出最好的選擇。
當(dāng)然,我分析的所有的這些都會(huì)受到我使用 React 和 Preact 的經(jīng)驗(yàn)的影響。我對(duì)這些框架庫(kù)比較熟悉,但我也會(huì)關(guān)注它們對(duì)其他前端框架的支持。
為啥這些工具現(xiàn)在都出現(xiàn)了?
在某種程度上,我認(rèn)為這些工具的到來(lái)是對(duì) JavaScript 工具疲勞的一種反應(yīng)。

Snowpack、Vite 和 wmr 都用到了瀏覽器中的原生 JavaScript 模塊。早在 2018 年,Firefox 60 發(fā)布時(shí)默認(rèn)啟用了 ECMAScript 2015 的 Module 。此后,各大瀏覽器引擎都支持原生 JavaScript 模塊。Node.js 也在2019年11月推出了原生 JavaScript 模塊。在2021年的今天,我們還在尋找原生 JavaScript 模塊能夠帶來(lái)哪些新的可能性。
這些工具和現(xiàn)有的工具有什么不同?
無(wú)論我們?cè)陂_(kāi)發(fā)服務(wù)器上使用 webpack、Rollup 還是 Parcel,工具都會(huì)從我們的源代碼和 node_modules 文件夾中把我們的整個(gè)代碼庫(kù)打包在一起,通過(guò)構(gòu)建過(guò)程運(yùn)行這些代碼,比如 Babel、TypeScript 或 PostCSS,然后將打包的代碼推送到我們的瀏覽器上。這一切都需要花費(fèi)大量的工作,并且會(huì)使開(kāi)發(fā)服務(wù)器在更大的代碼庫(kù)中慢慢爬行,甚至在所有的工作都用于緩存和優(yōu)化之后也是如此。
Snowpack、Vite 和 wmr 開(kāi)發(fā)服務(wù)器則不采用這種模式。相反,它們會(huì)等到瀏覽器找到一個(gè) import 語(yǔ)句,并為模塊發(fā)出 HTTP 請(qǐng)求。只有在這個(gè)請(qǐng)求發(fā)出后,該工具才會(huì)對(duì)請(qǐng)求的模塊和模塊導(dǎo)入樹(shù)中的任何葉節(jié)點(diǎn)應(yīng)用轉(zhuǎn)換,然后將這些轉(zhuǎn)換提供給瀏覽器。這大大加快了速度,因?yàn)樵谕扑偷介_(kāi)發(fā)服務(wù)器的過(guò)程中減少了工作。
你會(huì)注意到描述中缺少了 esbuild 。它首先是一個(gè) bundler 程序。它并不像其他工具那樣繞開(kāi) bundler。相反,esbuild 通過(guò)避免昂貴的轉(zhuǎn)換、利用并行化和使用Go語(yǔ)言來(lái)快速處理代碼。

實(shí)驗(yàn)
我從 React 文檔中選取了一個(gè)示例應(yīng)用,并使用文中所提到的每個(gè)工具重新構(gòu)建了它。我選擇的項(xiàng)目是 Yogita Verma 的 Snap Shot。這里有一個(gè)原始 repo 的鏈接,還有一個(gè)我的repo鏈接,里面有四個(gè)版本的 Snap Shot,每個(gè)版本都使用不同的構(gòu)建工具。我們稍后會(huì)比較每個(gè)構(gòu)建步驟的輸出。重新構(gòu)建這個(gè)應(yīng)用程序,讓我可以測(cè)試開(kāi)發(fā)人員將一些相當(dāng)標(biāo)準(zhǔn)的 React 依賴(lài)項(xiàng)添加到工具(包括 React Router 和 axios)中的體驗(yàn)。
原始 repo:https://github.com/Yog9/SnapShot Demo:https://github.com/Elliotclyde/build-tool-test
可以比較的功能
在我們深入了解每個(gè)工具的具體內(nèi)容之前,它們都支持以下功能(在不同程度上)。
對(duì)原生 JavaScript模塊的一流支持TypeScript編譯(但不進(jìn)行類(lèi)型檢查)JSX用于擴(kuò)展性的插件 API內(nèi)置開(kāi)發(fā)服務(wù)器 CSS bundling和對(duì)CSS-in-JS的支持。
所有這些工具都可以將 TypeScript 編譯成 JavaScript,但即使有類(lèi)型錯(cuò)誤也會(huì)這樣做。為了進(jìn)行正確的類(lèi)型檢查,你需要安裝T ypeScript,并在你的 JavaScript 根文件上運(yùn)行 tsc --noEmit ,或者使用編輯器插件來(lái)觀察類(lèi)型錯(cuò)誤。
好了,下面我們來(lái)具體看看每個(gè)工具。
esbuild

esbuild 是由 Evan Wallace(Figma的CTO)創(chuàng)建的。它的主要特點(diǎn)是,它提供的構(gòu)建步驟比基于 Node 的打包器快 10×-100×(根據(jù)他們自己的基準(zhǔn))。它沒(méi)有提供許多你可能會(huì)在 create-react-app 這樣的工具中找到的開(kāi)發(fā)者便利。但是有越來(lái)越多的 esbuild starter 啟動(dòng)器出現(xiàn)來(lái)填補(bǔ)這些空白,包括 create-react-app-esbuild,estrella 和 Snowpack,它們的構(gòu)建步驟使用 esbuild。
esbuild 是非常新的。它還沒(méi)有達(dá)到 1.0 版本,還沒(méi)有完全準(zhǔn)備好用于生產(chǎn)使用 — 但它已經(jīng)不遠(yuǎn)了。它為你提供了直觀的 JavaScript 和帶有智能默認(rèn)值的命令行 API。
用例
esbuild 完全改變了 bundler 的游戲規(guī)則。它將在大型代碼庫(kù)中發(fā)揮最大的作用,因?yàn)?esbuild 和 node 打包器之間的速度差異會(huì)成倍增加。當(dāng) esbuild 達(dá)到 1.0 的時(shí)候,它在大型生產(chǎn)站點(diǎn)中會(huì)非常有用,將為團(tuán)隊(duì)節(jié)省大量等待構(gòu)建完成的時(shí)間。不幸的是,大型生產(chǎn)站點(diǎn)必須要等到 esbuild 變得穩(wěn)定。在此期間,它只是很好地增加了一些速度,讓你在項(xiàng)目中的 bundling 變得更快。
esbuild 快如閃電的速度對(duì)于你正在做的任何工作來(lái)說(shuō)都是一種獎(jiǎng)勵(lì)。減少等待構(gòu)建運(yùn)行的時(shí)間,對(duì)開(kāi)發(fā)者的體驗(yàn)總是有好處的! 考慮到這一點(diǎn),如果你是在做快速應(yīng)用的原型,你可能會(huì)想要從比 esbuild 更高級(jí)的東西開(kāi)始--否則,在獲得我們期望的 JavaScript 中的便利之前,你需要花一些時(shí)間引入依賴(lài)項(xiàng)并配置你的環(huán)境生態(tài)系統(tǒng)。另外,如果你想盡可能地減小 bundle 包的大小,你可能會(huì)想使用 Rollup 和 terser ,它們會(huì)產(chǎn)生略小的 bundle 大小。
設(shè)置
我決定以一種幼稚的方式在 esbuild 中啟動(dòng)一個(gè) React 項(xiàng)目:npm安裝 esbuild、React 和 ReactDOM。我創(chuàng)建了一個(gè) src/code秘密花園.jsx 文件和一個(gè) dist/index.html 文件。然后,我使用下面的命令將app編譯成一個(gè) dist/bundle.js 文件。
./node_modules/.bin/esbuild?src/code秘密花園.jsx?--bundle?--platform=browser?--outfile=dist/bundle.js
當(dāng)我在瀏覽器中打開(kāi) index.html 時(shí),我遇到了 "白屏 "和 "Uncaught ReferenceError: process is not defined " 的控制臺(tái)錯(cuò)誤。文檔和CLI都準(zhǔn)確地解釋了你需要做什么來(lái)避免這種情況,但對(duì)于初學(xué)者來(lái)說(shuō),這可能有點(diǎn) "捉襟見(jiàn)肘",因?yàn)樵?bundling React 時(shí),它需要一個(gè)額外的參數(shù)。
--define:process.env.NODE_ENV=\"production\"
或者,如果你在 npm 腳本中包含了 esbuild ,就像這樣寫(xiě)來(lái)轉(zhuǎn)義引號(hào)。
--define:process.env.NODE_ENV=\\\"production\\\"
任何綁定到瀏覽器的需要 node 環(huán)境變量的庫(kù)都需要這個(gè) define 參數(shù)。Vue 2.0 也需要這些參數(shù)。你在使用 Preact 時(shí)不會(huì)有同樣的問(wèn)題,因?yàn)樗恍枰魏苇h(huán)境變量,而且默認(rèn)情況下已經(jīng)為瀏覽器準(zhǔn)備好了。
在運(yùn)行了帶有定義參數(shù)的命令后,我的 "Hello world ConardLi " React 應(yīng)用完美地運(yùn)行了。JSX 可以使用 .jsx 文件開(kāi)箱即用。也就是說(shuō),React 需要手動(dòng)導(dǎo)入,然后將JSX轉(zhuǎn)換為 React.createElement。然而,有一些方法可以在 JSX 中添加自動(dòng)導(dǎo)入,或?yàn)?Preact 配置JSX。
用法
esbuild 為開(kāi)發(fā)服務(wù)器提供了一個(gè) -serve 的選項(xiàng)。它繞過(guò)了文件系統(tǒng),直接從內(nèi)存中為模塊提供服務(wù),確保瀏覽器不會(huì)提取舊版本的模塊。然而,它不包括實(shí)時(shí)/熱重載,所以你會(huì)發(fā)現(xiàn)自己在保存后要刷新瀏覽器,這不是一個(gè)良好的體驗(yàn)。
我決定使用新發(fā)布的 watch 功能.這告訴 esbuild 在每次保存源文件時(shí)重新編譯代碼。但是我們?nèi)匀恍枰粋€(gè)服務(wù)器來(lái)查看我們保存的變化。我們可以拉入一個(gè)開(kāi)發(fā)服務(wù)器包,比如 Luke Jackson 的 servor。
npm?install?servor?--save-dev
然后我們就可以使用 esbuild 的 Javascript API 作為服務(wù)器啟動(dòng),同時(shí)運(yùn)行 esbuild 的 watch 模式。讓我們?cè)陧?xiàng)目的根目錄創(chuàng)建一個(gè)名為 watch.js 的文件。
//?watch.js
const?esbuild?=?require("esbuild");
const?servor?=?require("servor");
esbuild.build({
??//?pass?any?options?to?esbuild?here...
??entryPoints:?["src/app.jsx"],
??outdir:?"dist",
??define:?{?"process.env.NODE_ENV":?'"production"'?},
??watch:?true,
});
async?function?serve(){
??console.log("running?server?from:?http://localhost:8080/");
??await?servor({
????//?pass?any?options?to?servor?here...
????browser:true,
????root:?"dist",
????port:?8080,
??});
}
serve();
現(xiàn)在在命令行中運(yùn)行 node watch.js 。這為我們提供了一個(gè)很好的開(kāi)發(fā)服務(wù)器,但是同樣,它也不能給我們提供熱更新或者快速刷新(也就是說(shuō),你的客戶(hù)端狀態(tài)不會(huì)被保存)。但這已經(jīng)足夠滿(mǎn)足我的測(cè)試需求了。
即使我們每次保存文件時(shí)都要對(duì)整個(gè)應(yīng)用程序進(jìn)行重新編譯,但在 esbuild 變慢之前,我們需要有一個(gè)相當(dāng)龐大的應(yīng)用程序。在我設(shè)置了這個(gè)工具之后,我從更改中得到了即時(shí)的反饋。我的電腦使用的是2012年的英特爾i7,所以它肯定不是一臺(tái)頂級(jí)的機(jī)器。
如果你需要一個(gè)帶有實(shí)時(shí)重載和一些 React 默認(rèn)值的預(yù)配置 esbuild 版本,你可以克隆這個(gè) repo。
https://github.com/Elliotclyde/esbuild-react-starter
支持的文件
如果這是你的風(fēng)格,esbuild 可以在 JavaScript 中導(dǎo)入 CSS 。它將會(huì)把CSS編譯成一個(gè)輸出文件,名字和你的主輸出 JavaScript 文件一樣。它還可以默認(rèn)打包 CSS @import 語(yǔ)句。目前還沒(méi)有對(duì)CSS模塊的支持,但有計(jì)劃。
用于 esbuild 的插件社區(qū)正在不斷壯大。例如,Vue單文件組件和 Svelte 組件都有可用的插件。
esbuild 可以使用 JSON 文件,并且可以將它們 bundle 到 JavaScript 模塊中,無(wú)需任何配置。
它還可以用 JavaScript 導(dǎo)入圖片,可以選擇將圖片轉(zhuǎn)換為數(shù)據(jù)URL或復(fù)制到輸出文件夾中。這種行為在默認(rèn)情況下并沒(méi)有啟用,但你可以在你的 esbuild 配置對(duì)象中添加以下內(nèi)容來(lái)啟用這兩個(gè)選項(xiàng)。
loader:?{?'.png':?'dataurl'?}?//?Converts?to?data?url?in?JS?bundle
loader:?{?'.png':?'file'?}?//?Copies?to?output?folder
代碼拆分似乎是一項(xiàng)正在進(jìn)行中的工作,但大多數(shù)情況下是以ESM輸出格式進(jìn)行的,而且看起來(lái)確實(shí)是項(xiàng)目的優(yōu)先級(jí)。另外值得一提的是,tree-shaking 是 esbuild 默認(rèn)內(nèi)置的,無(wú)法關(guān)閉。
生產(chǎn)構(gòu)建
在 esbuild 命令中使用 "minify "和 "bundle " 選項(xiàng)不會(huì)創(chuàng)建一個(gè)像 Rollup/Terser 流水線(xiàn)一樣小的 bundle 。這是因?yàn)?esbuild 犧牲了一些bundle大小的優(yōu)化來(lái)盡可能少的通過(guò)你的代碼。然而,根據(jù)你的項(xiàng)目,這種差異可能是微不足道的,但對(duì)于bundle速度的提高來(lái)說(shuō)是值得的。在我的 Snap Shot 應(yīng)用程序的克隆中,esbuild 創(chuàng)建了一個(gè)177KB的包,這比使用 rollup 和 terser 的 Vite 產(chǎn)生的165KB多不了多少。
總結(jié)

esbuild是一個(gè)非常強(qiáng)大的工具。但如果你習(xí)慣于零配置的設(shè)置,那可能會(huì)很困難。如果你需要更多,那么你可能想看看下一個(gè)工具,基于esbuild的Snowpack。
Snowpack

Snowpack 是由 Skypack 和 Pika 的創(chuàng)造者開(kāi)發(fā)的一款構(gòu)建工具。它提供了一個(gè)很棒的開(kāi)發(fā)服務(wù)器,并且是以 "非打包式開(kāi)發(fā) "的理念創(chuàng)建的。
引用文檔中的一句話(huà) "你應(yīng)該能夠使用一個(gè)打包程序,因?yàn)槟阆胍皇且驗(yàn)槟阈枰?
默認(rèn)情況下, Snowpack 的構(gòu)建步驟并沒(méi)有將文件打包到一個(gè)單一的包中,而是提供了在瀏覽器中運(yùn)行的非打包esmodules。實(shí)際上 esbuild 是作為一個(gè)依賴(lài)關(guān)系包含在其中的,但我們的想法是使用 JavaScript 模塊,只有在需要時(shí)才與 esbuild 打包。
Snowpack 有一些非常精巧的文檔,包括一個(gè)與J avaScript 框架一起使用的指南列表,以及一堆模板。有些指南還在不斷完善中,但其他的指南,比如針對(duì) React 的指南,就很不錯(cuò),很清晰。看起來(lái) Snowpack 也把 Svelte 當(dāng)做一等公民來(lái)對(duì)待。實(shí)際上,我第一次聽(tīng)說(shuō) Snowpack 是在2020年Svelte峰會(huì)上 Rich Harris 的 "未來(lái)主義Web開(kāi)發(fā) "演講中。也就是說(shuō),即將推出的 Svelte 元框架 SvelteKit 本來(lái)應(yīng)該由 Snowpack 提供支持,但后來(lái)改用了 Vite(我們接下來(lái)會(huì)對(duì)其進(jìn)行評(píng)測(cè))。
使用案例
如果你想在非打包部署上加倍努力,Snowpack 是個(gè)不錯(cuò)的選擇。你可能會(huì)用少量的模塊來(lái)編寫(xiě)源代碼,這就意味著你不會(huì)用非捆綁構(gòu)建來(lái)創(chuàng)建一個(gè)大的請(qǐng)求瀑布。如果你不需要額外的復(fù)雜性和技術(shù)債務(wù),那么 Snowpack 是一個(gè)很好的選擇。一個(gè)很好的用例是,如果你正在增量地將前端框架采用到服務(wù)器渲染或靜態(tài)的應(yīng)用程序中。你可以從node生態(tài)系統(tǒng)中獲得盡可能少的工具,但你仍然會(huì)得到聲明式前端框架的好處。
其次,我認(rèn)為 Snowpack 是 esbuild 的一個(gè)很好的封裝器。如果你想嘗試 esbuild,但同時(shí)又想擁有一個(gè)開(kāi)發(fā)服務(wù)器和預(yù)先編寫(xiě)的前端框架模板,那么選擇 Snowpack 是不會(huì)錯(cuò)的。在 Snowpack 配置的構(gòu)建步驟中啟用 esbuild,你就可以了。
就目前的情況來(lái)看,我認(rèn)為 Snowpack 不會(huì)是像 create-react-app 這樣的零配置工具的最佳替代品,因?yàn)槿绻阌幸粋€(gè)大的應(yīng)用,需要一個(gè)超級(jí)花哨的優(yōu)化生產(chǎn)就緒的構(gòu)建步驟,你就需要自己導(dǎo)入插件并配置它們。
設(shè)置
讓我們通過(guò)命令行來(lái)啟動(dòng)Snowpack的項(xiàng)目。
mkdir?snowpackproject
cd?snowpackproject
npm?init?#fill?with?defaults?
npm?install?snowpack
現(xiàn)在,讓我們?cè)趐ackage.json中添加以下內(nèi)容。
//?package.json
"scripts":?{
??"start":?"snowpack?dev",
??"build":?"snowpack?build"
},
接下來(lái),我們將創(chuàng)建一個(gè)配置文件。
//?Mac?or?Linux
touch?snowpack.config.js
//?Windows
new-item?snowpack.config.js
我認(rèn)為 Snowpack 最神奇的地方在于在配置文件中設(shè)置一個(gè)看似無(wú)害的鍵值對(duì)。例如,把這個(gè)粘貼到配置文件中。
//?snowpack.config.js
module.exports?=?{
??packageOptions:?{
????"source":?"remote",
??}
};
source: remote 啟用了一種叫做流式導(dǎo)入的東西。通過(guò)流式導(dǎo)入使 Snowpack 能夠繞過(guò)npm安裝,將裸導(dǎo)入(例如,從import React from‘ React’)轉(zhuǎn)換為 Skypack 的CDN導(dǎo)入。
繼續(xù)前進(jìn),讓我們創(chuàng)建一個(gè) index.html 文件。
html>
<html?lang="en">
<head>
??<meta?charset="UTF-8">>
??<title>Snowpack?streaming?importstitle>
head>
<body>
??<div?id="root">div>
??
??<script?type="module"?src="app.js">script>
body>
html>
最后,我們將添加一個(gè) code秘密花園.jsx 文件。
//?code秘密花園.jsx?
import?React?from?'react'
import?ReactDOM?from?'react-dom'
const?App?=?()=>{
??return?<h1>Welcome?to?Snowpack?streaming?imports!h1>
}
ReactDOM.render(<App?/>,document.getElementById('root'));?0
注意,我們?cè)谌魏坞A段都沒(méi)有安裝 React 或 ReactDOM 的npm。但如果我們像這樣啟動(dòng) Snowpack 開(kāi)發(fā)者服務(wù)器。
./node_modules/.bin/snowpack?dev
我們的應(yīng)用程序還能用。
Snowpack 不是從 nodemodules 文件夾中提取,而是從 Skypack 中提取npm包,Skypack ?是一個(gè)托管 npm 注冊(cè)表的CDN,它是預(yù)先優(yōu)化的,可以在瀏覽器中工作。然后,Snowpack 將它放在一個(gè) ./snowpack/pkg URL中。
用法
這離基于 Node/npm 的工作流還有很大的差距。我們實(shí)際上看到的是一個(gè)新的基于 CDN/JavaScript 模塊的工作流。
然而,如果我們的應(yīng)用按原樣運(yùn)行生產(chǎn)構(gòu)建,Snowpack 會(huì)拋出一個(gè)錯(cuò)誤。這是因?yàn)樗枰涝跇?gòu)建時(shí)要使用哪個(gè)版本的 React 和 ReactDOM 。你可以通過(guò)一個(gè) snowpack.deps.json 來(lái)解決這個(gè)問(wèn)題,它可以通過(guò)運(yùn)行下面的程序自動(dòng)創(chuàng)建。
./node_modules/.bin/snowpack?add?react
./node_modules/.bin/snowpack?add?react-dom
這不會(huì)從 npm 下載包,但它會(huì)記錄用于 Snowpack 構(gòu)建所使用包的版本。
一個(gè)需要注意的是,我們會(huì)錯(cuò)過(guò)開(kāi)發(fā)者的錯(cuò)誤信息,因?yàn)?Skypack 會(huì)發(fā)布生產(chǎn)版本的包。
即使我們沒(méi)有使用流式導(dǎo)入,Snowpack 開(kāi)發(fā)服務(wù)器也會(huì)將 node_modules 中的每個(gè)依賴(lài)關(guān)系打包成一個(gè) JavaScript 文件,將這些文件轉(zhuǎn)換為本地 JavaScript 模塊,然后將其提供給瀏覽器。這意味著瀏覽器可以緩存這些腳本,只有在它們發(fā)生變化時(shí)才會(huì)重新請(qǐng)求它們。開(kāi)發(fā)服務(wù)器會(huì)在保存時(shí)自動(dòng)刷新,但不會(huì)保留客戶(hù)端的狀態(tài)。所有來(lái)自 node 的依賴(lài)關(guān)系似乎都能正常工作,不管它們是使用傳統(tǒng)的模塊格式還是 node API(比如我們?cè)?esbuild 中遇到的臭名昭著的 process.env)。
在 React 中保存客戶(hù)端狀態(tài)需要 react-refresh,它需要一些自己的 Babel 包作為依賴(lài)。這些包不是默認(rèn)包含的,但可以使用更最大化的React模板。該模板拉入了 react-refresh、Prettier、Chai 和 React Testing Library,總體的 Node 依賴(lài)包重達(dá) 80MB。
npx?create-snowpack-app?my-react-project?--template?@snowpack/app-template-react
支持的文件
支持JSX,但同樣,默認(rèn)情況下只支持 .jsx 文件。Snowpack 會(huì)自動(dòng)檢測(cè)是使用 React 還是 Preact ,并據(jù)此決定使用哪種渲染函數(shù)來(lái)進(jìn)行JSX轉(zhuǎn)換。但是,如果我們想進(jìn)一步定制JSX,就需要通過(guò)他們的插件引入 Babel 。還有一個(gè) Snowpack 插件可以用于 Vue 單文件組件,當(dāng)然也可以用于 Svelte 組件。此外,Snowpack 還可以編譯 TypeScript ,但對(duì)于類(lèi)型檢查,我們需要 TypeScript 插件。
CSS可以導(dǎo)入到 JavaScript 中,并在運(yùn)行時(shí)被扔到文檔 中。只要CSS模塊的擴(kuò)展名為 .module.css ,也支持開(kāi)箱即用的 scoping 。
導(dǎo)入的JSON文件將被強(qiáng)制轉(zhuǎn)換為一個(gè) JavaScript模塊中,并以對(duì)象作為默認(rèn)導(dǎo)出。Snowpack 支持圖片,并將其復(fù)制到生產(chǎn)文件夾中。為了配合它的非打包理念,Snowpack不將圖像作為數(shù)據(jù)URL納入捆綁中。
生產(chǎn)構(gòu)建
默認(rèn)的 snowpack 構(gòu)建命令基本上是將源文件結(jié)構(gòu)復(fù)制到一個(gè)輸出文件夾中。對(duì)于編譯成 JavaScript 的文件(例如TypeScript, JSX, JSON, .vue, .svelte),它將每個(gè)單獨(dú)的文件轉(zhuǎn)換成一個(gè)獨(dú)立的瀏覽器友好的 JavaScript 模塊。
這很好用,但對(duì)于生產(chǎn)來(lái)說(shuō)并不是很好,因?yàn)槿绻创a被分割成很多文件,可能會(huì)引起大量的請(qǐng)求。在 Snap Shot 應(yīng)用中,我最終得到了 184KB 的源文件,然后又從 Skypack 中請(qǐng)求了 105KB 的依賴(lài)關(guān)系,這就造成了一個(gè)非常大的請(qǐng)求。
然而,Snowpack 將 esbuild 作為一個(gè)依賴(lài)項(xiàng),我們可以通過(guò)在Snowpack配置中添加一個(gè) "optimization "對(duì)象,使 esbuild 能夠打包、最小化和編譯我們的代碼。
//?snowpack.config.js
module.exports?=?{
??optimize:?{
????bundle:?true,
????minify:?true,
????target:?'es2018',
??},
這樣就可以使用 esbuild 提供的優(yōu)化功能來(lái)運(yùn)行代碼,所以只要加入這些選項(xiàng),我們就可以得到和之前使用 esbuild 一樣的構(gòu)建。
總結(jié)
Snowpack 通過(guò)功能齊全的開(kāi)發(fā)服務(wù)器、詳細(xì)的文檔和易于安裝的模板提供輕量級(jí)的開(kāi)發(fā)人員體驗(yàn)。你可以決定是否要打包你的應(yīng)用程序以及如何打包。如果你想要一個(gè)既能提供開(kāi)發(fā)服務(wù)器又能提供更有意見(jiàn)的構(gòu)建步驟的工具,你可能會(huì)想看看我們列表中的下一個(gè)工具 Vite。

Vite

Vite 是由 Vue 的創(chuàng)始人尤雨溪開(kāi)發(fā)的。esbuild 專(zhuān)注于構(gòu)建步驟,Snowpack 專(zhuān)注于開(kāi)發(fā)服務(wù)器,而 Vite 則同時(shí)提供了這兩點(diǎn):一個(gè)完整的開(kāi)發(fā)服務(wù)器和一個(gè)使用 Rollup 的優(yōu)化構(gòu)建命令。
用例
如果你想要一個(gè)嚴(yán)肅的 create-react-app 或 Vue CLI 的競(jìng)爭(zhēng)對(duì)手,Vite 是最接近的一個(gè),因?yàn)樗鼛в?batteries-included 的功能。快如閃電的開(kāi)發(fā)服務(wù)器和零配置優(yōu)化的生產(chǎn)構(gòu)建意味著你可以在沒(méi)有任何配置的情況下從零到生產(chǎn)。Vite 可用于小型項(xiàng)目或大型生產(chǎn)應(yīng)用程序,Vite 的一個(gè)很好的用例是任何可觀的單頁(yè)應(yīng)用。
你為什么不使用 Vite?Vite 是一個(gè)有成見(jiàn)的工具,你可能不同意它的意見(jiàn)。你可能不想使用 Rollup 來(lái)構(gòu)建(我們一直在討論 esbuild 有多快),或者你可能希望你的工具能夠給你提供 Babel、eslint 和 webpack 加載器生態(tài)系統(tǒng)的全部功能。
另外,你想要零配置的服務(wù)器端渲染框架,你最好還是繼續(xù)使用基于 webpack 的框架,比如 Nuxt.js 和 Next.js ,直到 Vite 服務(wù)器端渲染更加完善。
設(shè)置
Vite 比 esbuild 和 Snowpack 有更多的默認(rèn)值。它的文檔清晰而詳細(xì)。我們得到了對(duì) Vue 的全面支持,尤雨溪是創(chuàng)建者,所以 Vite 是 Vue 開(kāi)發(fā)者來(lái)說(shuō)無(wú)疑是一條必經(jīng)之路。也就是說(shuō),Vite 可以和任何前端框架一起使用,甚至還提供了一個(gè)模板列表來(lái)幫助你入門(mén)。
用法
Vite 的開(kāi)發(fā)服務(wù)器非常強(qiáng)大。Vite 通過(guò) esbuild 將一個(gè)項(xiàng)目的所有依賴(lài)關(guān)系預(yù)先打包到一個(gè)單一的本地 JavaScript 模塊中,然后用一個(gè)大量緩存的 HTTP 頭來(lái)提供服務(wù)。這意味著在第一次頁(yè)面加載后,不會(huì)在編譯、服務(wù)或請(qǐng)求導(dǎo)入的依賴(lài)項(xiàng)上浪費(fèi)時(shí)間。Vite還提供了清晰的錯(cuò)誤信息,打印出準(zhǔn)確的代碼塊和行號(hào),以排除故障。同樣使用 Vite ,我在引入使用 node API 或傳統(tǒng)格式的依賴(lài)項(xiàng)時(shí)沒(méi)有任何問(wèn)題。它們似乎都被塞進(jìn)了一個(gè)瀏覽器可接受的 esmodule 中。
Vite 的 React 和 Vue 模板都引入了支持熱模塊替換的插件。Vue模板為一個(gè)用于單文件組件引入了Vue插件,以及一個(gè)用于 JSX 的 Vue 插件。React模板引入了 react-refresh 插件。無(wú)論哪種方式,都會(huì)給你提供熱模塊替換和客戶(hù)端狀態(tài)保存。當(dāng)然,它們?cè)黾恿艘恍┮蕾?lài)性,包括Babel包,但是,在Vite中使用JSX時(shí),Babel其實(shí)并不是必須的。默認(rèn)情況下,JSX 的工作方式和 esbuild 一樣--它轉(zhuǎn)換為 React.createElement。它不會(huì)自動(dòng)導(dǎo)入 React,但它的行為可以被配置。
同時(shí),Vite 并不像 Snowpack 和 wmr 那樣支持流式導(dǎo)入。這意味著要像往常一樣安裝npm的依賴(lài)關(guān)系。
一個(gè)很酷的事情是,Vite 包含了對(duì)服務(wù)器端渲染的實(shí)驗(yàn)性支持。挑選你所選擇的框架,并生成直接運(yùn)到客戶(hù)端的靜態(tài)HTML。目前,看起來(lái)我們需要自己構(gòu)建這個(gè)架構(gòu),但這看起來(lái)還是一個(gè)很好的機(jī)會(huì),元框架可以建立在 Vite 之上。尤雨溪已經(jīng)有一個(gè)名為 VitePress 的作品正在進(jìn)行中,它是 VuePress 的替代品,具有使用Vite的優(yōu)點(diǎn)。而 Sveltekit 也已經(jīng)將Vite加入了依賴(lài)列表。看來(lái)CSS代碼拆分收錄也是 Sveltekit 改用Vite的原因之一。
支持的文件
對(duì)于 CSS,Vite 提供的功能是我們所看到的所有工具中最多的。它支持打包CSS導(dǎo)入以及CSS模塊。但我們也可以npm安裝PostCSS插件,并創(chuàng)建一個(gè) postcss.config.js 文件,Vite會(huì)自動(dòng)開(kāi)始將這些轉(zhuǎn)換應(yīng)用到CSS中。
我們可以安裝和使用CSS預(yù)處理器--只需npm安裝預(yù)處理器,并將文件重命名為正確的擴(kuò)展名(如 .filename.scss ),Vite就會(huì)開(kāi)始應(yīng)用相應(yīng)的預(yù)處理器。而且正如我們?cè)诟攀鲋兴f(shuō),Vite 支持CSS代碼分割。
圖片導(dǎo)入默認(rèn)為一個(gè)公共URL,但我們也可以通過(guò)使用URL字符串末尾的?raw參數(shù)將其作為字符串加載到捆綁中。
JSON 文件可以在源代碼中導(dǎo)入,并轉(zhuǎn)換為 esmodule 導(dǎo)出單個(gè)對(duì)象。我們也可以提供一個(gè)命名的導(dǎo)入, Vite 將在 JSON 文件的根字段中查找導(dǎo)入,并查找其余的 treeshake。
生產(chǎn)構(gòu)建
Vite 使用 Rollup 進(jìn)行預(yù)配置的生產(chǎn)構(gòu)建,并進(jìn)行了大量的優(yōu)化。它有意提供了一個(gè)零配置的構(gòu)建,這對(duì)大多數(shù)用例來(lái)說(shuō)應(yīng)該是足夠的。
該構(gòu)建包含了我們所期望的 Rollup 特性:打包、最小化和 tree shaking 。但我們也得到了一些額外的功能,比如代碼分割動(dòng)態(tài)導(dǎo)入和所謂的 "異步分塊加載",這是一種花哨的說(shuō)法,即如果我們請(qǐng)求導(dǎo)入另一個(gè)模塊的 JavaScript 模塊,構(gòu)建將被預(yù)先優(yōu)化,以同時(shí)加載這兩個(gè)模塊(異步)。
用 Snap Shot 應(yīng)用運(yùn)行Vite的默認(rèn)構(gòu)建,最終得到了一個(gè)5KB的 JavaScript 文件和一個(gè)160KB的JavaScript文件(總共165KB),項(xiàng)目中的所有CSS都被自動(dòng)最小化為一個(gè)2.71KB的小文件。
總結(jié)
Vite 的性質(zhì)使其成為我們當(dāng)前工具的嚴(yán)重競(jìng)爭(zhēng)對(duì)手。許多工作已經(jīng)完成,使開(kāi)發(fā)人員的體驗(yàn)真正無(wú)縫,并使生產(chǎn)就緒的構(gòu)建開(kāi)箱即用。

wmr

和 Vite 一樣,wmr 也是另一個(gè)成見(jiàn)的構(gòu)建工具,它同時(shí)提供了開(kāi)發(fā)服務(wù)器和構(gòu)建步驟。它是由 Preact 的創(chuàng)建者 Jason Miller 打造的,所以對(duì)于 Preact 開(kāi)發(fā)者來(lái)說(shuō),這絕對(duì)是一條幸福的道路。Jason Miller 在做客 JS Party 播客時(shí)解釋了wmr背后的思路。
Preact很小,如果你想做一個(gè)輕量級(jí)的項(xiàng)目,它真的很好。我們的工具在哪里呢?我們有一個(gè)基于webpack的工具,在生產(chǎn)中被一堆高大上的網(wǎng)站所使用,但那是重量級(jí)的工具。原型開(kāi)發(fā)工具在哪里?那是一方面。另一只手是我和一群碰巧在Preact團(tuán)隊(duì)里的人;我們已經(jīng)在打包器生態(tài)系統(tǒng)的邊緣徘徊了一段時(shí)間,鞭策人們,試圖在一個(gè)方向上達(dá)成共識(shí),我們可以朝著這個(gè)方向前進(jìn),以進(jìn)一步推進(jìn)這個(gè)編寫(xiě)現(xiàn)代代碼和發(fā)布現(xiàn)代代碼的想法。
這告訴我們,wmr 就是要編寫(xiě)和發(fā)布現(xiàn)代化的代碼,在項(xiàng)目中實(shí)現(xiàn)更輕的工具。
你可能想知道 wmr 代表什么?什么也不知道!wmr是什么意思?"Web Modules Runtime "和 "Wet Module Replacement "這兩個(gè)名字被浮出水面,但這是一個(gè)假的縮寫(xiě),類(lèi)似于 npm。
wmr 和 Preact 一樣采用了無(wú)情的 bundle size purging,所以它的體積很小--重量只有 2.6 MB--而且完全不包含任何 npm 依賴(lài)。不過(guò),它還是設(shè)法打包了一大堆非常棒的功能,包括一個(gè)熱模塊替換開(kāi)發(fā)服務(wù)器和一個(gè)優(yōu)化的生產(chǎn)構(gòu)建。
用例
如果我想用 Preact 盡快創(chuàng)建一個(gè)原型,我會(huì)用 wmr 。沒(méi)有任何配置,下載只需要幾秒鐘。感覺(jué)就像在使用一個(gè)超強(qiáng)的靜態(tài)文件服務(wù)器。通過(guò)TypeScript、優(yōu)化的構(gòu)建步驟和靜態(tài)HTML渲染,wmr提供了發(fā)布中小型應(yīng)用程序所需的一切。它的小尺寸也非常適合快速試用一個(gè)庫(kù)或演示一個(gè)想法。
如果你不使用 Preact、React 或 vanilla JavaScript,wmr可能不是你的工具。Preact 團(tuán)隊(duì)還沒(méi)有為其他框架提供模板。文檔也沒(méi)有我們看過(guò)的其他工具那么詳細(xì)。這意味著你離開(kāi)快樂(lè)的道路越遠(yuǎn),你就會(huì)越深入地挖掘源頭。所以,如果需要大量的定制,我不能推薦它。
設(shè)置
如果你使用的是Preact,除了快速安裝npm之外,完全不需要任何設(shè)置。使用 React with wmr 而不是 Preact,目前有兩個(gè)步驟。首先,在你的package.json中把htm/preact別名為htm/react,把react別名為es-react。
"alias":?{
??"htm/preact":?"htm/react",
??"react":?"es-react"
},
然后將引入es-react到你的組件中。
//?ReactDOM?only?needed?on?root?render(from?code秘密花園)
import?{?React,?ReactDOM,}?from?'es-react';
這意味著我們實(shí)際上并沒(méi)有使用你可能習(xí)慣的普通React包,而是從 es-react 中引入 React。這是因?yàn)閣mr依賴(lài)于與本地 JavaScript 模塊兼容的包。React默認(rèn)不使用本地模塊,而是使用一種稱(chēng)為 UMD 較老的模塊樣式。es-react 是一個(gè)包,它可以拉入 React ,但提供與web平臺(tái)兼容的導(dǎo)出。
這說(shuō)明了 wmr 的理念,即使用web平臺(tái)的原生基元,而不是使用工具來(lái)繞開(kāi)和抽象掉。
另一種選擇可以是在我們的應(yīng)用中使用 Skypack 導(dǎo)入,這也是為了在瀏覽器中工作而預(yù)先優(yōu)化的。
import?React?from?'https://cdn.skypack.dev/react';
import?ReactDOM?from?'https://cdn.skypack.dev/react-dom';
wmr 希望你寫(xiě)的是在瀏覽器中運(yùn)行的現(xiàn)代代碼,這可能意味著如果你引入使用node API或傳統(tǒng)模塊系統(tǒng)的依賴(lài)項(xiàng),你需要做一些配置。為了讓 Snap Shot 應(yīng)用正常運(yùn)行,我需要深入研究node模塊,并將一兩個(gè)庫(kù)轉(zhuǎn)換為使用本地JavaScript模塊語(yǔ)法。如果你使用的是舊庫(kù),這可能會(huì)拖慢你的速度。Preact生態(tài)系統(tǒng)都經(jīng)過(guò)優(yōu)化,可以在瀏覽器中運(yùn)行,應(yīng)該不需要任何修改。這是在 wmr 中堅(jiān)持 Preact 快樂(lè)之路的另一個(gè)原因。
wmr 有插件,它公開(kāi)了一個(gè)插件API,支持 Rollup 插件的構(gòu)建步驟。docs 上有越來(lái)越多的 wmr 專(zhuān)用例子,包括一個(gè)對(duì)HTML進(jìn)行最小化的插件,還有一個(gè)基于文件系統(tǒng)的路由功能。
wmr 支持不同的框架,但沒(méi)有任何預(yù)先構(gòu)建的模板。而且一開(kāi)始我發(fā)現(xiàn)配置 JSX 變換相當(dāng)困難。說(shuō)到這里,Jason 已經(jīng)確認(rèn)有計(jì)劃讓JJSX變得更可配置,而且 wmr 的目的是框架無(wú)關(guān)。JSX計(jì)劃在普通 JavaScript 文件中開(kāi)箱即用。
使用方法
要開(kāi)始,你可以在命令行中運(yùn)行這個(gè)命令。
npm?init?wmr?your-project-name
或者,你也可以運(yùn)行這些命令來(lái)手動(dòng)構(gòu)建你的應(yīng)用程序。
npm?init?-y
npm?install?wmr
mkdir?public
touch?public/index.html
touch?public/index.js
然后在index.html的正文中添加一個(gè)腳本導(dǎo)入(再次確保使用type="module")。
現(xiàn)在你可以在你的index.js文件中寫(xiě)一個(gè)Preact hello world。
import?{?render?}?from?'preact';
render(Hello?World?ConardLi!
,?document.body);
最后啟動(dòng)你的開(kāi)發(fā)服務(wù)器。
node_modules/.bin/wmr
現(xiàn)在我們有了一個(gè)完整的熱模塊替換開(kāi)發(fā)服務(wù)器,它會(huì)立即響應(yīng)我們?cè)创a的任何變化。
wmr 在轉(zhuǎn)換 JSX 時(shí)使用了一個(gè)叫 htm 的工具,它提供了一些很棒的好處。比方說(shuō),我們?cè)?wmr 中使用 Preact 寫(xiě)一個(gè)計(jì)數(shù)器,卻犯了一個(gè)錯(cuò)誤。
import?{?render?}?from?'preact';
import?{?useState?}?from?'preact/hooks';
function?App()?{
??const?[count,setCount]?=?useState(0)
??return?<>
???//?HIGHLIGHT
??count:?{count}
??>
}
render( ,?document.body);
count 在 onClick 處理函數(shù)中拼寫(xiě)錯(cuò)誤,所以運(yùn)行這個(gè)函數(shù)會(huì)出現(xiàn)錯(cuò)誤。通常情況下,我們必須依靠我們的工具和 source map 來(lái)收集關(guān)于錯(cuò)誤所在的信息,但wmr采取了不同的解決方案。對(duì)于htm,通過(guò)使用標(biāo)記的模板文本,這可以盡可能地接近瀏覽器中的原生JSX。所以,在哪里寫(xiě)React或Preact代碼通常是這樣的。
<MyComponent>I?am?JSX.?I?am?not?actually?valid?JavascriptMyComponent>
...htm看起來(lái)更像這樣。
html`<${MyComponent}>I?am?about?as?close?as?it?gets?to?JSX?as?you?can?get?while?being?able?to?run?in?the?browserMyComponent>`
現(xiàn)在,如果我們正在調(diào)試我們的代碼,打開(kāi) DevTools 中的 "Sources " 面板,我們應(yīng)該會(huì)看到一個(gè)腳本,它與源代碼在編輯器中的樣子幾乎相同。

通過(guò)這種方式,我們就可以正確地調(diào)查錯(cuò)誤在瀏覽器中的位置,而不必使用 source map。當(dāng)然,這個(gè)具體的例子是很造作的,但你可以看到這可能是非常有用的,因?yàn)檫@意味著wmr在你的開(kāi)發(fā)環(huán)境中不需要 source map 。
wmr 默認(rèn)支持流式導(dǎo)入,所以裸露的導(dǎo)入將從npm注冊(cè)表中拉下來(lái)。這是通過(guò)一個(gè)復(fù)雜的過(guò)程來(lái)完成的,這個(gè)過(guò)程會(huì)檢查 npm 包中的所有源碼,刪除所有的測(cè)試和元數(shù)據(jù),并將其轉(zhuǎn)換為一個(gè)單一的本地 JavaScript 導(dǎo)入。與 Snowpack 類(lèi)似,可以在不使用 npm 安裝任何東西的情況下構(gòu)建一個(gè)復(fù)雜的應(yīng)用程序。事實(shí)上,wmr 是第一個(gè)支持這種想法的工具。
支持的文件
至于 wmr 支持的其他類(lèi)型的文件,CSS 文件可以用 JavaScript 導(dǎo)入,CSS模塊也支持。
Vue單文件組件和Svelte組件都沒(méi)有內(nèi)置支持。不過(guò),wmr 的構(gòu)建步驟可以和 Rollup 插件一起使用,開(kāi)發(fā)服務(wù)器也可以配置Polka/Express中間件,所以可以用這些來(lái)將導(dǎo)入的文件轉(zhuǎn)換成 Vue 和 Svelte 組件。事實(shí)上,我為Vue單文件組件寫(xiě)了一個(gè)小插件來(lái)展示如何做到這一點(diǎn)。
在沒(méi)有插件的情況下,我們不能在 wmr 中把圖片作為數(shù)據(jù)URL導(dǎo)入到 JavaScript 中。相反,我們需要使用一個(gè)語(yǔ)法正確的 JavaScript 方法來(lái)導(dǎo)入它們。所以,如果我們?cè)诠参募A中有一張狗的圖片,我們可能會(huì)把它包含在 Preact 組件中,比如這樣。
function?Dog()?{
??return?<img?src={new?URL('./dog.jpg',?import.meta.url)}?alt="dog?hanging?out">img>
}
而一旦構(gòu)建步驟運(yùn)行,圖片就會(huì)被復(fù)制,并從分發(fā)文件夾中訪問(wèn)。開(kāi)發(fā)服務(wù)器中的圖片有熱模塊替換,所以有圖片的變化會(huì)立即反映在瀏覽器中。
再來(lái)說(shuō)說(shuō)文件支持。JSON可以導(dǎo)入,并轉(zhuǎn)換成 JavaScript 對(duì)象使用。但實(shí)際構(gòu)建應(yīng)用時(shí),我們就需要 Rollup JSON 插件了。
生產(chǎn)構(gòu)建
wmr 提供了一個(gè)生產(chǎn)構(gòu)建步驟,包括打包、小型化和 tree-shaking,而不需要任何額外的依賴(lài)。看了一下 wmr 的源碼,似乎在引擎蓋下使用了rollup和terser,wmr包中包含了這些的 minified 版本。Snap Shot 應(yīng)用的wmr捆綁包是164KB,所以它創(chuàng)建的捆綁包只比Vite創(chuàng)建的兩個(gè) JavaScript 文件的總大小小一點(diǎn)點(diǎn)。
還有一種方法可以將wmr配置為這樣一種方式,它使用 preact-iso 在瀏覽器上將一個(gè)應(yīng)用程序渲染為靜態(tài) HTML 并加工。這意味著wmr可以作為 Preact 的元框架使用,類(lèi)似于 Next.js 。
總結(jié)
我喜歡使用 wmr 來(lái)為 React 和 Preact 應(yīng)用做原型的體驗(yàn)。使用一個(gè)小得離譜但卻能提供開(kāi)發(fā)者便利的工具,接近于匹配重量級(jí)打包器,感覺(jué)很棒。

特征比較
我們剛剛分析了很多地方! 與其在這篇文章中上下滾動(dòng)比較結(jié)果,我已經(jīng)將所有內(nèi)容匯編在這里,以查看這些工具并排時(shí)的堆疊情況。我甚至為我們沒(méi)有明確提到的特性添加了額外的比較。
用例

設(shè)置

開(kāi)發(fā)服務(wù)器

生產(chǎn)構(gòu)建

其他特性

最后
我很高興能夠用我們剛剛看到的所有工具來(lái)構(gòu)建 JavaScript 應(yīng)用程序。無(wú)論我們是在編寫(xiě)一個(gè)小型的輔助項(xiàng)目還是一個(gè)大型的網(wǎng)站,所有這些工具都能加快反饋循環(huán),提高生產(chǎn)力。它們已經(jīng)打開(kāi)了大門(mén),問(wèn)我們?cè)?JavaScript 生態(tài)系統(tǒng)中需要什么,以及我們是否可以開(kāi)始失去傳統(tǒng)模塊和瀏覽器帶來(lái)的麻煩。這些工具將通過(guò)提供一個(gè)更精簡(jiǎn)、更快速的開(kāi)發(fā)者環(huán)境,在編寫(xiě)的代碼和運(yùn)行在瀏覽器中的代碼之抽象更少,從而降低了新開(kāi)發(fā)人員的進(jìn)入門(mén)檻。
如果你已經(jīng)厭倦了等待下載依賴(lài)和運(yùn)行構(gòu)建步驟,我建議你嘗試一下這種新一代的工具。
其他的 JavaScript 新工具
Rome– 一個(gè)完整的工具鏈,包括linting、編譯、捆綁、測(cè)試運(yùn)行和格式化SWC– 基于Rust的JavaScript/TypeScript編譯器Deno–JavaScript和TypeScript的運(yùn)行時(shí)(類(lèi)似于Node.js)
文中如有錯(cuò)誤,歡迎在留言區(qū)和我留言,如果這篇文章幫助到了你,歡迎點(diǎn)贊、在看和關(guān)注。你的點(diǎn)贊、在看和關(guān)注是對(duì)我最大的支持!
上面介紹的工具,你覺(jué)得哪個(gè)最好用呢?
最近面試BAT,整理一份面試資料《前端面試BAT通關(guān)手冊(cè)》,覆蓋了前端技術(shù)、CSS、JavaScript、框架、?數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。 獲取方式:關(guān)注公眾號(hào)并回復(fù)?前端?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。 明天見(jiàn)(??ω??)??
