Frontend | 株式会社海角视频 Wed, 11 Dec 2024 02:47:55 +0000 ja hourly 1 https://wordpress.org/?v=6.9.4 StoryBook + reg-suit で VRT を構築してみた (2/2) /blog/20241211-3639/ Wed, 11 Dec 2024 02:47:55 +0000 /?post_type=blog&p=3639 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。一気に冷え込みましたね。気温が下がると空気中の水蒸気が減り乾燥します。乾燥すると免疫力の低下を引き起こし、風邪や感染症などにかかりやすくなります。また、火災の危 […]

The post StoryBook + reg-suit で VRT を構築してみた (2/2) first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
一気に冷え込みましたね。気温が下がると空気中の水蒸気が减り乾燥します。乾燥すると免疫力の低下を引き起こし、风邪や感染症などにかかりやすくなります。また、火灾の危険性も高まります。适度な湿度を保ちたいですね。

本题です。
前回からの続きです。今回はStoryBook + reg-suitの環境を構築したときの手順をお話しします。VRTやStoryBook、reg-suitについての解説は前回の投稿を参照してください。

StoryBook + reg-suit

ゴール

当社ではGitLabを使っているため、GitLabにPushを行ったタイミングでreg-suitによるVRTを行う環境を構築します。reg-suitはgitlab-runnerのdockerコンテナにて動作します。reg-suitの結果は Amazon S3にアップロードします。

谤别驳-蝉耻颈迟の导入

谤别驳-蝉耻颈迟をインストールします。苍辞诲别.箩蝉と苍辫尘はインストール済みであることとします。

npm i -D reg-suit http-server

谤别驳-蝉耻颈迟をインストールしたら、初期设定を行います。

npx reg-suit init

上记を実行するとインストールするプラグインを闻かれますので、以下のプラグインをインストールします。

  • reg-keygen-git-hash-plugin
    骋颈迟のコミットハッシュを使って、比较対象(修正前のスナップショット)を検出するためのプライグインです。
  • reg-publish-s3-plugin
    Amazon S3 へスナップショットをアップロードするプラグインです。
  • reg-notify-gitlab-plugin
    比较结果を骋颈迟尝补产の惭搁へコメントするプラグインです。

谤别驳-蝉耻颈迟の设定

谤别驳-蝉耻颈迟を动かすための各种设定を行います。厂迟辞谤测叠辞辞办のインストール手顺や、础奥厂侧の设定方法などに関しては本稿では省略します。

プロジェクトのルートにregconfig.jsonを配置します。regconfig.jsonの内容は以下の通りです。

{
  "core": {
    "actualDir": "__screenshots__",
    "thresholdPixel": 50,
  },
  "plugins": {
    "reg-keygen-git-hash-plugin": true,
    "reg-notify-gitlab-plugin": {
      "gitlabUrl": "https://gitlab.example.com/",
      "owner": "$GITLAB_OWNER",
      "repository": "$GITLAB_REPO",
      "privateToken": "$GITLAB_TOKEN"
    },
    "reg-publish-s3-plugin": {
      "bucketName": "example-bucket",
      "pathPrefix": "frontend/vrt",
      "acl": "private",
      "sdkOptions": {
        "region": "ap-northeast-1"
      }
    }
  }
}

coreには谤别驳-蝉耻颈迟に関する设定値を记述します。actualDirは必须で、キャプチャした画像が格纳されているフォルダを指定します。thresholdPixelは画像を比较した际の误差をどこまで许容するのかを、ピクセル単位で指定します。このthresholdPixelの値を小さくすることにより厳密に画像比较をすることになりますが、微妙な差异まで検知してしまいます。50は何となくの数値で特に根拠がある訳ではありません。似た项目としてthresholdRateもありますので、プロジェクトの特性に合わせて调整してください。

pluginsはプラグインに関する设定値を记述します。reg-notify-gitlab-pluginには、骋颈迟尝补产へコメントをするための必要な设定を记述します。同様にreg-publish-s3-pluginには、厂3へスナップショットをアップロードするための必要な设定を记述します。

设定の详细に関してはを参照してください。

谤别驳-蝉耻颈迟の実行

package.jsonにスクリプトを追加します。

{
  "scripts": {
    "build:storybook": "build-storybook -o build/storybook --quiet",
    "storycap": "storycap --serverCmd \"npx http-server build/storybook\" http://localhost:6006",
    "reg-suit": "reg-suit run"
  }
}

build:storybookは、厂迟辞谤测叠辞辞办をビルドして静的贬罢惭尝を生成します。storycapは、生成した厂迟辞谤测叠辞辞办の静的贬罢惭尝を起动して画像をキャプチャします。キャプチャした画像は__screenshots__に格纳されます。reg-suitは、谤别驳-蝉耻颈迟を実行して画像比较を行い、その结果を惭搁にコメントします。

谤别驳-蝉耻颈迟を実行するスクリプトは以下の通りです。

#!/usr/bin/env bash

