Minification は、ソースコードからすべての非必須文字(スペース、タブ、改行、コメント)を削除するプロセスです。Minificationは、プログラムの実行ロジックを変更せずにJavaScript、CSS、HTMLファイルのサイズを削減します。MDN Web Docsによると、ミニフィケーションはファイルサイズを50~70%削減でき、アプリケーションの読み込み速度とFirst Contentful Paint(FCP)に直接影響します。
重要なポイント
Minification は、プログラムの実行に影響を与えないすべての文字を削除するソースコードの自動変換です。スペース、タブ、改行文字、コメント、冗長な括弧が削除または短縮されます。Minificationは、本番環境へのデプロイ前にJavaScript、CSS、HTML、そしてまれにJSON設定に適用されます。
ミニフィケーションの主な目的は、ネットワーク経由で送信されるファイルサイズを削減することです。ミニフィケーション後の300KBのJavaScriptファイルは120~150KBになり、低速な3G接続での読み込み時間を200~400ミリ秒短縮できます。Google PageSpeed InsightsとLighthouseはコードのミニファイアを直接推奨しています。これはパフォーマンス評価とCore Web Vitalsの基準の一つです。
ミニフィケーションはビルドパイプラインの不可欠な部分です。TypeScriptまたはBabelでのトランスパイル後、コードはTree Shaking(未使用関数の削除)、次にミニファイアーを通過し、その後で最終的なバンドルにまとめられます。最新のバンドラー(Webpack、Rollup、esbuild)では、ミニフィケーションはビルドの最終段階でプラグインによって実行されます。
| 要素 | 例(前) | 例(後) | 削減率 |
|---|---|---|---|
| スペースとタブ | let x = 5; | let x=5; | 〜10–20% |
| 改行 | \n 行間 | すべて1行に | 〜2–5% |
| コメント | // comment | 削除 | 〜5–30% |
| 冗長な括弧 | if ((x > 0)) | if(x>0) | 〜1–3% |
スペースと改行の削除は最もシンプルで明白なテクニックです。ミニファイアーのパーサーはAST(抽象構文木)を走査し、文字列リテラルの一部ではないすべての空白文字を削除します。ほとんどのミニファイアーはさらに演算子を1行に結合し、GZipやBrotliで圧縮する際に追加の削減をもたらします。
変数名の置換(マングリング)はより積極的なテクニックです。ローカル変数と関数パラメーターは1文字の識別子(a、b、c)に名前が変更されます。これにより、サイズがさらに15~30%削減されます。Terserとesbuildは、特定の名前を保持するオプション(例:mangle.props.reservedによる公開API)付きでマングリングをサポートしています。
デッドコード除去(DCE)は、決して実行されないコードブランチを削除します。ミニファイアーは常にfalseとなる条件(if (false))を分析し、対応するブロックを削除します。より高度な分析はミニフィケーション前のTree Shaking段階で実行されますが、ミニファイアーレベルのDCEはモジュールレベルで検出されなかったローカルなデッドコードのケースを捕捉します。
マングリングは、ローカル変数と関数パラメーターを短い識別子(1〜2文字)に名前変更します。Terserはスコープに基づいてマングリングを実行します。1つの関数内の変数は、外部スコープと競合しない一意の短い名前を取得します。mangle.reservedオプションを使用すると、特定の名前(公開ライブラリAPIなど)を保持できます。
マングリングは、グローバル変数、オブジェクトプロパティ(mangle.propsが有効でない限り)、およびnewで使用されるクラス名には影響しません。マングリングからライブラリの公開APIを保護するには、正規表現を指定してmangle.props.reservedを使用します:reserved: ["_prop", /^private_/]。この設定がないと、外部コードが名前でオブジェクトプロパティにアクセスする場合、マングリングによってライブラリが壊れる可能性があります。
// ソースコード
function calculateTotal(price, tax) {
var result = price + (price * tax);
// 合計を返す
return result;
}
var total = calculateTotal(100, 0.2);
console.log(total);// Terserミニフィケーション後
function calculateTotal(a, b){return a + a * b}
var c = calculateTotal(100, .2);
console.log(c);2番目の例では、Terserがコメント、スペース、改行を削除し、priceをa、taxをb、resultをcに名前変更しました。サイズは197文字から79に削減され、60%の削減率です。同時に、コードの機能は完全に維持されています:calculateTotal(100, 0.2)は120を返します。
Terserは、Webpackエコシステムおよびほとんどの最新バンドラーにおける標準的なJavaScriptミニファイアーです。TerserはES6+構文(アロー関数、async/await、スプレッド)、公開API保護付きマングリング、ソースマップ、およびCPU数による並列実行をサポートしています。バージョン5.16以降、TerserにはTypeScriptの最適化(型のみのインポートとインターフェースの削除)が含まれています。
esbuildは、Goで書かれたミニファイアーで、同名のバンドラーに組み込まれています。esbuildは、ネイティブコードと並列処理により、Terserよりも10~100倍高速にミニフィケーションを実行します。ただし、esbuildがサポートする最適化は少なく、プロパティ保持付きのマングリングは行わず、型のみのインポートは削除せず、式の最適化もそれほど積極的ではありません。
// webpack.config.js — TerserPluginの設定
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
dead_code: true,
},
mangle: {
reserved: ["React", "Component"],
},
output: {
comments: false,
},
},
parallel: true,
}),
],
},
};TerserPluginの設定には3つの主要ブロックがあります。compressは式の最適化を担当します:drop_consoleはconsole.logを削除し、drop_debuggerはdebuggerを削除し、dead_codeは到達不能なブランチを削除します。mangleはreservedで公開名を保護しながら変数の名前変更を制御します。parallelはCPU数によるマルチスレッドを有効にします。
// esbuild: JSおよびCSSミニフィケーションのCLIコマンド
// esbuild app.js --bundle --minify --outfile=dist/app.min.js
// esbuild app.css --bundle --minify --outfile=dist/app.min.css
const esbuild = require("esbuild");
esbuild.build({
entryPoints: ["src/app.js", "src/styles.css"],
bundle: true,
minify: true,
sourcemap: true,
target: ["es2015"],
outdir: "dist",
}).catch(() => process.exit(1));esbuild APIはワンライナー設定を受け入れます。minify: trueはJSとCSSの両方のミニフィケーションを有効にします。sourcemap: trueはデバッグ用のコードマップを生成します。targetは最小ESレベルを定義します — esbuildは選択されたバージョンに合わせて最新コードを自動的にトランスパイルします。esbuildはビルド時間が重要なプロジェクト(CI/CDパイプライン、Hot Module Replacement、高速プロトタイプ)で特に効果的です。
React NativeはMetro Bundlerを使用します。これはTerserベースのミニフィケーションを含む独自のバンドラーです。本番モードでは、Metroは自動的にアプリケーションのJavaScriptバンドルにミニフィケーションを適用します。Metroでのミニフィケーション設定は、transformer.minifierConfigセクションのmetro.config.jsを通じて設定されます。さらに、iOSでのバンドルサイズを削減するためにinline-requireを無効にすることもできます。
モバイルアプリケーションのWebViewもミニフィケーションの恩恵を受けます。WebViewで読み込まれるHTML、CSS、JSは、アプリケーションに埋め込まれるかサーバーから読み込まれる前にミニファイアされる必要があります。ローカルリソース(Assets)の場合、ミニフィケーションは特に重要です。APK/IPAのサイズはアプリストアでのインストール率に直接影響します。
HermesはFacebookが開発したReact Native用のJavaScriptエンジンです。Hermesは事前(AOT)バイトコードコンパイルを実行し、アプリケーションの起動時間を30~50%短縮します。Hermesの場合、JavaScriptバンドルのミニフィケーションは、Terserを使用してバイトコードコンパイル前に実行されます。Hermesは独自のHBC(Hermes Bytecode)形式をサポートしていますが、JSミニフィケーションの段階は引き続き必要です。
// metro.config.js — ミニフィケーション設定
const defaultConfig = require("metro-config/src/defaults");
module.exports = require("metro-config").mergeConfig(
defaultConfig,
{
transformer: {
minifierConfig: {
compress: {
drop_console: true,
},
mangle: {
safari10: true,
},
},
},
}
);MetroはminifierConfig.drop_consoleを使用して、React Nativeの本番バンドルからすべてのconsole.logを削除します。mangle.safari10パラメーターは、Safari 10(iOS 10)を壊す識別子の名前変更を防ぎます。これは、iOS 10/11を搭載した古いiPadやiPhone 5sデバイスをサポートするアプリケーションにとって特に重要です。
Minificationと圧縮(gzip、brotli)は異なる最適化段階です。ミニフィケーションはソースコードレベルで機能し、サーバーに送信する前に文字数を削減します。圧縮はトランスポートプロトコルレベルで機能し、ファイルをクライアントに送信する際にサーバー(nginx、Apache、CDN)によって適用されます。ミニフィケーションは圧縮前にサイズを削減するため、二重の効果をもたらします:gzipは既に削減されたデータを圧縮します。
ミニフィケーション後の300KBのJavaScriptファイル — 120KB、gzip後 — 35~40KB。ミニファイアされていないファイルにのみgzipを適用した場合、サイズは55~70KBになります。Minification + gzipは、gzip単独よりも30~40%優れた結果をもたらします。Brotli(レベル6)は、ミニフィケーション後にgzipよりもさらに15~20%効率的に圧縮します。
| 方法 | レベル | ファイルサイズ | 削減率 |
|---|---|---|---|
| 元のファイル | — | 300 KB | 0% |
| ミニフィケーション後 | コード | 120 KB | 60% |
| gzip後(ミニフィケーションなし) | トランスポート | 65 KB | 78% |
| Minification + gzip | コード + トランスポート | 38 KB | 87% |
| Minification + Brotli | コード + トランスポート | 30 KB | 90% |
よくある質問
UglifyJSはES6+構文をサポートしていない古いミニフィケーションツールです。Terserは最新のJavaScriptをサポートするUglifyJSのフォークです。すべての最新バンドラー(Webpack 5、Rollup、esbuild)はTerserまたは独自のミニファイアーを使用しており、UglifyJSはレガシープロジェクトでのみ使用されています。
Source mapsは本番バンドルに含まれない別個の.mapファイルです。サーバーは、許可された開発者にのみ(Authorizationヘッダーを介して)ソースマップを提供する必要があります。本番環境では、ソースマップはユーザーのブラウザによって読み込まれないため、バンドルサイズに影響しません。
破損のリスクは、オブジェクトのプロパティ名を変換する積極的なマングリングに存在します。コードがdata-attributesを介してDOM要素にアクセスしたり、フィールド名にJSON文字列を使用したりする場合、マングリングによって公開プロパティの名前が変更される可能性があります。解決策は、mangle.reservedで除外するか、特定の名前空間に対してマングリングを無効にすることです。
CSSミニフィケーションはJSミニフィケーションよりも効果は低い(15~25%)ですが、Core Web Vitalsへの準拠には必須です。CSSミニファイアーはスペースを削除し、同一セレクターを統合し、16進数カラーを短縮し(#ff0000 → #f00)、未使用の@keyframesを削除します。CleanCSSとesbuildは人気のあるCSSミニフィケーションツールです。
Source maps(.mapファイル)は、ミニファイアされたコードを元のソースにリンクします。Chrome DevToolsとSafari Web Inspectorでは、ソースマップが有効な場合、元のファイルが表示されます。正しく動作させるには、ソースマップをサーバーにアップロードし(本番環境でも)、開発者ツールを通じて有効にする必要があります。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。