🥵

node v9 の静的サイトをAstro でリプレースする

2023/12/15に公開

はじめに

ポート株式会社 サービス開発部 Advent Calendar 2023 13日目の記事です。

フロント開発に携わる🩷ピンク髪💅の eicho.chin です。こちらは最近実装した Astro のサイトの話を紹介できればと思います!🫣

Astro選ぶ理由

  1. 旬のフレームワーク、圧倒的人気
  2. cloudflare へのデプロイだけではなく、色んな方法でデプロイ可能
  3. 静的サイトであれば、SSG/SSR 選び放題
  4. Vite
  5. あらゆる面で CWVs に適応するフレームワーク🐵

今回のリプレースの目的/満たしたい希望

  1. node のバージョンをなるべく最新のものを使用したい。
  2. 将来開発のコストも削減できれば幸い。
  3. 既存の計測やクローリングに影響がないように実装します。

調査編🤨

sass/scss 導入使用

既存のcss を全部再利用♻️のため、利用可能かどうかの確認します。
Styles & CSS 🚀 Astro Documentation

yarn add -D sass

その他の設定は特に不要です。
src/stylesheets/application.scss にて、既存のscssファイル は 全部一つのファイルにまとめてる endpoint。
Astro コンポーネントは全部 scope であり、利用したい コンポーネントで import "../stylesheets/application.scss";するので問題なく、class のスタイルが適用されます。

利用案

scope で利用するのがセオリなんですが、既存のCSSを移行が目的のため、global で利用したいですが、以下の書き方でしたら、ビルド後は CSS 全部無くなります。

<!doctype html>
<html lang="ja">
    <head>
        <meta charset="UTF-8" />
        ...some code
        <style>
          @import url("@/stylesheets/application.scss");
        </style>

🐤🐤🐤 image 🐤🐤🐤

とても困りました。

Astro 3 以降 <Image /> (astro:assets)、CLS 最高に対応する Image 作り込みによる困る点

Images 🚀 Astro Documentation

Astro 3 以降 <Image /> (astro:assets) が CLS のために、色々良しなに画像がいじられます。

  1. 圧縮されます。
  2. ファイル配信形式もわかる、png/jpg => webp デフォルトに変換されます。
  3. densities で画素レベルで画像のサイズをコントロールできます。

↑良しなに画像に最適化のため、png の画像がぼやくように見えます。

解決方法1 (うまくいかなかった):

---
import { Image } from 'astro:assets';
---

<Image src={imageBtnFaceBook} width="33" height="33" alt="facebookでシェアする" densities={[1.5, 2]} quality="100" format="png"  />
  • densities: 拡大の最小から最大を設定、デカすぎる設定されると無視されます。
  • quality: lowmidmaxなどまたは 1 ~ 100設定可能。この設定で画像のサイズも変わります。
  • format: デフォルト webp ですが、何も変更したくない場合設定が必要です。

上記で一旦解決しそうに見えますが、実際はぼやくことは変わってません。

真・解決策:

Image component に任せます。

        <Image src={imageTxtMv1}  alt="イメージ alt" />

  • 充実に推奨の書き方で記述をします。
  • height、width も imgObject の取得される値を使用されます。
  • CSSで画像サイズをコントロールします。

[slug].astro で動的にルートされる場合、画像のpath に思うように 🦑 ない

astro v3.3.2, では <Image> コンポーネントで動的な path は利用不可。
<Image>の src は必ず Module Importing import imgUrl from "dir/image.png" ファイル Object を渡す必要があります。

失敗例:
[year].astro 動的画面ごとに dir/2023/txt_2023.png のようなパスとファイル名の画像を表示したい。

---
import { Image } from 'astro:assets';

export function getStaticPaths() {
  return [
    { params: { year: '2023' } },
  ];
}

const { year } = Astro.params;

// 成功
import imageUrl2023 from "../images/txt_2023.png";

// 失敗
import imageUrl from `../images/txt_${year}.png`;

CSS background: url("/path") で 利用したい場合、public/ 配下で配置するしかないぽい

これ以外で利用したい場合、他の ライブラリーを使用するしかない。
例:Astro ImageTools Documentation

GA4 計測の調査

gtag.js を使用して、アプリ + ウェブ プロパティの Google アナリティクス タグをサイトに追加する  |  Google for Developers

CVWs のチェックの時、点数下がらないようなソリューション Partytown

Partytown解決案:
メリット:CVWs のチェックの時、google タグで点数下がることがないように
https://www.kevinzunigacuellar.com/blog/google-analytics-in-astro/

本番のみ計測にしたいため、Vite の環境判別を使用します。

---
const isProduction = import.meta.env.PROD;
---

{isProduction && <slot />}

使う箇所:


