AstroとSvelteでStaticサイトを作って、GitHub Actions で定期的に情報を取得更新するようにした
はじめに
趣味領域で作っているNext.js StaticExport製の静的サイトがあるのですが、ページ数が5000弱であること、Next.jsの高い更新頻度に付いていくのが大変であるなどの理由から、リプレースを考えていました。その時にちょうどAstroがV2.2に達したTweetを見かけたので、Reactで動いているoriverk.devをAstroのPlayground代わりにしようと思いました。
- reference
Astroとは
Astro is the all-in-one web framework designed for speed. Pull your content from anywhere and deploy everywhere, all powered by your favorite UI components and libraries.
速度重視で、他のUIフレームワークも使えるオールインワンのWebフレームワークです(意訳)。実際にAstroではSSGとSSRの両方を作ることが出来、ReactやVue、Svelteなども混ぜて使うことが出来ます。
コード先頭にmarkdownのfrontmatterの様なものがあることを除けば、ぱっと見はSvelteやVueの様で、if文や繰り返し箇所はReactのJSXの様な感じです。
index.astro
---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"> {[...Array(2)].map((_, i) => ( <Card href={`https://astro.build/docs/${i === 0 ? '' : i}`} title={`Documentation ${i === 0 ? '' : i}`} /> ))} </ul> </main></Layout>
<style> main { margin: auto; padding: 1.5rem; max-width: 60ch; } h1 { font-size: 3rem; font-weight: 800; margin: 0; }</style>
AstroとSvelteを使った感想
よかったこと
- Astro自体が非常に単純で理解しやすい(Next.js比
- astro.configでmdファイルの取り扱いが設定でき、あれやこれやとuntil functionを書かずともfrontmatterを取得したり、htmlにコンパイルできる
- よいこととは実感してないけどリポジトリサイズが非常に小さい
- 3.34MB: oriverk/oriverk.dev
- 593KB: oriverk/astro-site
- 3.34MB: oriverk/oriverk.dev
よくはなかったこと・ふつごうだったこと
.astro
でのevent handlingにはdocument.querySelector
などと書く必要がある- Scripts and Event Handling 🚀 Astro Documentation
- SvelteなどのUIフレームワークを使う必要がある主因だと思う
- Scripts and Event Handling 🚀 Astro Documentation
- Astroの構文がReactとVue/Svelteの中間みたいで、if文やeach文を書くときに困惑する
- 経験により解消されるとは思う。
.astro
上でUIフレームワークコンポネントを呼び出す際に、両者との微妙な違いにより困ることがある。- GitHub上で scriptやstyle領域がハイライトされない
- SvelteもVueもされない
サイトについて
主に以下のような機能をもったサイトにしたいと考えました。
- Static Siteである
- GitHubのPinned ReposとContribution Calendar(GitHub草)を表示できる
- blog.oriverk.devのコンテンツを取得表示できる
- Cloudflare Pagesにデプロイし、サイトデータを自動で更新できる
また、以前にoriverk.devをReactで作ったときの感じを踏襲したいとも考えていました。
主に使用したもの
Astroだけでもサイトは作れますが、Astroと他UIフレームワークを使った場合の感じを知りたかったので、軽量さに共通点を持つSvelteをUIフレーム枠に採用しました。全体的なview?の/pagesはastroファイルで作り、componentsはsvelteという風に使い分けました。
- Astro
- Svelte • Cybernetically enhanced web apps
- fetcher
- linter
Init astro app
npm create astro@latest -- --template basics
AstroとAstronautを掛けているのか、Houstonという名前の顔文字が動いてて可愛いかったです。


npm i -D npm-run-allnpm i -D @commitlint/{config-conventional,cli}# echo '{"extends": ["@commitlint/config-conventional"]}' > .commitlintrc.json
npm install -D eslint @typescript-eslint/parser eslint-plugin-{astro,jsx-a11y,import} eslint-import-resolver-typescriptnpm install -D prettier prettier-plugin-astro eslint-config-prettier# echo {} > .prettierrc.json
npx husky-init && npm installnpx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
npx astro add svelte
npm i sass cssnano autoprefixer
code linterの設定
AstroとSvelteを混ぜるので当然なのですが、両者用の設定が必要でした。なので、init svelte appの箇所に加えて
npm i -D eslint-plugin-svelte3 prettier-plugin-svelte
ESLint config
他レポジトリで使っていたsvelte用のconfigと混ぜる形で作りました。Svelteは今年に入って触ったばかりなので、設定が正しい状態にあるかは分かりませんが、動いてます。
.eslintrc.yml
extends: - plugin:astro/recommended - plugin:jsx-a11y/recommended - plugin:import/recommended - plugin:import/typescript - prettieroverrides: - files: - '*.astro' parser: astro-eslint-parser parserOptions: parser: '@typescript-eslint/parser' extraFileExtensions: - .astro rules: {} - files: - '*.svelte' processor: svelte3/svelte3 parserOptions: parser: '@typescript-eslint/parser' extraFileExtensions: - .svelte rules: {} settings: svelte3/typescript: trueparser: '@typescript-eslint/parser'parserOptions: ecmaVersion: latest sourceType: moduleplugins: - svelte3 - '@typescript-eslint'ignorePatterns: - './dist/**/*'settings: {}
Prettier config
trailingComma: es5tabWidth: 2semi: falsesingleQuote: trueplugins: - prettier-plugin-astro - prettier-plugin-sveltepluginSearchDirs: false
ChatGPTとGitHub GraphQL API
GitHub API は以前に何度か利用したことがあって、ドキュメントが割と重く長いことを覚えていたので、時間節約のためにChatGPTを利用しました。ChatGPTに尋ねたところ、ChatGPTのバージョンは3.5でデータは2021年9月までのものらしく、例えば21年10月以降に変わった内容については正確には答えることが出来ません。なので、ChatGPTが出力したクエリをGitHub GraphQl API Explorerで試して正常に動くかを確認し、クエリを調整することにしました。
GitHub GraphQL API を用いて、ユーザ名oriverkのpinned repository と contribution calendar のデータを取得せよ
ChatGPT-3.5 出力結果
query { user(login: "oriverk") { pinnedItems(first: 6) { nodes { ... on Repository { name description url stargazers { totalCount } forkCount } } } contributionsCollection { contributionCalendar { totalContributions weeks { contributionDays { contributionCount date } } } } }}
Explorerで問題なく動くことを検証し、必要/不必要なデータを取得するために公式ドキュメントを片手に適宜クエリを修正し、利用しました。
Contribution Calendar(GitHub草)
描画するためのSvelteライブラリは複数ありましたが、その多くが更新を止めていました。なので、ライブラリを使わずに作ることにしました。
RSS fetcher
基本的にCatNose氏の下記「RSS集約サイト」に倣いました。なので割愛します。
- チーム個々人のテックブログをRSSで集約するサイトを作った(Next.js)
- catnose99/team-blog-hub: RSS based blog starter kit for teams
- catnose99/timeline: catnose's timeline
GitHub ActionsによるCloudflare Pagesへの定期的デプロイ
GitHub GraphQL API へのアクセスを少なするために、prebuildにてGitHubのユーザ情報と別レポジトリからの履歴書用mdファイル、oriverk.devのRSSを取得して、/contents
下にjsonファイルとして保存し、これらjsonファイルを利用してbuildしています。
{ "scripts": { "dev": "astro dev --project tsconfig.json", "start": "astro dev", "prebuild": "run-s prebuild:*", "build": "astro build", "preview": "astro preview", }}
GitHub Actionsでもこれを利用するようにしました。
workflows/deploy.yml
name: continuous-deploymenton: push: branches: - main - dev schedule: - cron: "0 2 * * *" workflow_dispatch:
jobs: publish: runs-on: ubuntu-latest permissions: contents: read deployments: write name: build and deploy to Cloudflare Pages steps: - name: checkout uses: actions/checkout@v3
# Run a build step here if your project requires - name: setup node uses: actions/setup-node@v3 with: node-version: 18
- name: install packages and build run: | npm install npm run build env: MODE: production SECRET_GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.SECRET_GITHUB_PERSONAL_ACCESS_TOKEN }} PUBLIC_GA_MEASUREMENT_ID: ${{ secrets.PUBLIC_GA_MEASUREMENT_ID }}
- name: deploy to Cloudflare Pages uses: cloudflare/pages-action@v1 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: astro-site directory: dist
- astro-site/deploy.yml at main · oriverk/astro-site · GitHub
- Cloudflare Pages GitHub Action · Actions · GitHub Marketplace
AstroでGoogle Analytics
エラー類
Astroとその他のUIフレームワーク(今回はSvelte)を混ぜる構成なので、どちらに起因するか見極める必要性があり、また両者の組み合わせによるエラーは公式ドキュメントには当然書いてないので、そういったところは大変だなあと感じました。
date-fns/locale
svelte と date-fns
Directory import '/home/oriverk/Codes/oriverk/astro-site/node_modules/date-fns/locale/ja' is not supported resolving ES modules imported from /home/oriverk/Codes/oriverk/astro-site/dist/entry.mjsDid you mean to import date-fns/locale/ja/index.js?
- import { ja } from 'date-fns/locale'+ import ja from 'date-fns/locale/ja/index.js'
CSS Logical Media Query error
Media Queries Level 4からの下記の様な書き方は、Svelteにおいては次のバージョンから使える模様。
@media (max-width: 30em) { ... }
- メディアクエリーの使用 - CSS: カスケーディングスタイルシート | MDN
- CSS Logical Media Query error · Issue #8324 · sveltejs/svelte