アートワーク: https://code-art.pictures/
最近では驚くべきことかもしれませんが、インターネット トラフィックは依然として多くのシナリオで問題となっています。モバイル ネットワークでは多くの場合、データ プランが制限されており、デバイスのバッテリーは無限ではなく、最も重要なことに、サイトの読み込みを待っている間のユーザーの注意力は限られています。だからこそバンドルのサイズが依然として重要なのです。ここでは、考慮すべき 7 つのヒントを紹介します。
2020 年、私はローカル ソーシャル ネットワークのプロモーション アプリをメンテナンスしていました。これは、ES5 を対象とした典型的な React TypeScript Webpack アプリケーションでした。 webpack 5 がリリースされたとき、私はアップグレードすることにしました。すべてが順調に進みました。エラー分析とユーザーからのフィードバックを監視しましたが、予想外のものは何もありませんでした。 1 週間後、自分のバンドルにアロー関数が含まれていることを偶然発見しました。それは新しい 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 による古典的な リファクタリング をお勧めします。上記のような単純な例だけでなく、階層の結合やデザインの繰り返しなどの複雑なケースもカバーしています。
それでは、小さな例を改良してみましょう。クランプはパラメーターを配列インデックスの範囲に制限するためによく使用されるようです。そのため、ショートカットを作成できます:
export class A { #myFancyStateObject }
この変更により、n はおそらく整数であることが意図されていることが明示されますが、現在はチェックされていません。また、未処理の特殊なケースである空の配列も強調しています。この小さな重複排除を行うことで、2 つの潜在的なバグも発見しました?
このことわざの正確な出典は覚えていませんが、的を射ていると思います:
オーバーエンジニアリングとは、自分が抱えていない問題を解決することです。
Web 開発の世界では、主に 2 つのタイプのオーバーエンジニアリングを観察しました。
このコードを考えてみましょう。パディングは 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」を使用しています。同様のパターンを持つ 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 モジュールを使用します。
注: 名前空間は、グローバル ライブラリの型定義を記述する場合には依然として役立ちます。
これらの小さなトリックのそれぞれにより、バンドル内の数バイトから数十バイトを節約できます。一貫して適用すれば、目に見える結果をもたらすことができます。
たとえば、空の文字列は false です。それが定義されており、空でないことを確認するには、次のように書くだけです:
const clampToRange = (n, {length}) => clamp(0, n, length - 1) const x = clampToRange(v1, a) // ...
== を使用して null を未定義に強制したり、その逆を行うことは完全に正当化されると信じています。
.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 中国語 Web サイトの他の関連記事を参照してください。