ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript バンドルのサイズを最小限に抑えるための実践的なヒント

JavaScript バンドルのサイズを最小限に抑えるための実践的なヒント

Patricia Arquette
リリース: 2024-12-31 01:39:12
オリジナル
455 人が閲覧しました

ractical Tips to Minimize Your JavaScript Bundle Size

アートワーク: https://code-art.pictures/

なぜわざわざ?

最近では驚くべきことかもしれませんが、インターネット トラフィックは依然として多くのシナリオで問題となっています。モバイル ネットワークでは多くの場合、データ プランが制限されており、デバイスのバッテリーは無限ではなく、最も重要なことに、サイトの読み込みを待っている間のユーザーの注意力は限られています。だからこそバンドルのサイズが依然として重要なのです。ここでは、考慮すべき 7 つのヒントを紹介します。

1. ES5 にトランスパイルしない

2020 年、私はローカル ソーシャル ネットワークのプロモーション アプリをメンテナンスしていました。これは、ES5 を対象とした典型的な React TypeScript Webpack アプリケーションでした。 webpack 5 がリリースされたとき、私はアップグレードすることにしました。すべてが順調に進みました。エラー分析とユーザーからのフィードバックを監視しましたが、予想外のものは何もありませんでした。 1 週間後、自分のバンドルにアロー関数が含まれていることを偶然発見しました。それは新しい Webpack 機能でした。

ES5 の状態に関する優れた記事は次のとおりです。重要なポイント:

  • 多くのライブラリにはすでに ES6 コードが含まれており、それらのバンドルは ES5 互換ではありません。
  • 世界中で人気のあるサイトのほとんどは ES5 と互換性がありません。あなたのサイトにも ES5 は必要ないかもしれません。
  • ES5 との互換性が依然として必要であることが確実な場合は、ビルド プロセスにライブラリを含める必要があります。

2. 最新の JavaScript 言語機能を理解し、使用する

より優れた、よりコンパクトなコードを作成できる機能をいくつか紹介します。

2.1.発電機

ジェネレーターは、ネストされた構造をトラバースする効率的な方法です。

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)
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

2.2.プライベートクラスフィールド

ミニファイヤは、エクスポートされたオブジェクトであっても、これらのフィールドが外部で使用できないことを確実に認識しており、名前を自由に短縮できます。

ソース

export class A {
  #myFancyStateObject
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

バンドル

export class A{#t}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

もちろん、これは TypeScript のプライベート フィールドでは機能しません。tsc がその仕事を終えると、プライベート フィールドであるという知識が消えるからです。

2.3.最新の API

Promise.withResolvers() または Map.groupBy() について聞いたことがありますか?これらの API は、この記事の執筆時点では広く利用可能になっていませんが、間もなく利用可能になる予定です。今すぐ時間をかけてそれらを理解し、数年後にそれらを採用できるように準備してください。

ヒント: 新しい JavaScript API を見つける方法

ブログやポッドキャストは無数にありますが、最も優れた「ニュースレター」は TypeScript リポジトリ内の新しい .d.ts ファイルであると思います。たとえば、es2024.collection.d.ts を開いて、お楽しみください ?

3. コードの重複を避ける

繰り返されるパターンに気づきましたか?

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 つの潜在的なバグも発見しました?

4. オーバーエンジニアリングを避ける

このことわざの正確な出典は覚えていませんが、的を射ていると思います:

オーバーエンジニアリングとは、自分が抱えていない問題を解決することです。

Web 開発の世界では、主に 2 つのタイプのオーバーエンジニアリングを観察しました。

4.1.過度の一般化

このコードを考えてみましょう。パディングは 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 変数を使用するのが最善の解決策だと思います。

4.2.不適切なフレームワークの使用

はい、私たちが大好きなもの、Next.js、React、Vue などについて話しています。アプリに DOM 要素レベルでの対話性があまり含まれていない場合、または動的ではない場合、または非常に単純な場合は、他のオプションを検討してください。

