JavaScriptを安全・確実にminify(圧縮)する方法まとめ

対象読者:フロントエンド開発で本番用JSを最適化したい人
ゴール:ビルドの再現性を保ちつつ、エラー調査しやすい sourcemap 付きの最小コードを出力する


なぜ minify するのか

  • 転送量の削減:空白・改行・コメントを除去、識別子短縮でファイルサイズを大幅に縮小
  • 描画の高速化:TTFB後のダウンロード完了が早まり、First Interaction も改善
  • 難読化の副次効果:可読性が落ちるため、コードの“そのまま流用”を一定抑止(セキュリティ対策にはならない点に注意)

代表的な手段と選び方

手段特徴向き・不向き
esbuild(CLI)高速。--minify だけで完了。バンドルも得意単体JS~中規模、WPテーマ等のシンプル構成
Terser(CLI / Rollup / Gulp)きめ細かい圧縮設定。既存ツールチェーンに馴染む細かい最適化調整が必要なとき
SWC(CLI/ツール)Rust製で高速。Babelの代替としてもTypeScript変換と併用したい場合
Webpack(mode=production)エコシステムが豊富。アセット連携が強い大規模SPA、複雑な依存管理
Vite(build)ESMベース。デフォルトで圧縮SPA/MPAのモダン構成

本記事では esbuildTerser を中心に、すぐ使える実例を示します。


esbuild でサッと最小構成

1) 単一ファイルをそのまま minify

npx esbuild path/to/app.js \
  --minify \
  --outfile=public/js/app.min.js

2) 依存をまとめて1本に(bundle)

npx esbuild path/to/app.js \
  --bundle \
  --minify \
  --sourcemap=external \
  --outfile=public/js/app.min.js
  • --sourcemap=externalapp.min.js.map を別ファイルとして出力(本番での配信/秘匿を調整しやすい)
  • 改行・空白は --minify が除去します(= 改行なしの1行コードに)

3) 複数ファイルをまとめて出力(outdir)

npx esbuild src/**/*.js \
  --minify \
  --outdir=public/js \
  --format=esm \
  --sourcemap=external

4) ライセンス表記の扱い(著作権コメント)

デフォルトでは一部コメントが保持されます。完全に消すなら:

npx esbuild src/app.js \
  --minify \
  --legal-comments=none \
  --outfile=public/js/app.min.js

※ ライセンス要件でヘッダー保持が必要な場合は --banner:js で明示付与を。

5) npm scripts に定義(再現性確保)

{
  "scripts": {
    "build:js": "esbuild src/app.js --bundle --minify --sourcemap=external --outfile=public/js/app.min.js",
    "watch:js": "esbuild src/app.js --bundle --minify --sourcemap --outfile=public/js/app.min.js --watch"
  },
  "devDependencies": {
    "esbuild": "^0.24.0"
  }
}

Terser を使う(細かい最適化が必要なとき)

1) 単体ファイルを minify

npx terser src/app.js \
  --compress \
  --mangle \
  --output public/js/app.min.js \
  --source-map "url='app.min.js.map'"

2) よく使うオプション

  • --compress:デッドコード除去、条件式の簡略化などを有効化
  • --mangle:識別子の短縮(衝突が怖いときは --mangle reserved=['$','jQuery'] のように予約)
  • --ecma 2020:対象ECMAScript指定で最適化が効きやすくなる場合あり
  • --comments all|some|false:著作権コメントの扱い

3) npm scripts 例

{
  "scripts": {
    "min:js": "terser src/app.js --compress --mangle --output public/js/app.min.js --source-map \"url='app.min.js.map'\""
  },
  "devDependencies": {
    "terser": "^5.31.0"
  }
}

Source Map(ソースマップ)の実務

置き場所

  • もっとも簡単:minifiedと同じディレクトリ*.map を出す
  • どうしても別ディレクトリ /maps に置きたい場合は、出力後に移動して sourceMappingURL を書き換えるのが現実的です(esbuild/Terserは“mapだけ別ディレクトリ”を素直に指定できないため)。

例:ビルド後に .map を移動して書き換え(macOS)

# 1) ビルド(mapは同じ場所に出す)
npx esbuild src/app.js --bundle --minify --sourcemap=external --outfile=public/js/app.min.js

# 2) mapを別ディレクトリに移動
mkdir -p public/maps
mv public/js/app.min.js.map public/maps/

# 3) 参照先を書き換え(sourceMappingURL を /maps に向ける)
# ※ sed の -i は macOS では拡張子要指定('' で回避)
sed -i '' 's|//# sourceMappingURL=app.min.js.map|//# sourceMappingURL=/maps/app.min.js.map|' public/js/app.min.js
  • CDN配信するなら、sourceMappingURLCDNの絶対URL にしておくとデバッグしやすい
  • 本番公開で map を配りたくない場合は、map非公開にして 500系で返す、もしくは --sourcemap 自体をビルド環境でのみ有効にする

よくある落とし穴と対策

  1. 即時関数やグローバル衝突
    ライブラリ同士が window.$ を奪い合うなど。IIFE 化や import/export ベースにリファクタしてからバンドル。
  2. 副作用のあるモジュール除去
    Tree Shaking が“副作用なし”と誤判定して削除することがある。package.jsonsideEffects 設定、あるいは keep 指定を検討。
  3. ライセンスコメントの削除
    ライセンス継承が必要なコードを取り込んでいる場合、--legal-comments=external|inline 等で適切に保持する。
  4. 本番での sourcemap 漏洩
    逆コンパイルされるため、アクセス制御非公開運用を。セキュリティ情報が含まれないかも確認。
  5. 互換性(古いブラウザ)
    最適化の結果、古い環境で壊れることがある。必要なら トランスパイル(Babel/SWC)ターゲット指定(esbuildの --target=es2018 など)を併用。

そのまま使える小さなテンプレート

npm + esbuild(単体ファイルを高速最小化)

{
  "name": "my-theme",
  "private": true,
  "scripts": {
    "build": "esbuild src/app.js --bundle --minify --sourcemap=external --outfile=public/js/app.min.js",
    "build:prod": "esbuild src/app.js --bundle --minify --legal-comments=none --sourcemap=external --outfile=public/js/app.min.js && mkdir -p public/maps && mv public/js/app.min.js.map public/maps/ && sed -i '' 's|//# sourceMappingURL=app.min.js.map|//# sourceMappingURL=/maps/app.min.js.map|' public/js/app.min.js"
  },
  "devDependencies": {
    "esbuild": "^0.24.0"
  }
}

npm + Terser(細かく調整したいとき)

{
  "name": "my-theme",
  "private": true,
  "scripts": {
    "min": "terser src/app.js --compress --mangle --output public/js/app.min.js --source-map \"url='/maps/app.min.js.map'\" && mkdir -p public/maps && mv public/js/app.min.js.map public/maps/"
  },
  "devDependencies": {
    "terser": "^5.31.0"
  }
}

コメント

タイトルとURLをコピーしました