見出し画像

serverlessのLambda開発環境としてserverless-webpackでトランスパイル、ESLint、エイリアス利用を設定してみた

SHIFT Group 技術ブログ

はじめに

こんにちは、SHIFTの開発部門に所属している Katayama です。

Node.js で import・export(ES6 の構文)を使えるように webpack × Babel の設定をやってみたでは Node.js で ES6 の構文(ES Modules)を利用するために、Babel でトランスパイルするという方法を取り上げた。

今回は上記の記事と同様の設定を行い、快適なLambda(サーバレス)の開発をできるようにしていきたいと思う。

やっていく設定内容のサマリとしては以下。

  • Lambda の開発で ES6 の構文(ES Modules)を利用するために Babel でトランスパイルするための設定(deploy パッケージに含まれる node_modules の管理も含む)
     ※Babel は webpack 内で動かすので、serverless-webpackの設定を行う事になる

  • webpack でのビルドする際に ESLint のチェックを実行するための設定

  • エイリアスの設定(webpack、ESLint)

それぞれ順番に見ていく。

serverless-webpack を設定し、Babel でトランスパイルする

Example with Babelが参考になるが、基本的に Babel でのトランスパイルの部分だけ見ると、サーバレスの webpack だから大きく違うという事はあまりなく、いつも通りの設定をすればいい。

まず Bable の設定だが、以下のようになる。
これは実行環境の Node.js のバージョンに合わせてトランスパイルするという設定になる(targets.nodeを参照)。

// babel.config.js
module.exports = {
  presets: [["@babel/preset-env", { targets: { node: "current" } }]],
};

続いて webpack の設定だが、以下のようになる。
module の設定により babel-loader で Babel を動かし、トランスパイルを行えるようにしている。

const slsw = require("serverless-webpack");
const nodeExternals = require("webpack-node-externals");

module.exports = {
  devtool: "source-map",
  target: "node",
  mode: slsw.lib.webpack.isLocal ? "development" : "production",
  entry: slsw.lib.entries,
  externals: [nodeExternals(), /aws-sdk/],
  module: {
    rules: [
      {
        test: /\.m?js$/,
        include: __dirname,
        exclude: /node_modules/,
        use: { loader: "babel-loader" },
      },
    ],
  },
};

上記の設定において、slsw.lib と externals について少し補足する。

  • slsw.lib
    これはserverless-webpack lib export helperに書かれている通り、サーバレスの設定(serverless.yaml)を利用して簡単にセットアップできるようにするために公開されている lib で、これを利用する事で entry や mode などを上記のように簡単に設定できる
    例えば、entry についていえば、複数の Lambda があるプロジェクトでも、Lambda の数だけ entry を設定する事なく、slsw.lib.entries とするだけで webpack でトランスパイルする Lambda 関数を設定できる。

  • externals
    これはNode modules / externalsに書かれている通り、デフォルトでは webapck は全てのモジュールをバンドルしようとするので、それを防止するための設定。
    Node.js の場合、実行時に node_modules から各依存ライブラリのコードを呼び出して動くので、バンドルする必要はない
    これを行わないとexternalsにあるように、Critical dependency の warn が出てしまう

    一点、注意として、externals で node_modules をバンドルから除外する場合、serverless の deploy 時に node_modules が含まれるようにする必要があるので、以下のように serverless.yaml の方に includeModules: true の設定が必要になる(これをしないと serverless の deploy 時のパッケージに node_modules が含まれなくなり、Lambda が AWS 上で動く際に依存ライブラリが見つからずエラーになる)

custom:
  webpack:
    includeModules: true

※serverless-offline を他の plugin と一緒に利用する場合、Usage with other pluginsに書かれている通り、 "sls offline" コマンドよりも "sls offline start" が推奨される(以下、公式からの引用)。

