はじめに

WEBコンテンツの配信にはS3の静的ウェブホスティングなどを使用しますが、Lambdaでもコンテンツの配信が可能です。NestJSのライブラリを使用すると簡単に実現できるので、その方法をご紹介します。

ファイル構成

一般的なNestJsの構成に、今回は”public”というディレクトリーを追加します。

01
02
03
04
05
06
07
08
.
├── public
├── src
│  ├── app.controller.ts
│  ├── app.module.ts
│  └── handler.ts
├── package.json
└── serverless.yml

実装

”@nestjs/serve-static”というライブラリを使用して、指定したディレクトリー内のファイルに直接アクセスできるようにします。

app.module.ts

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { AppController } from './app.controller';
 
@Module({
  controllers: [AppController],
  imports: [
    ServeStaticModule.forRoot({
      rootPath: `${__dirname}/../public`,
    }),
  ],
});
 
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply().forRoutes(AppController);
  }
}

rootPathpublicディレクトリーを設定することで、public内のファイルにドメイン + ファイルパスでアクセスできるようになります。例えば、Vue.jsで作成したSPAをpublicに配置すればSPAがそのまま動作します(SPA内のルーテイングも有効です)。

これだけだとファイル名を指定してアクセスする形になります(https://xxxxxxxxxx.com/xxxx.html など)。APIのパスでアクセスさせたい場合や、コンテンツ表示前に何らかの処理を挟みたい場合はコントーラーで制御します。

app.controller.ts

01
02
03
04
05
06
07
08
09
10
11
import { Controller, Get } from '@nestjs/common';
import { Response } from 'express';
 
@Controller()({
export class AppController {
  @Get('/hoge')
  hoge(@Res() res: Response) {
    -- 何らかの処理 --
    return res.sendFile(`${__dirname}/../public/xxxx.html`);
  }
}

特定のパスに対する処理の中でpublic内のファイルをreturnで返すようにします。その手前に処理を書き込む事により様々な制御が可能になります。

注意点

index.htmlなどでfaviconやjs、cssを読み込む際には”/favicon.ico”のように指定すると思います。この場合、読み込むfaviconのURLはhttps://xxxxxxx.com/favicon.icoとなります。例えばAPI GatewayでtestというステージにデプロイしAPI Gatewayのエンドポイントを使用するとします。index.htmlにアクセスするURLはhttps://xxxxxxx.com/test/index.htmlです。faviconのURLも同様にtestというパスが必要になるので、https://xxxxxxx.com/test/favicon.icoになります。が、index.htmlの中では”/favicon.ico”と指定しているのでhttps://xxxxxxx.com/favicon.icoにアクセスしようとします。faviconにアクセスする正しいURLはhttps://xxxxxxx.com/test/favicon.icoなので、404のエラーが発生します。よって、index.htmlの記述を”/test/favicon.ico”に変更しなければなりません。これに限らず、ローカルで起動する際などにもドメインの後ろに何らかのパスが追加される場合には同様の対処が必要になります。

最後に

LambdaではAPIやバッチなどを作成することが多いと思いますが、小難しい設定などは必要なくライブラリと少しの記述の追加で簡単にWEBコンテンツを配信することもできます。特殊な条件下であったり何らかの理由でS3のバケットを増やせない際には手っ取り早く代用できると思います。