LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

バックエンドが要らない手軽なサイトをNext.jsで作ってみた【サイト公開編】

この記事はLCL Advent Calendar 2020 - 20日目です。

qiita.com

日にちが空いてしまいましたが前回の記事の続きを進めていきます。
まだ読まれてない方はこちらから先にご覧ください。

techblog.lclco.com

さっそくUIを実装していく

まず 初期生成された index.tsx の余計なコードを消しておきます。

import { Container } from '../components/Container'

const Index = () => (
  <Container height="100vh">
  </Container>
)

export default Index

今回はChakra UIを使ってUIを組み立てていきます。 ゼロから組み合わせるのも面倒なので専用のビルダーツールを使ってとことんラクをします。

https://openchakra.app/openchakra.app

f:id:yamshta:20201217182008p:plain

サイト名を表示するコンポーネントを追加

ビルダーツールで生成したコードを利用してHeroコンポーネントを編集します。
fontSizeが配列になっているのはブレイクポイントに合わせてレスポンシブに大きさを変えるためです。Chakra UI、気が利いてますね。

chakra-ui.com

f:id:yamshta:20201217182027p:plain

Headタグを追加

faviconとタイトルくらいは設定しておきたいので index.tsx にHeadタグを追加します。

import Head from "next/head"

import { Container } from '../components/Container';
import { Hero } from '../components/Hero';

const Index = () => {
  return (
    <Container>
      <Head>
        <title>Remote 🏠 Sale|Amazonレビュー★4以上のリモートワークが捗る製品情報をお届け  </title>
        <meta charSet="utf-8" />
        <meta name="viewport" content="initial-scale=1.0, width=device-width" />
        <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡️</text></svg>" />
      </Head>
      <Hero />
    </Container>
  )
}
export default Index

先程のHeroコンポーネントも読み込むと以下のように表示されます。

f:id:yamshta:20201217182053p:plain

製品データ(JSON)を読み込む

次に前記事で生成した製品データ(JSON)を読み込みます。
と言っても、大したことはしません。普通にimportするだけです。

import saleSections from '../../.contents/saleSections.json';

TypeScriptを使っているので型定義を追加し、キャストしてあげれば値として扱えます。
配列になっているのでmapでループを回しつつ、コンポーネントに渡してあげます。

export type SaleSection = {
  title: string;
  items: SaleItem[];
}

...

<Container>
  ...
  <Hero />
  {(saleSections as SaleSection[]).map((saleSection, index) => (
    <Section props={saleSection} key={index} />
  ))}
</Container>

製品を表示するコンポーネントを追加

これについてはもう細かい説明は不要だと思いますのでスクショでベタっと紹介します。

index.tsx で参照されているのはSectionコンポーネントで、その中で更に使い回している部分をItemコンポーネントとして分割しています。コンポーネントは必ずしもファイルで分ける必要はないのです。

useColorModeは前回の記事で触れたとおりですね。折角なので使ってみました。index.tsx でDarkModeSwitchコンポーネントを読み込んで表示しておきます。

f:id:yamshta:20201217182250p:plain

拍子抜けなことにこれでNext.jsの実装は以上になります。

f:id:yamshta:20201217182307p:plain

醍醐味であるgetStaticPathsgetStaticPropsgetServerSidePropsは一切でてこず、その他の機能も使わずに終わってしまいました(汗)

あまりにも薄すぎてしまうので、次の記事ではNext.jsのImageコンポーネントやSEOの設定だったりを追加していきたいと思っています。

この記事はデプロイの設定をして終わりです。それでは続きます。

Vercelにデプロイ

まず、GitHubにリポジトリを作っていなかったので用意してPUSHします。
次にVercelのアカウントを作ってなかったので登録します。

https://vercel.com/signup

そしてVercelでリポジトリをインポートします。

GitHub連携の権限が許可されてないようで怒られました。
リンク先のGitHubから変更します。皆さんも気を付けてください。

f:id:yamshta:20201217182328p:plain

アクセス権限を与えたら次にプロジェクトをインポートします。
このタイミングで.envで管理していた環境変数を登録。

f:id:yamshta:20201217182341p:plain

このままだとまだbuildコマンドの設定を追加していなかったのでデプロイが失敗します。
複数のコマンドを実行できる「npm-run-all」を追加し、package.jsonのscriptsを以下のように変更します。

$ yarn add npm-run-all --dev
  "scripts": {
    "dev": "next dev",
    "build": "run-s build:posts build:next",
    "build:posts": "ts-node --project tsconfig.builder.json ./src/builder/items.ts",
    "build:next": "next build",
    "start": "next start"
  },

型でエラーになってしまうので tsconfig.json のexcludeにbuilder配下を除外する設定を追加します。

  "exclude": ["node_modules", "src/builder/*.ts"],

これを変更をPUSHすると自動でデプロイがされて... サイトが公開されました!!

f:id:yamshta:20201217182357p:plain

https://remote-sale.vercel.app/

定期デプロイの設定

1日1回データを更新したいのでGitHub Actionsの「cron」を使い自動デプロイを設定します。

vercel.com

有志で開発されているこちらのActionを使ってVercelへデプロイします。

github.com

.github/workflows/deploy.yamlを追加します。

name: deploy
on:
  schedule:
    - cron: '0 10 * * *' # 毎日10時00分(UTC)に実行
  workflow_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID}}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID_STATIC}}
      - name: preview-url
        run: |
          echo ${{ steps.vercel-action.outputs.preview-url }}

cronだと任意のタイミングで実行できないので、手動実行できるworkflow_dispatchをトリガーに含めておくと動作確認や再実行がしやすくなります。

github.blog

環境変数を設定

vercel-token: ${{ secrets.VERCEL_TOKEN }}

このトークンは以下のページから生成します。

vercel.com

f:id:yamshta:20201217182453p:plain

vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID_STATIC }}

これらの値は Vercel CLI を利用して以下の値を取得します。

$ yarn global add vercel
$ vercel
Vercel CLI 21.0.1
? Set up and deploy “~/workspace/github.com/yamshta/remote-sale”? [Y/n] y
? Which scope do you want to deploy to? Shunya Yamashita
? Found project “yamshta/remote-sale”. Link to it? [Y/n] y
🔗  Linked to yamshta/remote-sale (created .vercel)
🔍  Inspect: https://vercel.com/yamshta/remote-sale/27rjye3sf [4s]
✅  Preview: https://remote-sale.yamshta.vercel.app [copied to clipboard] [42s]
📝  To deploy to production (remote-sale.vercel.app), run `vercel --prod`

設定が完了すると.vercelディレクトリとその配下に project.json が追加されます。プロジェクトの組織ID(vercel-org-id)とプロジェクトID(vercel-project-id)の両方が含まれているのでGitHubのSecretsに登録しましょう。

f:id:yamshta:20201217182509p:plain

これで定期/手動実行ができるようになります。

補足:Vercelの自動デプロイを無効化

もし、GitHub Actionsのトリガーでしかデプロイしたくない場合はルート配下にvercel.jsonを追加して以下のように記述するとVercelの自動デプロイが無効化されます。

https://vercel.com/guides/upgrade-to-zero-configuration

{
  "github": {
    "enabled": false
  }
}

以上で、データの準備から実装、デプロイまでの一通りが終わりました。

簡単なペライチサイトとはいえ、色々なツールやパッケージのおかげで殆ど実装せず安全無料で世の中に公開できました。この開発体験は素晴らしいですね。

次の記事ではもう少しだけ実用的な実装をいくつか追加していきたいと思います。

remote-sale.vercel.app