When combining this plugin with other plugins there are a few things that you need to keep in mind. You should run serverless offline start instead of serverless offline. The start command fires the offline:start:init and offline:start:end lifecycle hooks which can be used by other plugins to process your code, add resources, perform cleanups, etc. このプラグインと他のプラグインを組み合わせる場合、いくつか注意すべき点があります。
serverless offline の代わりに serverless offline start を実行する必要があります。
start コマンドは offline:start:init と offline:start:end ライフサイクルフックを起動し、他のプラグインがコードの処理、リソースの追加、クリーンアップなどの実行に使用することができます。

Node.js で import・export(ES6 の構文)を使えるように webpack × Babel の設定をやってみたでは、@babel/preset-env の設定に target を指定していなかった。
そのため、ES5 の構文にトランスパイルするという設定になっており、core-js と regenerator-runtime を使うの設定をしていたが、Lambda を動かす Node のバージョンに合わせてトランスパイルするのであれば、最低でも Node14.x になると思うので、core-js などを利用して ES5 の構文に変換する必要性はなくなる(Lambda ランタイムにある通り、Node12.x は 2022/11/14 で廃止される)。

webpack でのビルドする際に ESLint のチェックを実行する

続いて、webpack でビルド(トランスパイル)を実行する際に、同時に ESLint でのチェックを実行するための設定を行っていきたいと思う(Node.js のトランスパイル時に ESLint でエラーがあれば Build 停止する設定を Webpack でやってみたなども参照)。

// 省略
const ESLintPlugin = require("eslint-webpack-plugin");

module.exports = {
  // 省略
  plugins: [new ESLintPlugin({ exclude: "node_modules" })],
};

この設定を行った上で、ESLint でエラーになる以下のような実装を行った Lambda 関数をpackageしてみると、webpack のビルドでエラーになり、処理が中断される事が確認できる。

// Lambda
export const handler = async (event) => {
  const hoge = "";
  // 省略
};
study@localhost:~/workspace/learn-serverless (main *)
$ yarn package
yarn run v1.22.19
$ sls package

Packaging aws-node-serverless-project for stage dev (ap-northeast-1)
Environment: linux, node 16.17.0, framework 3.23.0 (local), plugin 6.2.2, SDK 4.3.2
Docs:        docs.serverless.com
Support:     forum.serverless.com
Bugs:        github.com/serverless/serverless/issues

Error:
Webpack compilation failed:

in [eslint]
  /home/study/workspace/learn-serverless/src/lambda.js
    3:7  error  'hoge' is assigned a value but never used  no-unused-vars

  ✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.

エイリアスの設定(webpack、ESLint、VS Code)

Lambda を実装する上で自前の lib などを実装した場合、以下のように相対パスで import する必要がある。
これだとディレクトリが深くなれば見通しが悪くなる。

import library from "./lib/library";

これを'@/library'のようにエイリアスを使って実装できるようにする事で、import 時に相対パスを書かなくてよくなるようにしつつ、見通しが良い状態にするための設定を行う。

エイリアスを利用できるようにするにあたり、webpack と ESLint、エディター(VSCode)の 3 つで設定が必要になる。

webpack の設定

webpack の設定についてはresolve.aliasに書いてある通り、以下のように設定するだけでいい。

const path = require("path");
// 省略

module.exports = {
  // 省略
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src", "lib"),
    },
  },
};

これを行うと、元々何も設定しない時にエラーになっていたもの(以下の画像を参照)が、エラーが出なくなりビルドができるようになる。

webpack のエイリアスの設定後、コードの方は以下のように書けるようになる。

import library from "@/library";

ただこの状況だと、ESLint の方でエラーになってしまう。

これは ESLint 側のエイリアス設定ができていないのが原因なので、続いて ESLint の設定を行っていく。

ESLint の設定

ESLint で webpack のエイリアスの設定によるエラーが出ないようにするにはeslint-import-resolver-webpackを利用する。
設定方法は公式に書かれている通りで、以下のように ESLint の設定を変更すればいい。

{
  // 省略
  "settings": {
    "import/resolver": {
      "webpack": {
        "config": "webpack.config.js"
      }
    }
  }
  // 省略
}

