LoginSignup
0
0

DetaにNestJS、Angularの成果物をプッシュする手順

Last updated at Posted at 2023-07-05

DetaにNestJS、Angularの成果物をプッシュする手順

Detaとは

当方はHeroku無料枠廃止に伴うニュースから代替となるサービスの記事で知りました。感謝です。

Detaは無料でアプリをデプロイできるサービスです。
Deta Space

(Google翻訳)
...
Space では開発は無料です。私たちは、開発者が他の人のために自分のアイデアを実行するコンピューターを構成、管理したり、料金を支払ったりする必要はないと考えています。また、エンドユーザーはデフォルトで自分のものに対して自由に開発できるべきだと考えています。
...

(原文)
...With Space, development is free. We don’t think developers should have to configure, manage, or pay for the computer that runs their idea for other people. We also think that end-users should have the freedom to develop against their own stuff, by default.
...
For doers & dreamers

パーソナルクラウドなる標語を提唱しており、当方の語彙力ではお伝え出来ないですが、AWS、Azure、GCPとは異なる思想を持っているようです。失礼を承知で申し上げると、そこはかとなく漂うB級感がとても好みです。まだまだマイナーな存在のようで、Googleでdetaを検索しても検索結果に公式が上がってきません。

下図はhttps://deta.space/motivation/の画面の抜粋です。
キャプチャ (小).GIF

当記事のきっかけ

The Space Runtime
上記Detaのドキュメントに

(Google翻訳)Deta Space には、ほぼすべての種類のアプリを実行できる独自のランタイムである Space Runtime があります。たとえば、Space Runtime は以下をサポートします。

  • React、Vue、Svelteなどのフレームワークで構築されたフロントエンド サイト
  • Next、Nuxt、SvelteKitなどのフルスタック フレームワーク
  • Node.js、Python、さらには Go、Rust、またはよりカスタムなもので構築されたバックエンド アプリ

個々の Space アプリは、これらのさまざまなテクノロジーを組み合わせて構築できます。たとえば、SvelteKit アプリと Go API、Next.js アプリと Python API など、最大 5 つの異なる言語とフレームワークを組み合わせて構築できます。
(原文)Deta Space has its own runtime, the Space Runtime, that can run almost any type of app. For example, the Space Runtime supports:

  • frontend sites built with frameworks like React, Vue, and Svelte
  • full-stack frameworks like Next, Nuxt, or SvelteKit
  • backend apps built with Node.js, Python and even Go, Rust or something more custom

An individual Space app can be built by combining these different technologies, for example, a SvelteKit app with a Go API or a Next.js app with a Python API — really any combination of up to 5 different languages and frameworks.

とあります。NestJSはNode.jsで構築されたバックエンドに含まれると思います。かなしいかなAngularが列挙されていません。
当記事は自分なりに試してサーバーサイドNestJS、フロントサイドAngularの成果物をDetaにプッシュした手順を記します。

注意

Detaのアカウントの作成が済んでいる状態からの手順になります。
当記事では、成果物を外部に公開するところまでは試していません。
当記事の手順で進めたのち、  

space release

コマンドを実行すると、公開できるはずです。
試しに実行してみたところ、以下のように聞かれました。

Releasing makes your app available via a unique link for others to install and use.
If you only want to use this app yourself, use your Builder instance instead.
? Are you sure you want to release this app to others? (y/n) n
Aborted releasing this app.
(Google翻訳) リリースすると、他の人が独自のリンクを介してアプリをインストールして使用できるようになります。
このアプリを自分だけで使用したい場合は、代わりに Builder インスタンスを使用してください。

実行したとてAngularのテンプレートアプリが表示されるだけなので、それを公開するというのも忍びなく、キャンセルしてしましました。いずれ自信をもって公開できるもの作ろうと思います。
以上の通り、公開までは試しておりません。それでもよろしければ読み進めていただければと思います。

環境

Windows10
WSLストア版

手順

まずは理屈はおいておいて、当方がDetaにNestJS+Angularの成果物をDetaにプッシュできた手順を記し、後に設定の根拠を記します。

Dockerfile

Dockerfile
FROM node:16.20.1

ENV LANG=C.UTF-8
ENV LANGUAGE=en_US:

RUN apt-get update && apt-get install nano

# Space CLIのインストールと環境変数の設定
RUN curl -fsSL https://deta.space/assets/space-cli.sh | sh
ENV PATH $PATH:/root/.detaspace/bin
RUN echo $PATH

RUN mkdir /app
WORKDIR /app

Dockerイメージ作成