  • 静的サイト ジェネレーター — いくつかの厳選されたリストから始めることができます。
    • 注意: 中には React やその他のフレームワークを内部で使用しているものもあります。バンドルの最小化が目標の場合は、別のことを試してください。
  • WordPress などのコンテンツ管理システム。
  • バニラ — 特に次の 2 つの場合に役立ちます。
    • アプリはとてもシンプルです。
    • アプリは DOM をあまり操作しませんが、代わりに、たとえばキャンバス上に何かを描画します。まさにこれと同じようなプロジェクトがあります。

5. 時代遅れの TypeScript 機能を避ける

TypeScript の現在の目標は主に JavaScript の型チェックですが、常にそうであったわけではありません。 ES6 以前の時代には、「より優れた JavaScript」を作成しようとする試みが数多くあり、TypeScript も例外ではありませんでした。一部の機能はその初期に遡ります。

5.1.列挙型

適切に使用するのが難しいだけでなく、非常に冗長な構造に変換されます。

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 ハンドブックでは、列挙型の代わりに単純なオブジェクトを使用することを推奨しています。共用体型を考慮することもできます。

5.2.名前空間

ネームスペースは、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 モジュールを使用します。

注: 名前空間は、グローバル ライブラリの型定義を記述する場合には依然として役立ちます。

6. 小さな最適化を無視しない

これらの小さなトリックのそれぞれにより、バンドル内の数バイトから数十バイトを節約できます。一貫して適用すれば、目に見える結果をもたらすことができます。

6.1.真/偽のプロパティを使用する

たとえば、空の文字列は false です。それが定義されており、空でないことを確認するには、次のように書くだけです:

const clampToRange = (n, {length}) =>
  clamp(0, n, length - 1)
const x = clampToRange(v1, a)
// ...
ログイン後にコピー

6.2.場合によっては非厳密な比較を許可する

== を使用して null を未定義に強制したり、その逆を行うことは完全に正当化されると信じています。

.btn-a {
    background-color: skyblue;
    padding: 4px;
}
.btn-b {
    background-color: deepskyblue;
    padding: 8px;
}
ログイン後にコピー

6.3.ヌル合体、論理和、およびデフォルトパラメータを使用してデフォルト値を置き換える

<button className='btn-a' onClick={handleClick}>
    Show
</button>
// ...
<button className='btn-b' onClick={handleSubmit}>
    Submit
</button>
ログイン後にコピー

6.4.ワンライナーにアロー関数を使用する

これの代わりに:

enum A {
  x, y
}
ログイン後にコピー

これを書きます:

var A;
(function (A) {
    A[A["x"] = 0] = "x";
    A[A["y"] = 1] = "y";
})(A || (A = {}));
ログイン後にコピー

6.5.非常に単純なオブジェクトにはクラスを使用しないでください

これの代わりに:

namespace A {
  export let x = 1
}
ログイン後にコピー

これを書きます:

var A;
(function (A) {
    A.x = 1;
})(A || (A = {}));
ログイン後にコピー

オブジェクトをフリーズして、そのプロパティを変更から保護することもできます。

7. バンドルを定期的に検査する

各バンドラーには、webpack の webpack-bundle-analyzer や Vite の vite-bundle-analyzer など、そのコンテンツを視覚化するツールがあります。次のようなツールは、バンドルに関する一般的な問題を特定するのに役立ちます:

  • ライブラリが不釣り合いな量のスペースを占有します。移行またはアップグレードする時期が来たのでしょうか?
  • プロジェクトのさまざまな部分で 2 つの類似したライブラリが使用されています。統合して 1 つだけを使用できますか?
  • 大きなファイルがバンドル内に存在しますが、ユーザーの 0.5% がアクセスするページ (ライセンス テキストなど) からのみアクセスされます。動的 import() を使用してバンドルを分割できる可能性があります?

これらのツールに加えて、時々手動でバンドルを読んで不規則性を見つけることをお勧めします。たとえば、TypeScript の構成ミスにより、ES6 バンドルに ES5 ヘルパーが含まれたり、ESM プロジェクトに CJS ヘルパーが含まれたりする可能性があります。これらの問題は自動化ツールでは検出できない可能性がありますが、それでも読み込み時間が長くなり、最も貴重な資産であるユーザーの注意が損なわれる可能性があります。


読んでいただきありがとうございます。コーディングを楽しんでください!

以上がJavaScript バンドルのサイズを最小限に抑えるための実践的なヒントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート