最近 AstroというWebサイト構築ツールが話題になっているようなので試してみました。
Astroはブログや企業のホームページを作ったりするためのツールです。この分野ではWordPressが有名ですが、性能やセキュリティーの面からGatsbyやHugoなどのSSG (Static Site Generators)も使われるようになって来ています、Astroも同じくSSGツールです。
Astroとは
Astroのサイトには日本語のドキュメントもありますよ😁
Astroを選ぶ理由には以下のように書かれています。
- コンテンツ重視: Astroは、コンテンツが豊富なWebサイトのために設計されています。
- サーバーファースト: HTMLをサーバーでレンダリングすることで、Webサイトの動作が速くなります。
- デフォルトで高速: Astroで遅いウェブサイトを構築することは不可能です。
- 簡単に使える: 専門家でなくても、Astroで何かを構築できます。
- 充実した機能と柔軟性: 100以上のAstroインテグレーションから選択できます。
興味を持った方は、Astroを選ぶ理由ページを読んで下さい。
さらに主な特長には以下のような技術的な特徴が書かれています。
- コンポーネントアイランド: 高速なウェブサイトを構築するための新しいウェブアーキテクチャー。
- サーバーファーストのAPI設計: ユーザーのデバイスから高コストのハイドレーションをなくします。
- デフォルトでゼロJS: サイトを遅くするJavaScriptランタイムオーバーヘッドはありません。
- エッジ対応: DenoやCloudflareのようなグローバルなエッジを含め、どこでもデプロイできます。
- カスタマイズ可能: Tailwind、MDX、その他100以上のインテグレーションから選択可能です。
- 特定のUIに依存しない: React、Preact、Svelte、Vue、Solid、Litなどをサポートします。
ざっくり言うと、WordPressにかわるナウなWebサイト構築ツールです。
EY-Officeサイト
さて、このブログを含むEY-OfficeのホームページはJekyllというRubyで書かれたSSG(Static Site Generators)を使っています。
しかしサイトの更新速度が遅いなどの問題もあり、JavaScriptベースのSSGに乗り換えようと試みて来ましたEY-OfficeサイトもJamstackブームに乗ってみようと思う(1)、 (2)、 (3)、 (4) に書いたようにNext.jsのSSGに乗り換えようとしたのですが頓挫してしまいました。
ある程度Next.js版が動くようになってみると、ページの生成が遅いのです。その後のNext.jsのバージョンアップで差分更新が実装されたらしいですが・・・やる気が無くなっていました😅
EY-Officeブログを考慮したブログサイトをAstroで作ってみた
AstroでEY-Officeブログ(サイト)を作り直す場合に考慮しなくてはいけないのは、
- 生成されるサイトのURLは現在と同じ
- できるだけ、現在のブログ記事が使えるようにする
です、1.はマストです。
そこで、今回は以下のような現状と同じファイル構造のブログ記事から
└── src
└── pages
└── _blog
├── 2022-12-01-thought-about-reskilling.md
├── 2022-12-06-what-about-my-next-development-mac.md
└── 2022-12-13-wonders-of-the-chai-assertion-framework.md
現状と同じURLのサイトが構築される事を目標に作りました
http://localhost:3000/blog/2022/12/01/thought-about-reskilling
最初のブログ記事http://localhost:3000/blog/2022/12/06/what-about-my-next-development-mac
2番目のブログ記事http://localhost:3000/blog/2022/12/13/wonders-of-the-chai-assertion-framework
3番目のブログ記事
コードの解説
今回作ったブログ・サイトのコードはGitHubに置きましたが、Astro説明もかねて一部コードの説明してみます。
├── README.md
├── astro.config.mjs ← ①
├── package-lock.json
├── package.json ← ②
├── public ← ③
│ ├── favicon.svg
│ └── images
│ ├── Masala-Chai.jpg
│ ├── pcs.png
│ └── reskilling.png
├── src
│ ├── components ← ④
│ │ └── Card.astro
│ ├── env.d.ts
│ ├── layouts ← ⑤
│ │ └── Layout.astro
│ ├── pages ← ⑥
│ │ ├── _blog ← ⑦
│ │ │ ├── 2022-12-01-thought-about-reskilling.md
│ │ │ ├── 2022-12-06-what-about-my-next-development-mac.md
│ │ │ └── 2022-12-13-wonders-of-the-chai-assertion-framework.md
│ │ ├── blog
│ │ │ ├── [y]
│ │ │ │ └── [m]
│ │ │ │ └── [d]
│ │ │ │ └── [name].astro ← ⑧
│ │ │ └── index.astro ← ⑨
│ │ └── index.astro ← ⑩
│ └── utils
│ └── BlogPath.ts ← ⑪
└── tsconfig.json ← ⑫
Astroの基本
⑩ .astroファイル src/pages/index.astro
.astroファイルはAstroのコンテンツやコンポーネント等を作る、とっとも基本的なファイルで以下のように---
に挟まれた上部はコンポーネントスクリプトと呼ばれJavaScriptのコードが書けます。
- この例ではLayout、Cardと呼ばれるコンポーネントを
import
文で取り込んでいます。
---
の下の部分はコンポーネントテンプレートと呼ばれHTMLとCSSが書かれます。
- Vue.jsのように、HTMLと、このHTML使うCSSが
<style>
内に書けます- HTMLタグのclass名は1つの.astroファイル内に限定されるので便利
- ReactやVue.jsと同じく大文字から始まるタグはコンポーネントです。コンポーネントには属性を通じてプロパティー(引数)を渡せます
---
import Layout from '../layouts/Layout.astro';
import Card from '../components/Card.astro';
---
<Layout title="Welcome to Astro.">
<main>
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<ul role="list" class="link-card-grid">
<Card
href="/blog"
title="ブログ"
body="将来のEY-Officeブログに向けてのスタート"
/>
</ul>
</main>
</Layout>
<style>
main {
margin: auto;
padding: 1.5rem;
max-width: 60ch;
}
・・・省略・・・
</style>
④ コンポーネント src/components/Card.astro
コンポーネントのコンポーネントスクリプトには、プロパティーの宣言とAstro.props
でプロパティーを取出すコードが書かれています。
コンポーネントテンプレート内の{・・・}
は、React同様にJavaScriptの値が取得でき、生成されるHTMLに埋め込まれます。
---
export interface Props {
title: string;
body: string;
href: string;
}
const { href, title, body } = Astro.props;
---
<li class="link-card">
<a href={href}>
<h2>
{title}
<span>→</span>
</h2>
<p>
{body}
</p>
</a>
</li>
<style>
・・・省略・・・
</style>
⑤ レイアウト src/layouts/Layout.astro
レイアウトもコンポーネントです。<slot />
タグのところにコンテンツが入ります
---
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body style="width: 80%; margin: 0 auto 0 auto;">
<slot />
</body>
</html>
<style is:global>
・・・省略・・・
</style>
⑦ Markdwon src/pages/_blog/2022-12-01-thought-about-reskilling.md
コンテンツには標準でMarkdownも使えます。コンポーネントスクリプトにはレイアウトの指定や、レイアウト.astro内で参照できるfrontmatter
オブジェクトのプロパティーを設定できます。
---
title: リスキリングに付いて考えてみた
---
最近**リスキリング**という言葉をよく聞くようになってきましたね。
🐿️リス・Killingじゃないですよ、Reskilling (Re・skill・ing)です。
なぜ日本でこの言葉が使われだしたのでしょうか?
[リスキリングとは - 経済産業省(PDF)](https://www.meti.go.jp/shingikai/mono・・・.pdf)
このへんが元なのでしょうか ???
・・・省略・・・
③ public/
public/
ディレクトリー下には、HTMLから参照される画像などを置きます。
Astroの機能
⑥ pages
src/pages/
以下に置かれた.astro
、.md
コンテンツはそのまま公開される.html
に変換されます。また、フォルダーがあれば/フォルダー名/
のようにURLに対応します。
ただし、src/pages/_blog/
のようにアンダーラインから始まるディレクトリーは公開(変換)されません。
⑧ ダイナック・ルーティング src/pages/blog/[y]/[m]/[d]/[name].astro
フォルダーやファイル名に[・・・]
(ブラケット)が含まれる場合は.astro
ファイル内で指定されたパスに変換されます。ここでは[y]/[m]/[d]/[name]
が2022/12/01/thought-about-reskilling
のように変換されます。
getStaticPaths()
関数はパス名やプロパティーを戻す関数です、ここに戻すparamsの値がブラケットに対応しますAstro.glob('/src/pages/_blog/*.md')
は/src/pages/_blog/
ディレクトリーにある全.md
ファイルのコンテンツの配列を戻しますblogParms()
関数はコンテンツのファイル名が対応するy, m, d, name
の値を戻します(詳細は後で説明します)。- プロパティー
props
にはHTMLに変換されたコンテンツとタイトルを戻します
getStaticPaths()
関数の戻り値に対応したコンポーネントテンプレートを使いコンテンツが作成されますAstro.params
、Astro.props
でgetStaticPaths()
関数が戻した値を取得- レイアウトは
<Layout>
を利用 <p>
でブログの日付を表示<h1>
でブログのタイトルを表示<div>
内にブログのコンテンツが表示
---
import Layout from '@layouts/Layout.astro';
import { blogParms } from '@utils/BlogPath';
export async function getStaticPaths() {
const posts = await Astro.glob('/src/pages/_blog/*.md');
const paths = posts.map(post => {
return {
params: blogParms(post),
props: { post: post.compiledContent(), title: post.frontmatter.title}
};
})
return paths;
}
const { y, m, d } = Astro.params;
const { post, title } = Astro.props;
---
<Layout title={title}>
<p style="color: gray">{y}-{m}-{d}</p>
<h1>{title}</h1>
<hr/>
<div set:html={post} />
</Layout>
⑪ JavaScriptのコード src/utils/BlogPath.ts
ページ生成に関わるJavaScript(TypeScript)関数を定義できます。
blogParms
関数はコンテンツのファイル名からy, m, d, nameを戻します2022-12-01-thought-about-reskilling.md
なら{y: '2022', m: '12', d: '01', name: 'thought-about-reskilling'}
が戻ります
blogUrl
関数はコンテンツに対応するURLを戻します2022-12-01-thought-about-reskilling.md
なら/blog/2022/12/01/thought-about-reskilling
が戻ります
import type { MarkdownInstance } from "astro";
export const blogParms = (post: MarkdownInstance<Record<string, any>>) => {
const [_, y, m, d, name] = post.file.match(/_blog\/(\d+)-(\d+)-(\d+)-(.+?).md/) ?? [0, 1,1,1,''];
return {y, m, d, name};
}
export const blogUrl = (post: MarkdownInstance<Record<string, any>>) => {
const p = blogParms(post);
return `/blog/${p.y}/${p.m}/${p.d}/${p.name}`;
};
⑨ 動的なコンテンツ src/pages/blog/index.astro
以下はブログ一覧ページの.astro
ファイルです。
ここではposts配列の内容から<li> 2022-12-01 : <a href="/blog/2022/12/01/thought-about-reskilling"> リスキリングに付いて考えてみた </a></li>
のような行を作成しています。コンテンツを動的に作る方法はReactのJSXに似ています。
---
import Layout from '@layouts/Layout.astro';
import { blogUrl, blogParms } from '@utils/BlogPath';
const posts = await Astro.glob('/src/pages/_blog/*.md');
---
<Layout title="Blog list">
<ul>
{posts.map(p => {
const {y,m,d} = blogParms(p)
return (<li> {`${y}-${m}-${d}`} : <a href={blogUrl(p)}> {p.frontmatter.title} </a></li>);
})}
</ul>
</Layout>
設定
① astro.config.mjs
Astroの設定ファイルです。詳細は省きますが、ここではMarkdownのシンタックスハイライトの設定をしています。
import { defineConfig } from 'astro/config';
export default defineConfig({
markdown: {
shikiConfig: {
theme: 'light-plus',
langs: [],
wrap: true,
}
}
});
② package.json
変更はしていませんが、以下のようなコマンドが定義されています。
npm start
(npm run dev
) 開発環境の起動npm run build
公開用HTML/CSSの作成npm run preview
buildで作られたHTML/CSS表示用サーバーの起動
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
⑫ tsconfig.json
import fromで指定するパス内の @・・・ の定義、ここでは@utils
、@layouts
を定義しています。
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@utils/*": ["src/utils/*"],
"@layouts/*": ["src/layouts/*"]
}
}
}
まとめ
Astroは使いやすいWebサイト構築ツールだと思います。とくに少しでもReactやVue.jsを使った方には簡単に使えると思います。
ビルドの時間も短く、日本語ドキュメントもあり、とてもお薦めのツールだと思います。
JekyllからNext.jsのSSGに乗り換えは失敗しましたが、Astroへの乗り換えは出来そうな気がします。