在沒有構建系統的情況下編寫 Javascript
嗨!這周我一直在寫一些 Javascript,和往常一樣,當我開始一個新的前端項目時,我面臨的問題是:我是否應該使用構建系統?
我想談談構建系統對我有什麼吸引力,為什麼我(通常)仍然不使用它們,以及一些前端 Javascript 庫要求你使用構建系統時,為什麼我覺得這讓我感到沮喪。
我寫這篇文章是因為我看到的大多數關於 JS 的文章都假定你正在使用構建系統,而對於像我這樣的人來說,編寫非常簡單的、不需要構建系統的小型 Javascript 項目時,構建系統可能反而添加了很多麻煩。
什麼是構建系統?
構建系統的思路是,你有一堆 Javascript 或 Typescript 代碼,你想在把它放到你的網站上之前把它翻譯成不同的 Javascript 代碼。
構建系統可以做很多有用的事情,比如:
- (出於效率的考慮)將 100 多個 JS 文件合併成一個大的捆綁文件
- 將 Typescript 翻譯成 Javascript
- 對 Typescript 進行類型檢查
- 精簡化
- 添加 Polyfills 以支持舊的瀏覽器
- 編譯 JSX
- 搖樹優化 (刪除不使用的 JS 代碼以減少文件大小)
- 構建 CSS(像 tailwind 那樣)
- 可能還有很多其他重要的事情
正因為如此,如果你今天正在構建一個複雜的前端項目,你可能會使用 Webpack、Rollup、Esbuild、Parcel 或 Vite 等構建系統。
很多這些功能對我很有吸引力,我過去使用構建系統也是出於這樣一些原因: 例如,Mess With DNS 使用 Esbuild 來翻譯 Typescript,並將許多文件合併成一個大文件。
目標:輕鬆地對舊的小網站進行修改
我做了很多簡單的小網站(之一、之二、之三、之四),我對它們的維護精力大約為 0,而且我改變它們的頻率很低。
我的目標是,如果我有一個 3、5 年前做的網站,我希望能在 20 分鐘內,
- 在一台新的電腦上從 GitHub 獲取源代碼
- 做一些修改
- 把它放到互聯網上
但我對構建系統(不僅僅是 Javascript 構建系統!)的經驗是,如果你有一個 5 年歷史的網站,要重新構建這個網站會非常痛苦。
因為我的大多數網站都很小,所以使用構建系統的 優勢 很小 —— 我並不真的需要 Typescript 或 JSX。我只要有一個 400 行的 script.js
文件就可以了。
示例:嘗試構建 SQL 實驗場
我的一個網站(SQL 試驗場)使用了一個構建系統(它使用 Vue)。我最後一次編輯該項目是在 2 年前,是在另一台機器上。
讓我們看看我今天是否還能在我的機器上輕鬆地構建它。首先,我們要運行 npm install
。下面是我得到的輸出:
$ npm install
[lots of output redacted]
npm ERR! code 1
npm ERR! path /Users/bork/work/sql-playground.wizardzines.com/node_modules/grpc
npm ERR! command failed
npm ERR! command sh /var/folders/3z/g3qrs9s96mg6r4dmzryjn3mm0000gn/T/install-b52c96ad.sh
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/surface/init.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/avl/avl.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/backoff/backoff.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_args.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_stack.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_stack_builder.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channel_trace.o
npm ERR! CXX(target) Release/obj.target/grpc/deps/grpc/src/core/lib/channel/channelz.o
在構建 grpc
時出現了某種錯誤。沒問題。反正我也不需要這個依賴關係,所以我可以花 5 分鐘把它拆下來重建。現在我可以 npm install
了,一切正常。
現在讓我們試著構建這個項目:
$ npm run build
? Building for production...Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:130:10)
at module.exports (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/util/createHash.js:135:53)
at NormalModule._initBuildHash (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:414:16)
at handleParseError (/Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:467:10)
at /Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:499:5
at /Users/bork/work/sql-playground.wizardzines.com/node_modules/webpack/lib/NormalModule.js:356:12
at /Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:373:3
at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:221:10)
at /Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:236:3
at runSyncOrAsync (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:130:11)
at iterateNormalLoaders (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:232:2)
at Array.<anonymous> (/Users/bork/work/sql-playground.wizardzines.com/node_modules/loader-runner/lib/LoaderRunner.js:205:4)
at Storage.finished (/Users/bork/work/sql-playground.wizardzines.com/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:43:16)
at /Users/bork/work/sql-playground.wizardzines.com/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:79:9
這個 Stack Overflow 的答案 建議運行 export NODE_OPTIONS=--openssl-legacy-provider
來解決這個錯誤。
這很有效,最後我得以 npm run build
來構建這個項目。
這其實並不壞(我只需要刪除一個依賴關係和傳遞一個略顯神秘的 Node 選項!),但我寧願不被那些構建錯誤破壞。
對我來說,對於小項目來說,構建系統並不值得
對我來說,一個複雜的 Javascript 構建系統對於 500 行的小項目來說似乎並不值得 —— 它意味著放棄了在未來能夠輕鬆更新項目的能力,以換取一些相當微小的好處。
Esbuild 似乎更穩定一些
我想為 Esbuild 大聲叫好: 我 在 2021 年了解到 Esbuild,並用於一個項目,到目前為止,它確實是一種更可靠的構建 JS 項目的方式。
我剛剛嘗試在一台新電腦上構建一個我最後一次改動在 8 個月前的 Esbuild 項目,結果成功了。但我不能肯定的說,兩年後我是否還能輕鬆的建立那個項目。也許會的,我希望如此!
不使用構建系統通常是很容易的
下面是 Nginx 實驗場 代碼中導入所有庫的部分的樣子:
<script src="js/vue.global.prod.js"></script>
<script src="codemirror-5.63.0/lib/codemirror.js"></script>
<script src="codemirror-5.63.0/mode/nginx/nginx.js"></script>
<script src="codemirror-5.63.0/mode/shell/shell.js"></script>
<script src="codemirror-5.63.0/mode/javascript/javascript.js"></script>
<link rel="stylesheet" href="codemirror-5.63.0/lib/codemirror.css">
<script src="script.js "></script>
這個項目也在使用 Vue,但它只是用 <script src
來載入 Vue —— 前端沒有構建過程。
一個使用 Vue 的無構建系統模板
有幾個人問如何在沒有構建系統的情況下開始編寫 Javascript。當然,如果你想的話,你可以寫原味的 JS,但我常用的框架是 Vue 3。
這是我做的一個小模板,用於啟動一個沒有構建系統的 Vue 3 項目。它只有 2 個文件和大約 30 行的 HTML/JS。
有些庫需要你使用構建系統
構建系統這些事情最近盤旋在我的腦海里,因為這周我正在用 CodeMirror 5 做一個新項目,我看到有一個新版本,CodeMirror 6。
所以我想 —— 很酷,也許我應該使用 CodeMirror 6 而不是 CodeMirror 5。但是 —— 似乎沒有構建系統你就不能使用 CodeMirror 6(根據 遷移指南),所以我打算堅持使用 CodeMirror 5。
同樣地,你以前可以把 Tailwind 作為一個巨大的 CSS 文件下載,但是 Tailwind 3 似乎根本不能作為一個大的 CSS 文件使用,你需要運行 Javascript 來構建它。所以我現在要繼續使用 Tailwind 2。(我知道,我知道,你不應該使用大的 CSS 文件,但是它驗收只有 300KB,而且我真的不希望有構建步驟)
(更正:看起來 Tailwind 在 2021 年發布了一個 獨立的命令行工具,這似乎是一個不錯的選擇)
我不完全確定為什麼有些庫不提供無構建系統版本 —— 也許發布無構建系統版本會給庫增加很多額外的複雜性,而維護者認為這不值得。或者,庫的設計意味著由於某種原因,不可能發布無構建系統版本。
我希望有更多的無構建系統的 Javascript 技巧
到目前為止,我的主要策略是:
- 在某個庫的網站上搜索 「CDN」,找到一個單獨的 Javascript 文件
- 使用 https://unpkg.com 來查看該庫是否有一個我可以使用的內置版本
- 託管我自己的庫的版本,而不是依賴可能崩潰的 CDN
- 編寫我自己的簡單集成方案,而不是拉入另一個依賴關係(例如,前幾天我為 Vue 編寫了自己的 CodeMirror 組件)。
- 如果我想要一個構建系統,就使用 Esbuild
還有一些看起來很有趣但我還沒有研究過的東西:
- 這個 關於 Javascript 注釋中類型語法的 Typescript 建議
- 一般來說,ES 模塊
via: https://jvns.ca/blog/2023/02/16/writing-javascript-without-a-build-system/
作者:Julia Evans 選題:lkxed 譯者:wxy 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive