作品:https://code-art.pictures/
現在可能會令人驚訝,但在許多情況下網路流量仍然是一個問題。行動網路的數據套餐通常有限,設備電池也不是無限的,最重要的是,用戶在等待網站載入時的注意力也是有限的。這就是為什麼捆綁包大小仍然很重要。以下有七個建議供您考慮。
2020 年,我正在為本地社交網路維護一個促銷應用程式。這是一個典型的針對 ES5 的 React TypeScript Webpack 應用程式。當 webpack 5 發佈時,我決定升級。一切都很順利;我監控了錯誤分析和使用者回饋,沒有什麼意外的。一週後,我意外地發現我的套件中包含了箭頭函數——這是一個新的 webpack 功能。
這是一篇關於 ES5 狀態的精彩文章。重點:
這裡有一些功能,可以讓您編寫更好、更緊湊的程式碼。
生成器是遍歷巢狀結構的有效方法:
type TreeNode<T> = { left?: TreeNode<T> value: T right?: TreeNode<T> }; function* traverse<T>(root: TreeNode<T>): Generator<T> { if (root.left) yield* traverse(root.left) yield root.value if (root.right) yield* traverse(root.right) }
壓縮器確信這些欄位不能有外部用途,即使在導出的物件中也是如此,並且可以自由縮短它們的名稱。
來源
export class A { #myFancyStateObject }
捆綁包
export class A{#t}
當然,對於 TypeScript 私有欄位來說,這不起作用,因為一旦 tsc 完成其工作,它們是私有的這一知識就會消失。
你聽過 Promise.withResolvers() 或 Map.groupBy() 嗎?在撰寫本文時,這些 API 尚未廣泛使用,但很快就會廣泛使用。現在花點時間熟悉它們,並準備好在幾年後採用它們。
有無數的部落格和播客,但我發現最好的「新聞通訊」是 TypeScript 儲存庫中的新 .d.ts 檔案。例如,只需打開 es2024.collection.d.ts 即可享受?
你注意到重複的模式了嗎?
type TreeNode<T> = { left?: TreeNode<T> value: T right?: TreeNode<T> }; function* traverse<T>(root: TreeNode<T>): Generator<T> { if (root.left) yield* traverse(root.left) yield root.value if (root.right) yield* traverse(root.right) }
重複的程式碼不僅增加了套件的大小,而且還使理解每個部分的作用變得更加困難。這通常會導致開發人員編寫新程式碼,而不是識別和重複使用現有的實用函數,從而進一步使捆綁包變得臃腫。
關於這個主題已經有很多優秀的材料,所以我不再重述它,而是推薦經典:Martin Fowler 的重構。它不僅涵蓋了上面的簡單範例,還涵蓋了耦合層次結構和重複設計等複雜情況。
現在,讓我們改進我們的小例子。看來clamp經常用於將參數限制在數組索引範圍內,所以我們可以創建一個快捷方式:
export class A { #myFancyStateObject }
此變更明確表明 n 可能是整數,目前尚未檢查。它還突出顯示了一個未處理的邊緣情況:空數組。透過進行這個小的重複資料刪除,我們還發現了兩個潛在的錯誤?
我不記得這句話的確切來源,但我認為它是正確的:
過度設計正在解決你沒有的問題。
在 Web 開發領域,我觀察到兩種主要類型的過度設計。
考慮這段程式碼。內邊距是 4px 的倍數,背景顏色是藍色陰影。這可能不是巧合,如果是這樣,則可能表示可能存在重複。但是我們真的有足夠的資訊來提取通用 Button 組件,還是我們過度設計了?
CSS
export class A{#t}
JSX
const clamp = (min, val, max) => Math.max(min, Math.min(val, max)) const x = clamp(0, v1, a.length - 1) const y = clamp(0, v2, b.length - 1) const z = clamp(0, v3, c.length - 1)
這個建議確實與「避免重複」有些衝突。過度重複程式碼刪除可能會導致過度設計。那麼,你在哪裡劃清界線呢?就我個人而言,我使用神奇的數字“3”:一旦我看到三個具有相似模式的地方,可能是時候提取通用組件了。
對於我們的藍色按鈕,我相信最好的解決方案是使用 CSS 變量,至少用於填充,而不是創建一個新組件。
是的,我說的是我們喜歡的東西——Next.js、React、Vue 等等。如果您的應用程式在 DOM 元素層級不涉及大量互動性,或者不是動態的,或者非常簡單,請考慮其他選項:
TypeScript 目前的目標主要是對 JavaScript 進行類型檢查,但情況並非總是如此。早在 ES6 出現之前,人們就曾多次嘗試創建“更好的 JavaScript”,TypeScript 也不例外。有些功能可以追溯到早期。
它們不僅難以正確使用,還會轉換成相當冗長的結構:
TypeScript
type TreeNode<T> = { left?: TreeNode<T> value: T right?: TreeNode<T> }; function* traverse<T>(root: TreeNode<T>): Generator<T> { if (root.left) yield* traverse(root.left) yield root.value if (root.right) yield* traverse(root.right) }
JavaScript
export class A { #myFancyStateObject }
官方 TypeScript 手冊建議使用簡單物件而不是枚舉。您也可以考慮聯合類型。
命名空間是 ESM 之前的模組解決方案。它們不僅增加了套件的大小,而且由於命名空間是全局的,因此在大型專案中很難避免命名衝突。
TypeScript
export class A{#t}
JavaScript
const clamp = (min, val, max) => Math.max(min, Math.min(val, max)) const x = clamp(0, v1, a.length - 1) const y = clamp(0, v2, b.length - 1) const z = clamp(0, v3, c.length - 1)
使用 ES 模組取代命名空間。
注意:但是,對於為全域庫編寫類型定義,命名空間仍然有用。
這些小技巧中的每一個都可以為您節省捆綁中的幾個到幾十個位元組。如果堅持使用,可以帶來明顯的效果。
例如,空字串是假的。要檢查它是否已定義且非空,您可以簡單地編寫:
const clampToRange = (n, {length}) => clamp(0, n, length - 1) const x = clampToRange(v1, a) // ...
我相信使用 == 強制 null 為 undefined,反之亦然,是完全合理的。
.btn-a { background-color: skyblue; padding: 4px; } .btn-b { background-color: deepskyblue; padding: 8px; }
<button className='btn-a' onClick={handleClick}> Show </button> // ... <button className='btn-b' onClick={handleSubmit}> Submit </button>
而不是這個:
enum A { x, y }
寫下:
var A; (function (A) { A[A["x"] = 0] = "x"; A[A["y"] = 1] = "y"; })(A || (A = {}));
而不是這個:
namespace A { export let x = 1 }
寫下:
var A; (function (A) { A.x = 1; })(A || (A = {}));
您也可以凍結物件以保護其屬性免遭變更。
對於每個捆綁器,都有可視化其內容的工具,例如用於 webpack 的 webpack-bundle-analyzer 和用於 Vite 的 vite-bundle-analyzer。這些工具可以幫助您識別捆綁包的常見問題:
除了這些工具之外,偶爾手動閱讀捆綁包以發現違規行為也是一個好主意。例如,由於 TypeScript 配置錯誤,您可能會在 ES6 捆綁包中找到 ES5 幫助程序,或在 ESM 專案中找到 CJS 幫助程序。這些問題可能無法被自動化工具發現,但仍然會增加載入時間,並可能會損失您最寶貴的資產 - 用戶的注意力。
感謝您的閱讀。快樂編碼!
以上是最小化 JavaScript 套件大小的實用技巧的詳細內容。更多資訊請關注PHP中文網其他相關文章!