イメージ名deta、タグnode-16.20.1でDockerイメージを作成しました。

docker build -t deta:node-16.20.1

Dockerコンテナ作成

docker run --name deta-nest-angular -v /development/deta-nest-angular:/app -w /app -p 4200:4200 -p 3000:3000  -itd --dns 8.8.8.8 deta:node-16.20.1

DetaSpaceのアクセストークンを取得

DetaSpaceのアクセストークンを取得します。
image.png

Generate Tokenをクリックします。
image.png

生成されたトークンが表示されます。トークンが表示されるタイミングはこの時のみです。外部に漏れないように控えてください。

開発環境とDetaを連結

以下はコンテナ内の作業です。
space loginコマンドを実行し、DetaSpaceにログインします。

space login

# 以下のようにトークンを聞かれるので、上の手順で取得したアクセストークンをコピペします。
To authenticate the Space CLI with your Space account, generate a new access token in your Space settings and paste it below:

? Enter access token (0 chars) >

# トークンを入力してアクセスに成功すると以下の表記になりました。  
? Enter access token (41 chars) > ***************************************** 
👍 Login Successful!

Checking for new Space CLI version...
                                                                     
i New Space CLI version available, upgrade with space version upgrade

コンテナ内での作業

VSCodeで作成したコンテナ内に入ります。
以下のように構成していきます。

app/
  ├front-side/       # Angularのプロジェクトディレクトリ
  │  ├node_modules/
  │  ├package.json
  │  ...
  ├server-side/      # NestJSのプロジェクトディレクトリ
  |  ├app/           # Angularのデプロイ先
  │  ├node_modules/
  │  ├package.json
  │  ...  
  ├node_modules/     # プロジェクトのルートディレクトリに@angular/cli、@nestjs/cliをインストール
  ├package.json
  └Spacefile         # DetaSpaceの設定ファイル
# プロジェクト初期化
npm init -y
# プロジェクトのルートディレクトリで@angular/cliと@nestjs/cliをインストールします。  
npm install --save-dev @angular/cli @nestjs/cli
# Angularのテンプレートプロジェクトを生成します。
npx ng new front-side
# NestJSのテンプレートプロジェクトを生成します。
npx nest new server-side

Angluarのビルド先をNestJSのプロジェクトディレクトリ直下に設定します。

angular.json
{
  ...
  "projects": {
    "front-side": {
      ...
      "architect": {
        "build": {
          ...
          "options": {
            "outputPath": "../server-side/app" #←ここ
          }
        }
      }
    }
  }
}

NestJSでAngularのビルド結果を提供できるように、@nestjs/serve-staticをインストールし、設定します。

cd /app/server-side

npm install @nestjs/serve-static

app.module.tsを修正します。

server-side/src/app.module.ts
...
import { ServeStaticModule } from '@nestjs/serve-static'
import { join } from 'path';

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: join(__dirname, '../app'), 
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

ブラウザでNestJSで作成したサーバーにアクセスし、Angularで作成した画面が表示されるか確認します。
フロントサイドをビルドします。先ほどのangular.jsonでビルド先を変更したので、server-side/appディレクトリにビルドされます。

cd /app/front-side
npm run build

localhost:3000にアクセスしたとき、Hello world!の表示ではなくAngularの成果物が表示されるように、server-side/src/app.controllerを修正します。

server-side/src/app.controller.ts
@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  /* この部分をコメントアウトします。
  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
  */
}

またサーバーを起動する際のポートは環境変数から取得するようにserver-side修正します。
Detaで実行する為に必要です。

(Google翻訳) アプリがPORT環境変数で定義されたポートをリッスンするように構成されていることを確認してください。
(原文💡 Make sure your app is configured to listen on the port defined by the PORT environment variable.)
Deta公式(Run a Node.js App)

server-side/src/main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // ポートを環境変数から取得するようにする。
  const port = process.env.PORT || 3000;
  await app.listen(port);
}

NestJSのテストサーバーを起動します。

cd /app/serve-side
npm run start:dev

ブラウザでhttp://localhost:3000にアクセスしAngularの画面が表示されます。

NestJSのビルド時、Webpackを使用して単一ファイルになるように設定します。
※デフォルトの状態でビルドしたものだと、Detaにアップロード後実行できませんでした。単一ファイルになる様にし、node server-side/main.jsで起動できるようにすることで実行できました。