...some code
...
<ProductionOnly>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-id"></script>
	<script>			
        window.dataLayer = window.dataLayer || [];
		function gtag(){ dataLayer.push(arguments); }
		gtag('js', new Date());

		gtag('config', 'UA-id');
	</script>
</ProductionOnly>

実装編😆

Astroのコレクションを使う形

複数のコレクションによる整理

公式から引用:

予約されているプロジェクトディレクトリsrc/contentの中にあるトップレベルのディレクトリは、1つのコンテンツコレクションを表わします。src/contentディレクトリの中に入れられるのは、コンテンツコレクションだけです。このディレクトリは他のものには使えません。

  • コレクションディレクトリ内に Markdownや MDX、YAML、JSON のようなデータフォーマットを使用できます。
  • ファイル名の前にアンダースコア (_) を付けると、ビルドから除外されます。

JSON ファイルを使用したコンテンツ定義

zod で schema定義

AstroはZodを使ってコンテンツスキーマを動かしています。Zodを利用すると、Astroはコレクション内のすべてのファイルのフロントマターを検証し、プロジェクト内からコンテンツをクエリする際に自動的にTypeScriptの型を提供できます。

デフォルトで zod が組み込まれています。詳しくは:Zodによるデータ型の定義

import { z, defineCollection } from 'astro:content'

const dataCollection = defineCollection({
type: 'data',
schema: z.object({
  content: z.object({
    about: z.object({
      title: z.string(),
      lead: z.string(),
      currentSituation: z.string(),
      contentStatus: z.string(),
      isItWork: z.string(),
    })
  });

npm run devの後、.astro/types.d.ts ファイルがビルドされます。
実際開発時に、型が流れてくるイメージです。

JSONを使用する場合

JSON の場合、type: 'data' を設定する必要があります。詳しくはこちら:コレクションスキーマの定義

const dataCollection = defineCollection({
  type: 'data',  // data の指定により、JSON 定義を使用できます
  schema: z.object({...}),
})

export const collections = {
  data: dataCollection // データコレクションのname は data になります。
}

静的サイトビルド getStaticPaths()getCollection()で画面を生成する

pages/[example].astroページを作成します。

ページがファイル名で動的パラメータを使用する場合、そのコンポーネントはgetStaticPaths()関数をエクスポートする必要があります。
この関数はAstroが静的サイトビルダーであるために必要です。つまり、サイト全体が事前に構築されます。

---
export async function getStaticPaths () {
  const entries = await getCollection('data') // コレクションで定義したname でコレクションを指定します。
  return entries.map(entry => ({
    params: { id: entry.id }, // params は必須、path になります。
    props: { entry } // オブション
  }))
}

const { entry } = Astro.props
---

<!--テンプレート-->
<Component entry={entry} />

getStaticPathsで retrun された params や props は このように Astro.props から取り出すことが可能です。
実際取得したいデータもまた子コンポーネントに渡すことが可能です。

イメージ図:

画像は ファイル名 のみ JSON ファイルに保存、使用の際は、module import して表示を行う。

  1. エントリーJSON定義の際は以下のように fileNameのみになります。

    {
        ...some code
         "data": {
            "name": "コンテンツネーム",
            "contentId": "10001",
            "logo": "logo_10001" // ファイル名
          }
    }
    
  2. ファイル名を使用してダイナミックインポートで モジュールを<Image>に使用

    <Image 
        src={await import(`../images/${entryData.data.logo}.png`).then((data) => data.default)} 
        alt="テスト内容"
    />
    

    今回画像も全部pngのため上記の書き方で問題ないですが、些か優雅さは足りないのです。🥲

困った編🧐

Amplify で Astroをデプロイしたい場合、困難に遭遇

Amplify デフォルトイメージの Node バージョン最新は 18.13.0 でした。
Astro 3.2.2 は最低 18.14.1 が要求されてます。僅か 1 パッチパージョンで、失敗してしまいます。🥲

解決方法

Amazon ECR Public Gallery - Docker/library/node
Amplify で構築イメージを上記のpublic イメージから 使いたい node バージョンのイメージを指定する形で解決可能になります。

末尾スラッシュ問題

他の方も同じような問題 :

再現手順:

  1. スラッシュなしのurl を踏む
    https://feature-10000.d39edkp5r8k421po.amplifyappfake.com/fake

  2. https://<app_url>/<build_#>/<path_I_was_on> の ように <build_#> がpath に追加されてしまう。

暫定対応

  1. ビルド設定を変えます
    こちらの設定で、この変更が可能になります!buildformat
ビルド設定 画像
format: 'directory'
format: 'file'
  1. サイト内遷移リンクを / なしに戻る
  2. Amplify でリダイレクト設定
  3. (正規 URLを設定)

終わりに

初めて Astro を触りました。CWVs などの対応が完備してて、とても嬉しいです。

Discussion