💨

最初の1行のコードからライブデプロイまで10分:超高速Nest.jsブログコース

に公開

Cover

これはNest.jsの速習コースです。このチュートリアルでは、わずか数ステップで、10分未満で最初のコード行からデプロイまでのブログを構築します。

これほど速い理由は、このチュートリアルではプロセスの詳細な説明には踏み込まず、代わりに完成品を構築するように直接案内するからです。フレームワークの学習は、既存のプロジェクトを自分のニーズに合わせて変更する方が速いと信じています。

このブログは、純粋なNode.jsバックエンドプロジェクトで一般的なテクノロジースタックを表す3つの機能モジュールで構成されています。

  • Nest.js
  • データベースとしてPostgreSQL
  • ページレンダリングのためにejs

早速始めましょう。

1. プロジェクトの初期化

Nest.jsプロジェクトは、プロジェクト管理のためにCLIツールに大きく依存しています。まず、Nest.js CLIをインストールしましょう。

npm i -g @nestjs/cli

CLIを使用して新しいプロジェクトを作成します。

nest new personal-blog

これにより、personal-blogという名前の新しいフォルダが作成され、必要なすべての依存関係がインストールされます。お好みのエディタでこのディレクトリを開いて、正式に編集を開始してください。

2. PostgreSQLデータベースへの接続

次に、PostgreSQLデータベースを統合します。公式の推奨事項に従って、ORMとしてTypeORMを使用します。ORMの役割は、データベースをコードに統合することです。

依存関係のインストール

npm install @nestjs/typeorm typeorm pg
  • @nestjs/typeorm: TypeORMの公式Nest.jsモジュールで、TypeORMをNest.jsに適応させます。
  • typeorm: TypeORMライブラリ自体。
  • pg: PostgreSQL用のNode.jsドライバーで、Node.jsがPostgreSQLの読み書きを可能にします。

データベースの設定

チュートリアルを高速化するために、ローカルでのデータベースのインストールとセットアップの手順はスキップします。代わりに、オンラインデータベースを直接プロビジョニングします。

Leapcellでワンクリックで無料データベースを作成できます。

Leapcell

ウェブサイトでアカウントを登録した後、「Create Database」をクリックします。

ImageP1

データベース名を入力し、デプロイメントリージョンを選択すると、PostgreSQLデータベースを作成できます。

表示される新しいページで、データベースに接続するために必要な情報が見つかります。下部にはコントロールパネルが用意されており、ウェブページ上で直接データベースを読み取ったり変更したりできます。

ImageP2

データベース接続の設定

src/app.module.tsファイルを開き、TypeOrmModuleをインポートします。

Leapcellからのデータベース設定を使用して接続情報に記入します。ssltrueに設定する必要があることに注意してください。そうしないと、接続が失敗します。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'your_leapcell_host', // Replace with your Leapcell host
      port: 5432,
      username: 'your_postgres_username', // Replace with your PostgreSQL username
      password: 'your_postgres_password', // Replace with your PostgreSQL password
      database: 'personal_blog_db', // Replace with your database name
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true, // Set to true in development, it automatically syncs the database schema
      ssl: true, // Required for services like Leapcell
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Postsモジュールの作成

次に、ブログ投稿を管理するモジュールを作成します。

Nest CLIを使用して、必要なファイルを迅速に生成できます。

nest generate module posts
nest generate controller posts
nest generate service posts

その後、データベースに接続するためにPostエンティティファイルを作成する必要があります。src/postsディレクトリで、post.entity.tsという名前のファイルを作成します。

// src/posts/post.entity.ts
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn } from 'typeorm';

@Entity()
export class Post {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  title: string;

  @Column('text')
  content: string;

  @CreateDateColumn()
  createdAt: Date;
}

次に、データベースに接続する必要があります。

PostsModuleTypeOrmModuleを登録します。src/posts/posts.module.tsを開き、TypeOrmModule.forFeature([Post])をインポートします。