上記のように設定して webpack でビルド(serverless の deploy パッケージ作成)を行うと、エラーなく package コマンドが完了する事が確認できる。

ここまでの設定で最低限、webpack でエイリアスを利用する場合の設定は完了になるが、エディターが VS Code であるなら、次に見ていく設定を行う事でオートコンプリート(サジェスト)を有効にできるので、その設定についてみていく。

VS Code の設定

jsconfig.jsonと呼ばれる VS Code に Javascript プロジェクトとしての情報を教えるための設定ファイルがあるが、これを少し設定する事でオートコンプリートが効くようにしていく。

設定方法はUsing webpack aliasesに書かれている通りで、中身としては以下のようになる。

// jsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/lib/*"]
    }
  },
  "exclude": ["node_modules"]
}

paths の設定により、"@/"で始まるパスは、"src/lib/"と同じであるという事を VS Code に教える事ができ、そのため以下の動画のようにオートコンプリートが効くようになる。

※一点注意として、jsconfig.json は VS Code を開いた時に読み込まれるので、新規に jsconfig.json を作成した場合は、VS Code を再起動(閉じて開き直す)をする必要がある。

まとめ

今回は Node.js の serverless で開発をしていく上での環境設定として、serverless-webpack の設定と、それに付随する ESLint の設定、エイリアスの設定を行ってみた。
基本的には純粋に webpack・Babel を利用してビルド(トランスパイル)する方法と何ら変わないが、entry の書き方が少し省略して書けたり、node_modules の扱いで serverless.yaml 側の設定も必要になったり、若干異なる部分もあった。

次回は今回設定したサーバレスを利用して、キューイングである AWS SQS → AWS SES でメール送信を行うサーバレスアプリケーションを実装してみたいと思う。

※最新の Node.js14.x の Lambda ではUsing Node.js ES modules and top-level await in AWS Lambdaにある通り、package.json に "type": "module" を指定する事で、ES Modules が使えるようになっているので、webpack × Babel の設定を行わずに ES Modules を利用する事もできる。

※今回見てきた webpack × Babel によるトランスパイルの方法は、フロントエンド・バックエンドで ES Modules を利用したい場合に長年行われてきたものになるが、最近はPure ESM packageという考え方で、ES Modules のみでしか利用できないライブラリ(camelcase-keysnanoidなど)も出てきている。
この辺り、そろそろ潮流が変わるのかもしれないな~と感じている。とは言え、まだまだ webpack × Babel の組み合わせで開発している現場は多くあると思うので、今回の内容がどなたかのお役に立つと幸いです。

おまけ

明示的に依存として node_modules に追加する方法

以下のように includeModules を設定する事で、Lambda 関数の実装内で依存しているライブラリを自動的に判定して deploy 時のパッケージに node_modules を含めてくれる。

custom:
  webpack:
    includeModules: true

ただ、上記のような設定では困る場合もある。
例えば、sequelize などの ORM を利用する場合、DB クライアントのライブラリとしてmysql2が必要になるが、これは明示的に Lambda 内で import しないので、自動でパッケージの node_modules に含まれない。

その場合、Forced inclusionに書かれている通り、以下のように設定する事で、強制的にLambda関数の依存に指定したライブラリを追加するように設定する事もできる
(もしLambdaの実行に必要なライブラリがnode_modulesに含まれないと、モジュールが見つけらないというエラーになってしまう)。

custom:
  webpack:
    includeModules:
      forceInclude:
        - myslq2;

《この公式ブロガーの記事一覧》


執筆者プロフィール:Katayama Yuta
認証認可(SHIFTアカウント)や課金決済のプラットフォーム開発に従事。リードエンジニア。
経歴としては、SaaS ERPパッケージベンダーにて開発を2年経験。 SHIFTでは、GUIテストの自動化やUnitテストの実装などテスト関係の案件に従事したり、DevOpsの一環でCICD導入支援をする案件にも従事。その後現在のプラットフォーム開発に参画。

\明日も最新記事を公開/


みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!