server-side/package.json
{
  ...
  "scripts": {
    "build": "nest build --builder webpack", 
    "start:dev": "nest start --watch --builder webpack", 
    ...
  }
}
server-side/webpack.config.js
const { NODE_ENV = 'production' } = process.env;
module.exports = {
  target: 'node',
  mode: NODE_ENV,
  externals: [
    {
      '@nestjs/websockets/socket-module': 
        'commonjs2 @nestjs/websockets/socket-module',
      '@nestjs/microservices/microservices-module': 
        'commonjs2 @nestjs/microservices/microservices-module',
      '@fastify/static': 'commonjs2 @fastify/static'
    },
  ],
  optimization: {
    minimize: false,
  },
};

プロジェクトのルートディレクトリから、ビルド、開発サーバーでの起動、通常起動が出来るようにpackage.jsonscriptsを設定します。ここで設定したスクリプトをこの後にでてくるSpacefileに設定します。

/app/package.json
{
  ...
  "scripts": {
    "build": "npm run build:front-side && npm run build:server-side", 
    "build:front-side": "cd front-side && npm run build", 
    "build:server-side": "cd server-side && npm run build", 
    "start:dev": "npm run dev:front-side & npm run dev:server-side", 
    "dev:front-side": "cd front-side && ng serve --host 0.0.0.0 --poll 2000", 
    "dev:server-side": "cd server-side && npm run start:dev", 
    "start": "node server-side/dist/main.js"
  }, 
  ...
}

space newコマンドを実行

コンテナ内の作業です。
プロジェクトルートディレクトリで、space newコマンドを実行します。

# プロジェクトルートディレクトリに移動
cd /app

space new

# 生成するプロジェクト名を聞かれるので入力します。
# 当例ではfirst-deta-appとしました。
? What is your projects name? > first-deta-app

# yを選択します。
? Do you want to setup "first-deta-app" with this configuration? (Y/n)

処理が完了すると、.spaceディレクトリ、Spacefileが作成され、.gitignoreに.spaceが追記されます。
Spacefileを以下のように修正します。

Spacefile
v: 0
micros: 
  - name: first-deta-app
    src: ./server-side
    engine: nodejs16
    include:
      - app
      - dist
    run: node dist/main.js
    commands: 
      - npm run build
    dev: npm run start:dev
    primary: true
    public: true

space pushコマンドを実行

いよいよ、Detaにpushします。

space push

# 成功するとURLが表示されます。  
Validating your Spacefile...
                                                     
Your Spacefile looks good, proceeding with your push!

✓ Successfully started your build!
✓ Successfully pushed your Spacefile!
...
省略
...
✓ Successfully pushed your code and updated your Builder instance!
Builder instance: https://firstdetaapp-1-t7712186.deta.app

表示されるURLにアクセスすると、Angularの画面が表示されるはずです。
またdeta.spaceのキャンバス画面を確認すると、開発中のアプリのアイコンが追加されています。
image.png

以上です。

設定の根拠

Dockerfile

Dockerfile(再掲)
FROM node:16.20.1

ENV LANG=C.UTF-8
ENV LANGUAGE=en_US:

RUN apt-get update && apt-get install nano

# Space CLIのインストールと環境変数の設定
RUN curl -fsSL https://deta.space/assets/space-cli.sh | sh
ENV PATH $PATH:/root/.detaspace/bin
RUN echo $PATH

RUN mkdir /app
WORKDIR /app

Dockerイメージにnode:16.20.1を選定した理由は、公式ドキュメントに以下のような記載がありました。

(Google翻訳) 💡 現在、Space は Node.js 16 のみをサポートしていますが、間もなく Node.js 18 のサポートを追加する予定です。nvmなどのノード バージョン マネージャーを使用して、コンピューターに Node.js と npm をインストールすることをお勧めします。これにより、さまざまなバージョンの Node.js をすばやくインストールして使用できるようになります。
(原文)💡 Currently, Space only supports Node.js 16, with plans to add support for Node.js 18 soon. We recommend using a Node version manager like nvm to install Node.js and npm on your computer. This will allow you to quickly install and use different versions of Node.js.

DockerHubでNode.js16系統で一番新しいバージョンナンバーのイメージを選びました。
Space CLIのインストールと環境変数の設定の部分は公式サイトのこちらにあるようにDeta Space用のアプリを構築するのに必要なため、Dockerコンテナ生成時にSpace CLIがインストールされるように設定しました。
下に続く環境変数の設定ですが、公式にある通りRUN curl -fsSL https://deta.space/assets/space-cli.sh | shコマンドでインストールすると、以下のように環境変数の設定を促すメッセージが表示されます。

  inflating: /root/.detaspace/bin/space
Deta Space CLI was installed successfully to /root/.detaspace/bin
Manually add /root/.detaspace/bin to your path:
  export PATH="/root/.detaspace/bin:$PATH"

  Run 'space --help' to get started