// src/posts/posts.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsController } from './posts.controller';
import { PostsService } from './posts.service';
import { Post } from './post.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Post])],
  controllers: [PostsController],
  providers: [PostsService],
})
export class PostsModule {}

Leapcellのデータベース詳細ページに移動し、Webエディタで次のコマンドを実行して、対応するテーブルを生成します。

CREATE TABLE "post" (
    "id" UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    "title" VARCHAR NOT NULL,
    "content" TEXT NOT NULL,
    "createdAt" TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

最後に、PostsServiceを作成する必要があります。PostsServiceは、投稿に関連するすべてのビジネスロジックを処理する責任があります。src/posts/posts.service.tsを開き、次のコードを追加します。

// src/posts/posts.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Post } from './post.entity';

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Post)
    private postsRepository: Repository<Post>
  ) {}

  findAll(): Promise<Post[]> {
    return this.postsRepository.find({
      order: {
        createdAt: 'DESC',
      },
    });
  }

  findOne(id: string): Promise<Post> {
    return this.postsRepository.findOneBy({ id });
  }

  async create(post: Partial<Post>): Promise<Post> {
    const newPost = this.postsRepository.create(post);
    return this.postsRepository.save(newPost);
  }
}

EJSによるページレンダリングの設定

次に、動的なHTMLページをレンダリングできるようにEJSを設定します。

依存関係のインストール

npm install ejs

ビューエンジンの統合

src/main.tsファイルを開き、次のように変更します。

// src/main.ts
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);

  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('ejs');

  await app.listen(3000);
}
bootstrap();

プロジェクトのルートディレクトリ(srcと同じレベル)に、viewspublicフォルダを作成します。

- personal-blog
    - src
    - views
    - public

フロントエンドページの実装

viewsフォルダに次のファイルを作成します。

  • _header.ejs (再利用可能なヘッダー)

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title><%= title %></title>
        <link rel="stylesheet" href="/css/style.css" />
      </head>
      <body>
        <header>
          <h1><a href="/">My Blog</a></h1>
          <a href="/posts/new" class="new-post-btn">New Post</a>
        </header>
        <main></main>
      </body>
    </html>
    
  • _footer.ejs (再利用可能なフッター)

        </main>
        <footer>
            <p>&copy; 2025 My Blog</p>
        </footer>
    </body>
    </html>
    
  • index.ejs (ブログホームページ)

    <%- include('_header', { title: 'Home' }) %>
    
    <div class="post-list">
      <% posts.forEach(post => { %>
      <article class="post-item">
        <h2><a href="/posts/<%= post.id %>"><%= post.title %></a></h2>
        <p><%= post.content.substring(0, 150) %>...</p>
        <small><%= new Date(post.createdAt).toLocaleDateString() %></small>
      </article>
      <% })
      %>
    </div>
    
    <%- include('_footer') %>
    
  • post.ejs (投稿詳細ページ)

    <%- include('_header', { title: post.title }) %>
    
    <article class="post-detail">
      <h1><%= post.title %></h1>
      <small><%= new Date(post.createdAt).toLocaleDateString() %></small>
      <div class="post-content"><%- post.content.replace(/\n/g, '<br />') %></div>
    </article>
    <a href="/" class="back-link">&larr; Back to Home</a>
    
    <%- include('_footer') %>
    
  • new-post.ejs (新規投稿ページ)

    <%- include('_header', { title: 'New Post' }) %>
    
    <form action="/posts" method="POST" class="post-form">
      <div class="form-group">
        <label for="title">Title</label>
        <input type="text" id="title" name="title" required />
      </div>
      <div class="form-group">
        <label for="content">Content</label>
        <textarea id="content" name="content" rows="10" required></textarea>
      </div>
      <button type="submit">Submit</button>
    </form>
    
    <%- include('_footer') %>
    

2. CSSスタイルの追加

public/css/style.cssに簡単なスタイルを追加します。

