CodeCode

なんか色々おぼえ書き。だいたいweb制作関連。

Astro.jsで軽量なブログを作る覚え書き

広島フロントエンド勉強会のサイトをAstroで開発できるようにしたので、このブログも軽量なAstroで開発できるようにするための覚え書き。 (まだしてない)

初期セットアップ

まずは、プロジェクトを作ります。
npm create astro@latest
対話形式で環境を制作できます。 まずはプロジェクトのディレクトリを作ります。 今回はAstroBlogとしています。 サンプルファイルやブログのテンプレートを使うか、必要最低限の空の状態にするかと聞かれるので、今回はEmptyを十字キーで選びます。 依存関係をインストールするかと聞かれるので、Yesを選択します。 TypeScriptを使うかと聞かれるので、今回はNoを選択します。 最後にgitリポジトリをイニシャライズするかと聞かれるのでYesを選択します(リポジトリがすでにある場合はNoを選択)。 これで初期セットアップは完了です。 インストールが終わると
/
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public
│   └── favicon.svg
├── src
│   ├── env.d.ts
│   └── pages
│       └── index.astro
└── tsconfig.json
このようなディレクトリができあがるので、開発環境を起動します。
npm run dev
http://localhost:3000/にアクセスするとプレーンな画面が開きます。

Indexファイルと共通レイアウト

では早速さわっていきましょう。 /src/pages/index.astroを開きます。
---
---

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
        <meta name="viewport" content="width=device-width" />
        <meta name="generator" content={Astro.generator} />
        <title>Astro</title>
    </head>
    <body>
        <h1>Astro</h1>
    </body>
</html>
とりあえずこれを必要最低限に編集します。
---
---

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>Astro</title>
    </head>
    <body>
        <h1>Astro</h1>
    </body>
</html>
続いてページを跨いで利用できる共通のレイアウトを作ります。 /src/layoutslayout.astroを作ります。 <slot />にはこのレイアウトを使うページのコンテンツが挿入されます。
---
---

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>Astro</title>
    </head>
    <body>
        <!-- ここにコンテンツが入る -->
        <slot />
    </body>
</html>
/src/pages/index.astroをレイアウトを使うように変更します。
---
import Layout from '../layouts/layout.astro';
---
<Layout>
    <h1>Astro</h1>
</Layout>
このままだとTitleがどのページも『Astro』になってしまうので変数化します。 /src/layouts/layout.astroを編集します。
---
// ページから渡ってきたtitleを取得
const { title } = Astro.props
---

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>{ title }</title>
    </head>
    <body>
        <!-- ここにコンテンツが入る -->
        <slot />
    </body>
</html>
続いて/src/pages/index.astroも編集します。
---
import Layout from '../layouts/layout.astro';
---
<Layout title="Indexページ">
    <h1>Astro</h1>
</Layout>
/src/pagespage.astroを作ります。
---
import Layout from '../layouts/layout.astro';
---
<Layout title="Pageページ">
    <h1>Page</h1>
</Layout>
こちらもちゃんとタイトルが変わっています。

記事の作成

ブログの記事を作っていくのですが、AstroはMarkdownをサポートしているので、Markdownで書いてみます。 /src/pages/posts/article01.mdを作ります。
# article01

article01のテキストが入ります。
このままだとtitleもなくプレーンなテキストが出るだけなので、こちらもレイアウトを使うように変更します。
---
layout: '../../layouts/PostLayout.astro'
title: 'article01ページ'
---

# article01

article01のテキストが入ります。
http://localhost:3000/posts/article01にアクセスすると記事ページが表示されます。 しかし、タイトルを設定しているのに反映されていません。 layoutに値が渡っているか見てみます。
---
// ページから渡ってきたtitleを取得
const { title } = Astro.props
console.log(Astro.props);
---

<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>{ title }</title>
    </head>
    <body>
        <!-- ここにコンテンツが入る -->
        <slot />
    </body>
</html>
console.logを書いて、http://localhost:3000/にアクセスします。 コンソールを見てみると
{ title: 'Indexページ' }
{
  file: '/Users/takanashi66/Desktop/AstroBlog/src/pages/posts/article01.md',
  url: '/posts/article01',
  content: {
    title: 'article01ページ',
    file: '/Users/takanashi66/Desktop/AstroBlog/src/pages/posts/article01.md',
    url: '/posts/article01'
  },
  frontmatter: {
    title: 'article01ページ',
    file: '/Users/takanashi66/Desktop/AstroBlog/src/pages/posts/article01.md',
    url: '/posts/article01'
  },
  headings: [ { depth: 1, slug: 'article01', text: 'article01' } ],
  rawContent: [Function: rawContent],
  compiledContent: [Function: compiledContent],
  'server:root': true
}
と出ています。 titleを探してみると indexは
{ title: 'Indexページ' }
article01は
{
  〜略〜
  frontmatter: {
    title: 'article01ページ',
    file: '/Users/takanashi66/Desktop/AstroBlog/src/pages/posts/article01.md',
    url: '/posts/article01'
  },
  〜略〜
}
frontmatterというプロパティの中に入っています。 ページ(.astro)と記事(.md)では値の渡し方、持ち方が違うようです。 なので/src/layouts/layout.astroをページに応じて値を代入するように編集します。
---
// ページから渡ってきたtitleを取得
const { title } = Astro.props.frontmatter || Astro.props;
// console.log(Astro.props);
---

~略~
改めてhttp://localhost:3000/posts/article01にアクセスするとちゃんとタイトルが出ました。

記事の時だけ親要素を追加する

さて、Indexページとarticle01ページでは両方bodyの直下にコンテンツが出てきます。 それぞれのページで別のスタイルを当てたい場合など、astroファイルならHTMLが直接書けるので、問題ないですがMarkdownではそうもいかないので、layoutで対応していきます。 /src/layouts/postLayout.astroを作ります。
---
import Layout from '../layouts/layout.astro';
const { title } = Astro.props.frontmatter;
---
<Layout title={title}>
    <article class="post">
        <slot />
    </article>
</Layout>
レイアウトファイルの中からさらにレイアウトファイルを呼ぶことで、共通レイアウトを維持したまま親要素をコントロールすることができます。

記事一覧の作成

/src/pages/posts/article01.mdをコピーしてarticle02.mdを作ります。
---
layout: '../../layouts/layout.astro'
title: 'article02ページ'
---

# article02

article02のテキストが入ります。
/src/pages/index.astroのIndexページに記事の一覧が出るようにしましょう。 Astro.globを使って.mdファイルを取得します。 取得した.mdファイルの情報をmapで回してURLとtitleを出力します。
---
import Layout from '../layouts/layout.astro';
// posts内の.mdファイルを取得
const posts = await Astro.glob('./posts/**/*.md')
---
<Layout title="Indexページ">
    
    <h1>Astro</h1>
    
    <h2>記事一覧</h2>
    
    <ul>
        {
            posts.map(post => {
                return <li><a href={post.url}>{post.frontmatter.title}</a></li>
            })
        }
    </ul>
    
</Layout>
記事の一覧のリンクが出力されました。

Build

最後に公開用のファイルを出力します。
npm run build
すると distというディレクトリが作られ、そこにHTMLが出力されます。
dist
├── favicon.svg
├── index.html
├── page
│   └── index.html
└── posts
    ├── article01
    │   └── index.html
    └── article02
        └── index.html

参考

Astro

Astroで爆速Markdownブログ構築

トップへ戻る