そのため環境変数の設定を含めました。

NestJSについてWebpackでビルドする理由

通常通りビルドしてDetaにプッシュすると、下図のようなエラーが発生しました。
server-side/package.jsonとプロジェクトルートのpackage.jsonscriptsを元の状態に近い以下のようにしてpushしてみます。

/app/server-side/package.json
{
  ...
  "scripts": {
    //"build": "nest build --webpack", 
    "build": "nest build", 
    ...
  }
}
/app/package.json
{
  ...
  "scripts": {
    ...
    //"start": "node server-side/dist/main.js", 
    "start": "cd server-side && nest start", 
    ...
  }
}
space push

プッシュ自体は成功しますが、URLにアクセスすると、以下の表示になります。
image.png

webpackを用いて単一ファイルになる様にビルドし、node server-side/dist/main.jsコマンドで起動するようにしたところ、回避されました。
webpackの設定は下記のサイトを参考にさせていただきました。
NestJSアプリケーションをwebpackでBundle【> 404 motivation not found】

webpack.confi.jsのexlternalsへの記載方法

webpack.config.jsを再掲します。
先述の参考サイトに載っていたものを元に作っております。
当方、externalsに載っている項目はどのように設定しているのかわかりませんでした。

server-side/webpack.config.js
const { NODE_ENV = 'production' } = process.env;
module.exports = {
  target: 'node',
  mode: NODE_ENV,
  externals: [
    {
      '@nestjs/websockets/socket-module': 
        'commonjs2 @nestjs/websockets/socket-module',
      '@nestjs/microservices/microservices-module': 
        'commonjs2 @nestjs/microservices/microservices-module',
      '@fastify/static': 'commonjs2 @fastify/static'
    },
  ],
  optimization: {
    minimize: false,
  },
};

ChatGPT大先生に伺ったところ、ビルドしてエラーになったものを記述する、とのことでした。
試しにexternalsを空にしてビルドを実行してみます。

server-side/webpack.config.js
...
module.exports = {
  target: 'node',
  mode: NODE_ENV,
  externals: [
    {
      //空
    },
  ], 
...

server-sideディレクトリでnpm run buildを実行します。

npm run build

# 以下のエラーが発生します。  
> server-side@0.0.1 build
> nest build --builder webpack

ERROR in ./node_modules/@nestjs/core/nest-application.js 19:107-150
Module not found: Error: Can't resolve '@nestjs/websockets/socket-module' in '/app/server-side/node_modules/@nestjs/core'
 @ ./node_modules/@nestjs/core/index.js 26:21-50
 @ ./src/main.ts 3:15-38

ERROR in ./node_modules/@nestjs/core/nest-application.js 20:124-177
Module not found: Error: Can't resolve '@nestjs/microservices/microservices-module' in '/app/server-side/node_modules/@nestjs/core'
 @ ./node_modules/@nestjs/core/index.js 26:21-50
 @ ./src/main.ts 3:15-38

ERROR in ./node_modules/@nestjs/serve-static/dist/loaders/fastify.loader.js 19:113-139
Module not found: Error: Can't resolve '@fastify/static' in '/app/server-side/node_modules/@nestjs/serve-static/dist/loaders'
 @ ./node_modules/@nestjs/serve-static/dist/index.js 20:13-48
 @ ./node_modules/@nestjs/serve-static/index.js 6:9-26
 @ ./src/app.module.ts 13:23-54
 @ ./src/main.ts 4:21-44

エラー内容から、

  • @nestjs/websockets/socket-module
  • @nestjs/microservices/microservices-module
  • @fastify/static

を拾い、それをwebpack.config.jsexternalsに列挙します。
エラーのあったモジュール名 : commonjs2 ○○(○○はエラーのあったモジュール名)
という形式で列挙します。

server-side/webpack.config.js
...
  externals: [
    {
      '@nestjs/websockets/socket-module': 
        'commonjs2 @nestjs/websockets/socket-module',
      '@nestjs/microservices/microservices-module': 
        'commonjs2 @nestjs/microservices/microservices-module',
      '@fastify/static': 'commonjs2 @fastify/static'
    }
  ]
...

以上です。

感想等

Detaの公式を読むと(原文は英語で私読めないのでGoogle翻訳して読んでいます。)、なにかこう、とても応援したくなるサービスです。
記事を書いている2023/07/05現在、公式ブログの最新は2023/2/23で、What's newの最新は2023/04/27なので、あまり活発とは見受けられないのですが、どんどん発展して欲しいと願っています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0