Skip to main content

サーバーサイドのnode_modulesをminifyしてコンテナ化する方法

まとめ

  • サーバーサイドのコードをminifyすることで容量を削減する

原因

  • コンテナ化するときnode_modulesをそのままイメージ内にCOPY(ADD)する

対策

  • サーバーサイドのコードもwebpackでminifyする

対策の動機

  • コンテナの容量を削減する
  • node server.js で実行できる状態にする
  • 1ファイルになるため、nodejsのrequireの解決時間が短くなる
    • = コンテナの起動時間が短くなる

導入方法

webpack 4の設定

webpack 4のざっくりとした設定は次の通り。

import * as webpack from "webpack";

const isProduction = process.env.NODE_ENV === "production";

const outputName = isProduction ? "server.prod.js" : "server.dev.js";

const useMinimize = false;

export const config: webpack.Configuration = {
mode: isProduction,
entry: {
[outputName]: "./src/index.ts",
},
optimization: {
minimize: useMinimize,
noEmitOnErrors: true,
},
devtool: isProduction ? undefined : "inline-source-map",
target: "node",
resolve: {
extensions: [".js", ".ts", ".tsx"],
alias: {
grpc: "@grpc/grpc-js", // https://github.com/grpc/grpc-node/issues/1185
},
},
module: {
rules: [ /** 各種loader */ ],
},
output: {
path: "dist",
filename: "[name].js",
libraryTarget: "commonjs2", // commonjsとしてoutputする
},
plugins: [
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production"),
"global.GENTLY": false, // https://github.com/node-formidable/node-formidable/issues/337#issuecomment-153408479
}),
],
},

ただし、ビルドするコードは次のようなものを含んではいけない。

制限

サーバー内でダイナミックインポートが利用できない

Bad

const sampleCode = (dynamicPath: string) => {
const someModule = require(dynamicPath); // 動的なrequire
// use someModule
};

Workaround

  • webpack.DefinePluginで該当箇所のコードが含まれないようにする
  • webpack.resolve.aliasを利用して動的なrequireを含まないライブラリに置換する

fsライブラリなどで実行時にファイルを読み込みができない

Bad

// in library
import * as fs from "fs";
const getConfig = () => {
return fs.readFileSync(__dirname + "/config.json");
};

Workaround

  • jsonの読み込みで利用している場合、importもしくはrequireに置き換える
  • デバッグ用に必要な場合はprocess.env.NODE_ENV !== "production"でラップしてproductionビルド時はDead Codeにする

継続方法(運用)

  • 実装制限を守る
  • CIでサーバー側のコードもビルドする
    • = 実装制限を破ったものはビルドで失敗する
  • minimizeしていないコードも同時にバンドルしてデバッグしやすさを担保する

対策の問題点

  • サーバーの実装制限がつく
  • 専門的なライブラリを使用している場合、解決策を見いだせない場合がある

展望

  • もっと良い方法がないか探す

参考資料