/* public/css/style.css */
body {
  font-family: sans-serif;
  line-height: 1.6;
  margin: 0;
  background-color: #f4f4f4;
  color: #333;
}
header {
  background: #333;
  color: #fff;
  padding: 1rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
header a {
  color: #fff;
  text-decoration: none;
}
main {
  max-width: 800px;
  margin: 2rem auto;
  padding: 1rem;
  background: #fff;
  border-radius: 5px;
}
.post-item {
  margin-bottom: 2rem;
  border-bottom: 1px solid #eee;
  padding-bottom: 1rem;
}
.post-item h2 a {
  text-decoration: none;
  color: #333;
}
.post-detail .post-content {
  margin-top: 1rem;
}
.new-post-btn {
  background: #5cb85c;
  padding: 0.5rem 1rem;
  border-radius: 5px;
}
.post-form .form-group {
  margin-bottom: 1rem;
}
.post-form label {
  display: block;
  margin-bottom: 0.5rem;
}
.post-form input,
.post-form textarea {
  width: 100%;
  padding: 0.5rem;
}
.post-form button {
  background: #337ab7;
  color: #fff;
  padding: 0.7rem 1.5rem;
  border: none;
  cursor: pointer;
}
footer p {
  text-align: center;
}

バックエンドとフロントエンドページの接続

HTTPリクエストを処理し、EJSテンプレートをレンダリングするために、src/posts/posts.controller.tsを更新します。

// src/posts/posts.controller.ts
import { Controller, Get, Render, Param, Post, Body, Res } from '@nestjs/common';
import { PostsService } from './posts.service';
import { Response } from 'express';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  @Render('index')
  async root() {
    const posts = await this.postsService.findAll();
    return { posts };
  }

  @Get('new')
  @Render('new-post')
  newPostForm() {
    return;
  }

  @Post()
  async create(@Body() body: { title: string; content: string }, @Res() res: Response) {
    await this.postsService.create(body);
    res.redirect('/posts');
  }

  @Get(':id')
  @Render('post')
  async post(@Param('id') id: string) {
    const post = await this.postsService.findOne(id);
    return { post };
  }
}

次に、ルートパス/がブログホームページにリダイレクトされるようにsrc/app.controller.tsを更新します。

// src/app.controller.ts
import { Controller, Get, Res } from '@nestjs/common';
import { Response } from 'express';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  root(@Res() res: Response) {
    return res.redirect('/posts');
  }
}

ブログの実行

ブログを開始するには、ターミナルで次のコマンドを実行します。

npm run start:dev

ブラウザでhttp://localhost:3000を開いてブログページを表示します。新しい投稿を書いてみてください!

ImageP3

ImageP4

これで、ウェブサイトとAPIを自由にカスタマイズして、Nest.jsの理解を深めることができます。

ブログのオンラインデプロイ

さて、自分で作ったウェブサイトを他の人に見せて、誰でもアクセスできるようにするにはどうすればよいか考えているかもしれません。

以前データベースを作成するために使用したLeapcellを覚えていますか?Leapcellはデータベースを作成するだけでなく、Nest.jsを含むさまざまな言語やフレームワークのプロジェクトをホストできるWebアプリケーションホスティングプラットフォームでもあります。

Leapcell

以下の手順に従ってください。

  1. プロジェクトをGitHubにコミットします。GitHubの公式ドキュメントを参照して手順を確認してください。Leapcellは後でGitHubリポジトリからコードをプルします。
  2. Leapcellページで「Create Service」をクリックします。
    ImageP5
  3. Nest.jsリポジトリを選択すると、Leapcellが必要な構成を自動的に入力します。
    ImageP6
  4. 下部にある「Submit」をクリックしてデプロイします。デプロイはすぐに完了し、デプロイメントホームページに戻ります。ここで、Leapcellがドメインを提供していることがわかります。これがブログのオンラインアドレスです。
    ImageP7

これで、このリンクを友人と共有すれば、誰もがオンラインであなたのブログを見ることができます!


Xでフォローする:@LeapcellJP


ブログでこの記事を読む

関連記事:

Discussion