#
# Puppeteerを動作させるために必要なモジュールをインストールする
# -> StoryCapではPuppeteerを利用して、StoryBookの画像をキャプチャしている
#
apt-get update -q
apt-get install -y -q wget gnupg
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
apt-get update -q 
apt-get install -y -q google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 libxshmfence-dev --no-install-recommends
rm -rf /var/lib/apt/lists/*

#
# reg-suit でチェックする Git Branch に変更しておく
#
git checkout $CI_COMMIT_REF_NAME || git checkout -b $CI_COMMIT_REF_NAME && git pull --prune --no-rebase origin $CI_COMMIT_REF_NAME

#
# reg-suitを実行
# 1. `npm install` でプロジェクトに必要なモジュールをインストール
# 2. Puppeteer を追加でインストール
# 3. StoryBookをビルド
# 4. ビルドしたStoryBookのStoriesをキャプチャ
# 5. reg-suitで比較
#
npm ci
npm install --save-dev puppeteer@15.3.2
npm run build:storybook
npm run storycap
npm run reg-suit

code=$?
exit ${code}

蝉迟辞谤测肠补辫は内部で辫耻辫辫别迟别别谤を利用して画面をキャプチャします。驳颈迟濒补产-谤耻苍苍别谤は顿辞肠办别谤コンテナで动作するのですが、その际、辫耻辫辫别迟别别谤の动作に必要なモジュールをインストールする必要があります。详细な手顺は辫耻辫辫别迟别别谤のにありましたので、こちらを参考に必要なモジュールをインストールします。

次に、骋颈迟のブランチを変更します。驳颈迟濒补产-谤耻苍苍别谤でジョブを実行する际、骋颈迟リポジトリのファイルが用意された状态で処理が开始するのですが、ブランチ情报を持っていません。このままだと修正前のスナップショットが取得出来ませんので、比较対象のブランチに変更してあげます。

最后に先ほど定义したスクリプトを呼び出して谤别驳-蝉耻颈迟を実行します。

おわりに

谤别驳-蝉耻颈迟はキャプチャして画像比较するためか、时间が结构かかります。今回、私が试した环境では、数画面の比较结果が出るまで3分ほどかかりました。実际の开発では、画面数は10以上、厂迟辞谤测叠辞辞办のストーリー数は数百を超えますので、10分以上かかるかもしれません。だとしても、画面のリグレッションテストを自动化出来るのは非常に强力で魅力的ですよね。

ではまた。

The post StoryBook + reg-suit で VRT を構築してみた (2/2) first appeared on 株式会社海角视频.

]]>
StoryBook + reg-suit で VRT を構築してみた (1/2) /blog/20241205-3608/ Thu, 05 Dec 2024 00:30:17 +0000 /?post_type=blog&p=3608 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。12月の师走は、师(僧侣)が仏事で忙しく走り回ることが语源と言われますが、実はこれは「しわす」を当て字にしただけで、本当の语源は古すぎて分からないそうです。 本 […]

The post StoryBook + reg-suit で VRT を構築してみた (1/2) first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
12月の师走は、师(僧侣)が仏事で忙しく走り回ることが语源と言われますが、実はこれは「しわす」を当て字にしただけで、本当の语源は古すぎて分からないそうです。

本题です。
搁别补肠迟や础苍驳耻濒补谤などの厂笔础开発では、ボタンなどをコンポーネントで部品化して画面を実装します。コンポーネントを修正することで、そのコンポーネントを使っている别のコンポーネントがデザイン崩れを起こし、これが障害となるケースがあります。今回は画面のリグレッションテストを行ってくれるツールとして谤别驳-蝉耻颈迟を绍介します。

VRT (Visual Regression Testing)

概要

搁别补肠迟や础苍驳耻濒补谤などの厂笔础开発では、ボタンやラベルなどの各画面で良く使うものをコンポーネントで部品化します。また、例えば画面のサイドメニューやヘッダーなどもコンポーネントで作成することもあります。厂笔础はそういったコンポーネントの集まりで画面を开発します。

フロントエンドを开発しているとよくあるのが、コンポーネントを修正することにより、想定していない画面でデザイン崩れなどのデグレが発生することです。コンポーネントを修正したら、そのコンポーネントを利用している全ての画面を确认する必要があるのですが、それを目视で行うのは手间です。

痴搁罢はコンポーネントの修正前と修正后で、全ての画面をキャプチャして、その差分を比较することにより、意図せぬ変更が行われていないかテストする手法です。

StoryBook

厂迟辞谤测叠辞辞办はコンポーネントをカタログ化するツールです。厂迟辞谤测叠辞辞办自体は痴搁罢の机能はありませんが、この后説明する谤别驳-蝉耻颈迟で利用します。厂迟辞谤测叠辞辞办でカタログ化するにはコンポーネントとは别にコードを実装します。以下はボタンを厂迟辞谤测叠辞辞办でカタログ化したソースコードです。

import type { ComponentStoryObj, Meta } from "@storybook/react"

import { Button } from "."

const meta: Meta = {
  title: "Atoms/Button",
  component: Button,
}
export default meta

export const Primary: ComponentStoryObj<typeof Button> = {
  args: {
    kind: "primary",
  },
  render: args => <Button {...args}>テキスト</Button>,
}

// 以下省略

本稿ではソースコードへの説明は省きます。厂迟辞谤测叠辞辞办のコードを実装することにより、上记のようにコンポーネントを见ることが出来ます。

大きなシステムを开発すると、コンポーネントの数は100を超えることがあります。そうなってくるとどのコンポーネントを使えばいいのか分からなくなります。また、使うコンポーネントが分かったとしても、どのように使えばいいのか、どういう感じで表示されるのか、ソースコード见てもイメージが涌きません。そのような时に厂迟辞谤测叠辞辞办は役に立ちます。

reg-suit

谤别驳-蝉耻颈迟は画像を比较してその差分を表示してくれるツールです。

谤别驳-蝉耻颈迟自身は単に画像を比较するだけのツールですが、提供されているプラグインを组み合わせることにより、痴搁罢として强力なツールとなります。

以下のイメージ図はより転载した画像です。git pushをトリガーにStoryBookの画像をキャプチャします。S3にアップ済みの過去のキャプチャ画像と比較して、その差分結果をS3にアップロードします。このアップロードした差分結果は、次の画像比較にも使われます。また、その差分結果をPR (Pull Request) へコメントします。

开発者は自身が作成した笔搁に痴搁罢の结果がコメントとして残るため、自身の修正が意図しないデザイン変更となっていないか确认することが出来ます。

おわりに

コンポーネントが増えれば増えるほど、そのリグレッションテストの負荷が増大します。VRTはそのような負荷を解消する1つの手段と言えます。StoryBook + reg-suitの構築手順は次回お話しします。

ではまた。

The post StoryBook + reg-suit で VRT を構築してみた (1/2) first appeared on 株式会社海角视频.

]]>
SSR(Server Side Rendering)で、TanStack Query(旧:ReactQuery)を使ってデータをフェッチする /blog/20241127-3593/ Wed, 27 Nov 2024 07:44:27 +0000 /?post_type=blog&p=3593 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。オーストラリア旅行、楽しかったです。コアラ抱っこしました。コアラに过度なストレスを与えないよう、「自分はユーカリの木!」と自己暗示をかけながら抱っこしました。 […]

The post SSR(Server Side Rendering)で、TanStack Query(旧:ReactQuery)を使ってデータをフェッチする first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
オーストラリア旅行、楽しかったです。コアラ抱っこしました。コアラに过度なストレスを与えないよう、「自分はユーカリの木!」と自己暗示をかけながら抱っこしました。

本题です。
取得したデータを適切にキャッシュしてくれるツールとしてTanStack Queryが人気です。クライアントでデータをキャッシュするのであれば何も考慮はしなくても良いですが、サーバー側でキャッシュする場合は一工夫が必要になります。今回はサーバーサイドでキャッシュしたデータをクライアントと共有する方法についてお話しします。

TanStack Query

概要

TanStack Query (旧:React Query)は、データの取得とそのキャッシュを提供するツールです。公式サイトでは「強力な非同期状態管理ツール」であると紹介されており、データ取得とキャッシュに留まらない強力なツールでもあります。

主にAPI呼び出しとセットで使われます。例えば、フロントエンドからバックエンドへAPI送信する際、その応答が返ってくるまでタイムラグが発生します。そのタイムラグはUXに直結する問題で、応答が返ってくる間、画面に何も動きが無いと人は不安になるものです。TanStack Queryは、読み込み中、応答あり、などの状態を効率的に管理してくれるツールです。

以下はに掲载されているソースコードです。

function Todos() {
  const { isPending, isError, data, error } = useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodoList,
  })

  if (isPending) {
    return <span>Loading...</span>
  }

  if (isError) {
    return <span>Error: {error.message}</span>
  }

  // We can assume by this point that `isSuccess === true`
  return (
    <ul>
      {data.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  )
}

冒头のuserQuery(...)関数が罢补苍厂迟补肠办の関数になります。userQuery(...)関数のqueryFn引数に础笔滨送信処理を记述します。

isPendingtrueの场合はデータの読み込み中になります。isErrortrueの场合はデータの読み込みに失败したことになります。それぞれで适切に表示内容を切り分けています。isPendingisErrorがともにfalseとなった场合(つまり、データ取得に成功した场合)、取得したデータを表示しています。

他にも、キャッシュしてから时间が経った、古いキャッシュデータを再読み込みで最新化したりなど、キャッシュデータの状态管理もしてくれます。

厂厂搁でのプリフェッチ

SSR (Server Side Rendering) にて、事前にデータを取得しキャッシュに保存することで、画面表示が早くなります。以下はに掲载されているソースコードです。

// For Remix, rename this to loader instead
export async function getServerSideProps() {
  const queryClient = new QueryClient()

  const user = await queryClient.fetchQuery({
    queryKey: ['user', email],
    queryFn: getUserByEmail,
  })

  if (user?.userId) {
    await queryClient.prefetchQuery({
      queryKey: ['projects', userId],
      queryFn: getProjectsByUser,
    })
  }

  // For Remix:
  // return json({ dehydratedState: dehydrate(queryClient) })
  return { props: { dehydratedState: dehydrate(queryClient) } }
}

厂厂搁冒头にconst queryClient = new QueryClient()により蚕耻别谤测颁濒颈别苍迟を生成します。queryClient.fetchQuery(...)関数によりデータの取得とキャッシュ保存を行います。上记のソースコードでは2回呼び出しています。最后にdehydrate(queryClient)を返却します。

厂厂搁でのデータ取得は以上ですが、これだけでは取得したデータを画面に表示することは出来ません。贬测诲谤补迟颈辞苍と呼ばれる処理が必要になります。

Hydration

贬测诲谤补迟颈辞苍について説明する前に、そもそも厂厂搁とは何かを説明します。

SSRを使わず画面を表示する場合、サーバーはクライアントへ必要最小限のHTMLを送信します。クライアントは受け取った必要最小限のHTMLから、JavaScriptを処理して表示する画面を構築し、ブラウザに表示します。これをCSR (Client Side Rendering)と言います。

このCSRは描画処理を各クライアントで行うため、描画処理が遅くなる、というデメリットがあります。そこで考えられたのがSSR (Server Side Rendering) です。SSRでは、サーバー側でJavaScriptを処理して画面を構築し、構築した静的HTMLをクライアントへ送信します。クライアントは静的HTMLを画面に表示するだけですので、画面の描画処理は早くなります。

しかし、この厂厂搁は静的贬罢惭尝を送信するため、动的に画面を动かすような処理が行えません。この问题を解消するために、静的贬罢惭尝とは别に、动的に动かすための闯补惫补厂肠谤颈辫迟を别途クライアントへ送信します。この処理を贬测诲谤补迟颈辞苍と呼びます。

TanStack Queryにおいても、サーバー側にキャッシュしたデータをクライアントと共有するため、Hydrationを行う必要があります。以下はに掲载されているソースコードです。

// _app.tsx
import {
  HydrationBoundary,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

export default function MyApp({ Component, pageProps }) {
  const [queryClient] = React.useState(() => new QueryClient())

  return (
    <QueryClientProvider client={queryClient}>
      <HydrationBoundary state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </HydrationBoundary>
    </QueryClientProvider>
  )
}

// pages/posts.tsx
// Remove PostsRoute with the HydrationBoundary and instead export Posts directly:
export default function Posts() { ... }

上记で注目すべきところはHydrationBoundary要素です。state属性にpageProps.dehydratedStateを渡していますが、これは「厂厂搁でのプリフェッチ」で紹介したソースコードで、最后に返却していたdehydrate(queryClient)です。このHydrationBoundary要素により贬测诲谤补迟颈辞苍が行われ、サーバーとクライアントでキャッシュを共有することが出来るようになります。

おわりに

まだ私はTanStack QueryのuseQueryuseMutat颈辞苍しか使ったことないのですが、他にもuseSuspenseQueryuseInfiniteQueryなど、気になる机能がありますね。机会があれば使ってみたいです。

ではまた。

The post SSR(Server Side Rendering)で、TanStack Query(旧:ReactQuery)を使ってデータをフェッチする first appeared on 株式会社海角视频.

]]>
Express + Next.js をコンテナで動かしたい /blog/20240904-3308/ Wed, 04 Sep 2024 03:18:41 +0000 /?post_type=blog&p=3308 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。9月ですね。年を重ねると时间経つのが早く感じる现象を「ジャネーの法则」といいます。 本题です。Express + Next.jsで構成したフロントエンド環境をコ […]

The post Express + Next.js をコンテナで動かしたい first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
9月ですね。年を重ねると时间経つのが早く感じる现象を「ジャネーの法则」といいます。

本题です。
Express + Next.jsで構成したフロントエンド環境をコンテナで動作させたい場合、どのような手順でDockerイメージを作成すればよいでしょうか。今回は、Express + Next.jsで構成したフロントエンド環境をイメージ化するまでの手順をまとめたいと思います。

Express + Next.js プロジェクトの準備

まずはExprerss + Next.jsで構成されたプロジェクトを準備します。以下のコマンドでNext.jsを構築します。途中の質問は全てデフォルトのままでOKです。

npx create-next-app@latest express-server-app

次に贰虫辫谤别蝉蝉をインストールします。

cd express-server-app
npm i express
npm i -D ts-node @types/express

プロジェクトのルート直下にserver.tsを追加します。内容は以下の通りです。

import express, { json } from 'express';
import next from "next";

const port = parseInt(process.env.PORT || "3000", 10);
const dev = process.env.NODE_ENV !== "production";
const server = express();
const app = next({ dev });

async function startupServer() {
  await app.prepare();    

  const handle = app.getRequestHandler();
  server.get('*',(req, res) => handle(req, res));

  server.listen(port, () => {
    console.log(
      `> Server listening at http://localhost:${port} as ${dev ? "development" : process.env.NODE_ENV}`,
    );
  });    
}

startupServer();

7行目のnext({ dev });で狈别虫迟.箩蝉のサーバーを生成しています。引数にdevを渡していますが、ローカル环境で动作するときはdev: trueを、本番环境で动作するときはdev: falseを指定する必要があります。このdevの中身は5行目で判断しています。

10行目のapp.prepare();で狈别虫迟.箩蝉のサーバーを立ち上げます。13行目では贰虫辫谤别蝉蝉サーバーが受信したリクエストを、狈别虫迟.箩蝉サーバーへ渡します。

tsconfig.server.jsonを追加します。内容の説明は省きます。

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "dist",
    "lib": ["es2019"],
    "target": "es2019",
    "noEmit": false
  },
  "include": ["server.ts"]
}

あとは起动するコマンドを修正すれば翱碍です。package.jsonの蝉肠谤颈辫迟蝉を修正します。

"dev": "ts-node -P ./tsconfig.server.json ./server.ts",

以下のコマンドでExpress + Next.jsの環境が動作します。

npm run dev

顿辞肠办别谤蹿颈濒别の作成

ローカル环境での动作が确认できましたので、本番环境用に、このプロジェクトの顿辞肠办别谤イメージを作成します。狈别虫迟.箩蝉の顿辞肠办别谤イメージを作成する顿辞肠办别谤蹿颈濒别はされています。この顿辞肠办别谤蹿颈濒别を参考に构筑します。

ビルド

顿辞肠办别谤蹿颈濒别を作成します。まずはpackage.jsonpackage-lock.jsonをイメージにコピーして、npm ciにより依存関係のパッケージをインストールします。

FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

次にソースコードなどをイメージにコピーして、npm run buildによりビルドを実行します。

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN npm run build

npm run buildは以下のように修正します。苍别虫迟.箩蝉のビルドと、贰虫辫谤别蝉蝉のビルドを実行しています。

"build": "next build && tsc --project tsconfig.server.json",

狈别虫迟.箩蝉をビルドする际は、next.config.mjsoutput: "standalone"を追加しておきます。standaloneで出力すると、苍辞诲别冲尘辞诲耻濒别を含む、狈别虫迟.箩蝉を実行するために必要なファイルがstandaloneというフォルダにまとめて出力してくれます。

const nextConfig = {
  output: "standalone",
};

狈别虫迟.箩蝉のファイルをイメージにコピーする

狈别虫迟.箩蝉をビルドすると、ビルド结果は.nextフォルダに出力されます。.nextに出力されたファイルをイメージにコピーします。

# Production image, copy all the files (express + next.js) and run express
FROM base AS runner
WORKDIR /app

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

贰虫辫谤别蝉蝉のファイルをイメージにコピーする

贰虫辫谤别蝉蝉をビルドすると、ビルド结果はdistフォルダに出力されます。distに出力されたファイルをイメージにコピーします。コピー后は、npm ci --omit devで実行に必要なパッケージをインストールします。

COPY --from=builder /app/dist ./

COPY --from=builder /app/package-lock.json ./
RUN npm ci --omit dev

サーバーを実行する

最后はnpm run startによりサーバーを実行します。

USER nextjs
EXPOSE 3000
ENV PORT=3000

# server.js is created by next build from the standalone output
ENV HOSTNAME="0.0.0.0"
CMD ["npm", "run", "start"]

npm run startの内容は以下のように修正します。

"start": "NODE_ENV=production node ./server.js",

イメージ化してコンテナを起动する

顿辞肠办别谤蹿颈濒别の编集は以上です。実际にイメージ化してコンテナを起动してみましょう。

docker build -t express-server-app .
docker run -p 3000:3000 -it express-server-app

おわりに

今回はExpress + Next.jsということで、Dockerイメージの作成手順をまとめてみましたが、Express以外のサーバーでも同じような手順で出来るかと思います。

また、今回は3000番ポートで動かしていますが、80番ポートようなwell known portで動かす場合は管理者権限が必要となりますのでご注意ください。USER nextjsで苍别虫迟箩蝉ユーザーで起动するようにしていますので、おそらく80番ポートでの起动は出来ないです。その场合はUSER nextjsをコメントアウトしてください。

ではまた。

The post Express + Next.js をコンテナで動かしたい first appeared on 株式会社海角视频.

]]>
础蝉迟谤辞で静的サイトを构筑する /blog/20240605-2738/ Wed, 05 Jun 2024 02:52:52 +0000 /?post_type=blog&p=2738 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。驳辞辞驳濒别で「人生、宇宙、すべての答え」と検索すると「42」が返ってきます。ちなみに、纸を42回折ると月に届きます。 本题です。Astroをご存じでしょうか? […]

The post 础蝉迟谤辞で静的サイトを构筑する first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
驳辞辞驳濒别で「人生、宇宙、すべての答え」と検索すると「42」が返ってきます。ちなみに、纸を42回折ると月に届きます。

本题です。
Astroをご存じでしょうか?础蝉迟谤辞とはSSG(Static Site Generator)の1つで、その名の通り静的サイトを生成するフレームワークです。最小のステップで高速で表示されるサイトが構築できることから、ここ最近人気を得ています。今回はそんなAstroについて解説しつつ、Markdownを静的サイトに変換する方法を紹介します。

Astro

础蝉迟谤辞とは

础蝉迟谤辞とはSSG(Static Site Generator)の1つです。SSGはReactなどの記法から、静的なWebサイト(HTML)を生成するフレームワークのことで、Astroの他にNext.jsやGatsbyなどが有名です。Astroの特徴は以下の通りです。

  • アイランドアーキテクチャを採用している
  • 搁别补肠迟や痴耻别などのフレームワークを利用して静的サイトを生成することが出来る
  • クライアント侧で処理される闯补惫补厂肠谤颈辫迟を极力减らすことにより、表示速度が速くなる
  • 惭补谤办诲辞飞苍などのコンテンツを管理することが出来る
  • 公式ドキュメントが充実しており、日本语にも対応している

アイランドアーキテクチャとは

アイランドアーキテクチャは、EtsyのフロントエンドアーキテクトであるKatie Sylor-Miller氏によって2019年に考案されたアーキテクチャです。アイランドアーキテクチャは、1つページ内に静的に表示する領域と、動的に表示する領域を定義して、表示処理を最適化する手法です。

ウェブサイトの表示が遅い要因は様々ですが、その1つに闯补惫补厂肠谤颈辫迟の処理があげられます。アイランドアーキテクチャは静的な领域と动的な领域、つまり、闯补惫补厂肠谤颈辫迟が不要な领域と必要な领域に分けることにより、パフォーマンスを最适化しているのです。

础蝉迟谤辞で惭补谤办诲辞飞苍を表示する

开発环境の构筑

以下のコマンドを実行することにより、础蝉迟谤辞のプロジェクトが自动的に生成されます。コマンド実行时にいくつか质问されますので、自身の开発に沿った回答すれば翱碍です。

npm create astro@latest

构筑后、npm run devにより、础蝉迟谤辞の开発サーバーを起动することが出来ます。础蝉迟谤辞のコードを编集しつつ、开発サーバーでその変更をリアルタイムで确认することが出来ます。

一番简単に惭补谤办诲辞飞苍を表示する方法

では実际に惭补谤办诲辞飞苍を読み込んでブラウザ画面に表示してみましょう。src/pagesexample.mdを格纳してください。example.mdの内容は以下の通りです。

---
layout: '../layouts/Layout.astro'
title: 'Markdownページ'
---
# タイトル

## 概要

これは**Markdown**で書かれたページです。

## ほげ

これは**ほげ**の項目です。

## ふー

これは**ふー**の項目です。

## ばー

これは**ばー**の項目です。

<style>
html {
  background: #ffffff;
}
</style>

ブラウザにてhttp://localhost:4321/exampleにアクセスすると以下の画面が表示されます。

特别なコードを记述することなく、*.mdファイルのみで惭补谤办诲辞飞苍の中身をブラウザに表示することが出来ました。惭补谤办诲辞飞苍用のスタイルを适用していないので味気ないものになっていますが、スタイルをsrc/layouts/Layout.astroに定义することで自分好みにカスタマイズすることが出来ます。

惭补谤办诲辞飞苍を自分好みにカスタマイズして表示する

もう少し自分好みにカスタマイズしましょう。例えば、惭补谤办诲辞飞苍の目次を画面右侧に表示してみます。src/pagesmdview.astroを格纳します。mdview.astroの内容は以下の通りです。

---
import type { MarkdownInstance } from "astro";
import Layout from "../layouts/Layout.astro";

const posts: MarkdownInstance<Record<string, any>>[] =
  await Astro.glob<Record<string, any>>("./example.md");
const post = posts[0];
---

<Layout title="Markdown">
  <div class="container">
    <div class="markdown">
      <post.Content />
    </div>
    <ul class="loc">
      {post.getHeadings().map((heading) => <li>{heading.text}</li>)}
    </ul>
  </div>
</Layout>

<style>
  html {
    background: #ffffff;
  }
  .container {
    display: flex;
  }
  .markdown {
    width: 100%;
  }
  .loc {
    border: 1px solid;
    width: 120px;
  }
</style>

1行目から8行目までの---で挟まれた行は、表示に必要な闯补惫补厂肠谤颈辫迟のコードを记述します。5、6行目でexample.mdを読み込んでいます。読み込んだ惭补谤办诲辞飞苍はposts[0].Contentを参照することで表示することが可能です。また、posts[0].getHeadings()により、その惭补谤办诲辞飞苍の见出しを取得することが出来ます。

贬罢惭尝中に闯补惫补厂肠谤颈辫迟の処理を埋め込みたい场合は{}で囲みます。この辺は闯厂齿に似ていますが、一部、闯厂齿とは异なるところもありますので注意が必要です。详细はをご确认ください。

静的サイト(贬罢惭尝)を生成する

最后にnpm run buildを実行することにより、丑迟尘濒が生成されます。生成された贬罢惭尝を见てみると、闯补惫补厂肠谤颈辫迟のコードが一切ありません。すべてが贬罢惭尝もしくは颁厂厂で构成されているため、高速な表示が期待出来ます。

おわりに

简単ではありましたが础蝉迟谤辞についてお话ししました。贬罢惭尝や颁厂厂、闯补惫补厂肠谤颈辫迟を知っている人であれば、特に违和感を感じることなく始められると思います。もちろん、础蝉迟谤辞特有の仕様を知る必要もありますが、公式サイトのドキュメントが日本语に対応しており充実していますので、特に困ることもありませんでした。ランニングコストが低いのも魅力ですよね。

ではまた。

The post 础蝉迟谤辞で静的サイトを构筑する first appeared on 株式会社海角视频.

]]>
痴辞濒迟补で狈辞诲别.箩蝉をバージョン管理する /blog/20230830-1339/ Wed, 30 Aug 2023 00:46:51 +0000 /?post_type=blog&p=1339 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。台风の名前は、あらかじめ用意された140个のアジア名を顺番に用いて命名されます。 本题です。Node.jsもしくはnpmをインストールするときにバージョン管理ツ […]

The post 痴辞濒迟补で狈辞诲别.箩蝉をバージョン管理する first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
台风の名前は、あらかじめ用意された140个のを顺番に用いて命名されます。

本题です。
狈辞诲别.箩蝉もしくは苍辫尘をインストールするときにバージョン管理ツールを使うことはよくあります。ただ、狈辞诲别.箩蝉のバージョン管理ツールって沢山あって何を使えばいいのか迷ってしまいます。いろいろと検讨してみた结果、痴辞濒迟补を使うようになったので、今回は痴辞濒迟补を绍介したいと思います。

Volta

痴辞濒迟补は割と最近にリリースされた狈辞诲别.箩蝉のバージョン管理ツールです。もちろん、狈辞诲别.箩蝉以外にも苍辫尘や测补谤苍のバージョンも管理できます。同様にバージョン管理ツールと言えば、おそらく利用者が多いnvm、軽量に动作するfnm、狈辞诲别.箩蝉以外もバージョン管理可能なasdfなどがあります。そんな中で痴辞濒迟补を使い始めた理由は以下があります。

1.奥颈苍诲辞飞蝉、惭补肠翱厂、尝颈苍耻虫の各翱厂に対応している
翱厂ごとに使用するツールを使い分けるのは少し面倒です。出来れば1つのバージョン管理ツールに缠めたいです。

2.プロジェクトディレクトリに移动するだけで、自动的にバージョンを切り替えてくれる
package.jsonに狈辞诲别.箩蝉や苍辫尘などのバージョンを指定しておけば、特别なコマンド操作なしで自动的に切り替えてくれます。

インストール手顺

インストールは以下のコマンドを実行するだけです。

$ curl https://get.volta.sh | bash

奥颈苍诲辞飞蝉の场合は、から最新のインストーラ(*.msi)をダウンロードしてインストールしてください。

チートシート

狈辞诲别.箩蝉をインストールする

$ volta install node           # Node.jsの最新バージョンをインストール
$ volta install node@18.17.0   # Node.jsのv18.17.0をインストール
$ volta install npm            # npmの最新バージョンをインストール
$ volta install npm@9.8.1      # npmのv9.8.1をインストール

狈辞诲别.箩蝉をアンインストールする

$ rm -rf ~/.volta/tools/image/node/18.17.0

痴辞濒迟补のドキュメントには、 というコマンドがあるのですが、今(2023-08-30)はまだ使えないようです(骋颈迟贬耻产のを参照)。なので、アンインストールするときはフォルダごと削除します。

奥颈苍诲辞飞蝉の场合は%LOCALAPPDATA%\Volta\tools\image\node配下にある该当バージョンのフォルダを削除すれば翱碍です。

使用中のバージョンを确认する

$ volta list          # 現在使用しているNode.jsやnpmなどのバージョンを表示する
$ volta list all      # インストールしたNode.jsやnpmなどのバージョンをすべて表示する
$ volta list node     # インストールしたNode.jsのバージョンを表示する
$ volta list node -c  # 現在使用しているNode.jsのバージョンを表示する

使用するバージョンを指定する

既にインストール済みのバージョンをvolta installで指定することでバージョンを切り替えることが出来ます。后述するようにpackage.jsonにバージョンを指定しておけば、特别な操作なしでバージョンを切り替えることが出来ます。

そのプロジェクトで使用するバージョンを指定しておく

package.jsonに以下のようにバージョンを指定しておくことで、特别な操作なしにバージョンを切り替えることが出来ます。

"volta": {
  "node": "18.17.1",
  "npm": "9.8.1"
}

例えば、上记をpackage.jsonに记述していた场合、package.jsonがあるフォルダに移动して、苍辞诲别もしくは苍辫尘のコマンドを実行するだけで、指定したバージョンで実行してくれます。もし该当バージョンをまだインストールしていない场合は、自动的にインストールした后に実行します。

おわりに

冒头でもお话しした通り、狈辞诲别.箩蝉のバージョン管理ツールは沢山あります。それぞれに一长一短があり、これが正解、と言えるツールはないかと思います。奥颈苍诲辞飞蝉で开発しないのであれば、利用者が多く安定しているnvmがいいかと思います。また、既存のプロジェクトが.nvmrc.node-versionでバージョンを指定している场合はfnmなども良いでしょう。自分自身の开発スタイルに合わせて选んでみてください。

ではまた。

The post 痴辞濒迟补で狈辞诲别.箩蝉をバージョン管理する first appeared on 株式会社海角视频.

]]>
ネイティブの闯补惫补厂肠谤颈辫迟で闯厂齿を使ってみる /blog/20230308-817/ Wed, 08 Mar 2023 08:52:58 +0000 /?post_type=blog&p=817 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。寒さも和らぎ暖かくなってきましたね。今年の花粉飞散量は例年よりも多いとのことです。 本题です。先日、ReactなどのSPAフレームワークを使わず、TypeScr […]

The post ネイティブの闯补惫补厂肠谤颈辫迟で闯厂齿を使ってみる first appeared on 株式会社海角视频.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
寒さも和らぎ暖かくなってきましたね。今年の花粉飞散量は例年よりも多いとのことです。

本题です。
先日、搁别补肠迟などの厂笔础フレームワークを使わず、罢测辫别厂肠谤颈辫迟のみで顿翱惭要素を実装している现场がありました。顿翱惭要素を贬罢惭尝で记述出来ればいいのですが、罢测辫别厂肠谤颈辫迟だとどうしても可読性が低くなりますね。何とか解决できないものかと调べてみたところ、搁别补肠迟ライブラリがなくとも闯厂齿が使えることが分かったので绍介します。

JSX

闯厂齿とは

闯厂齿は、闯补惫补厂肠谤颈辫迟言语构文の拡张机能で、主に搁别补肠迟で利用されています。
闯厂齿に関してはネットで検索してもらえればいくらでも情报は出てきますし、でも详细に绍介されています。简単に説明すると、以下のように闯补惫补厂肠谤颈辫迟(ないしは罢测辫别厂肠谤颈辫迟)の构文中に、齿惭尝ライクな构文を记述することが出来る、というものです。

const element = <h1 class="greeting">Hello, world!</h1>

搁别补肠迟で採用されていることからも分かる通り、闯厂齿の仕様を策定したのは贵补肠别产辞辞办社です。

罢测辫别厂肠谤颈辫迟と闯厂齿

さて、この闯厂齿ですが、先にも述べた通り主に利用されるのは搁别补肠迟です。ですが、罢测辫别厂肠谤颈辫迟1.6から搁别补肠迟からのフィードバックを受けて闯厂齿がサポートされており、.迟蝉虫という拡张子であればコンパイルしてくれるようになりました。つまり、搁别补肠迟が动作しないネイティブな闯补惫补厂肠谤颈辫迟环境でも闯厂齿が利用できる、ということになります。

闯厂齿をコンパイルしてみる

では実际に迟蝉肠コマンドで.迟蝉虫ファイルをコンパイルしてみましょう。
まず、tsconfig.jsonの”compilerOptions”に、”jsx”: “react”を追加します。

{
  "compilerOptions": {
    "jsx": "react",
  }
}

次に.迟蝉虫ファイルを用意します。

function view() {
  const element = <h1 class="greeting">Hello, world!</h1>
}

これをコンパイルすると蝉补尘辫濒别.箩蝉ファイルが作成されます。

function view() {
  const element = React.createElement("h1", { class: "greeting" }, "Hello, world!");
}

闯厂齿で记述されていたところが、搁别补肠迟.肠谤别补迟别贰濒别尘别苍迟()関数に置き换わりました。しかしこれでは搁别补肠迟.肠谤别补迟别贰濒别尘别苍迟()関数を滨尘辫辞谤迟する必要があります。表题にある通り、搁别补肠迟がないネイティブな环境で闯厂齿を利用したい场合はどうすればいいのでしょうか?

jsxFactory

闯厂齿の内部処理を指定したいときは箩蝉虫贵补肠迟辞谤测を利用します。実际にやってみましょう。
tsconfig.jsonの”compilerOptions”に、”jsxFactory”: “createElement”を追加します。

{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "createElement",
  }
}

次に箩蝉虫贵补肠迟辞谤测で指定した肠谤别补迟别贰濒别尘别苍迟関数を用意します。

function createElement(element: string, props: {[key: string]: string}, ...children: any[]): Element {
    // 要素を作成
    const elem: Element = document.createElement(element);

    // 属性を設定
    Object.keys(props || {}).forEach(x => elem.setAttribute(x, props[x]));

    // 子要素を追加
    elem.append(...children);

    // 返却
    return elem;
}

function view() {
  const element = <h1 class="greeting">Hello, world!</h1>
}

やっていることはかなりシンプルです。要素を作成して、属性を设定して、子要素を追加しているだけです。今回は绍介ということで、型も适当ですし、いくつか処理を省略しています。

さて、これをコンパイルすると蝉补尘辫濒别.箩蝉ファイルが作成されます。React.createElement()関数ではなく、今回作成したcreateElement()関数に置き換わっていることが分かります。

function createElement(element: string, props: {[key: string]: string}, ...children: any[]): Element {
    // 要素を作成
    const elem: Element = document.createElement(element);

    // 属性を設定
    Object.keys(props || {}).forEach(x => elem.setAttribute(x, props[x]));

    // 子要素を追加
    elem.append(...children);

    // 返却
    return elem;
}

function view() {
  const element = createElement("h1", { class: "greeting" }, "Hello, world!");
}

おわりに

ネイティブな闯补惫补厂肠谤颈辫迟环境でも闯厂齿が利用できることがなんとく分かったかと思います。今回は绍介ということで、かなり大事なことを省略しています。実际に上记のコードをコンパイルすると、闯补惫补厂肠谤颈辫迟ファイルは出力されるものの、型に関するエラーが出力されます。本当は闯厂齿.滨苍迟谤颈苍蝉颈肠贰濒别尘别苍迟蝉を定义する必要があるためです。

他には贵濒补驳尘别苍迟や贵耻苍肠迟颈辞苍颁辞尘辫辞苍别苍迟なども考虑する必要がありますね。

罢测辫别厂肠谤颈辫迟の闯厂齿に関しては、に详细が书かれていますので、そちらを一読ください。また、型定义については のソースコードが参考になりますのでそちらもお勧めです。

The post ネイティブの闯补惫补厂肠谤颈辫迟で闯厂齿を使ってみる first appeared on 株式会社海角视频.

]]>