はじめに
こんにちは。debiru です。
今日は GitHub Pages を使って Astro を用いた Web サイトをデプロイする手順を紹介します。
自動デプロイスクリプトを用意したので、以下の 1. 〜 6. のセクションの手順を実施するだけで Astro サイトが爆誕します。
なお、今回は BeautifulCode を実現します。BeautifulCode とは、出力される HTML, CSS, JS のソースコードの可読性を担保することを指します。出力ソースコードの圧縮などをせず、インデントの整った美しいソースコードを提供することを目指します。
1. GitHub にリポジトリを作成する
- お好きなリポジトリ名を入力します
- リポジトリの公開範囲は Public にします
- Add a README file にチェックを入れます
そして Create Repository ボタンを押します。
2. GitHub Pages で使うドメイン名の DNS 設定を行う
例えば https://astro.debiru.net
という URL でサイトを公開したい場合、astro.debiru.net
のドメイン名に対する DNS 設定を行います。
このマニュアルを参考に、頂点ドメイン名(debiru.net
など)の場合は A レコードを、サブドメイン(astro.debiru.net
など)の場合は CNAME レコードを設定します。ただしサブドメインであっても、他のレコード(MX や TXT など)を設定している場合は、頂点ドメイン名と同様に A レコードを用いて設定してください。
3. GitHub Pages の設定を行う
作成したリポジトリの GitHub 上のページで、上部のグローバルメニューから Settings
を選び、左サイドバーにある Pages
を選びます。
- Source から
GitHub Actions
を選んでおきます
- Custom domain に、使いたいドメイン名を入力します
- Enforce HTTPS にチェックを入れます(チェックが入れられない場合は、ページをリロードしてみてください)
4. リポジトリを clone する
作成したリポジトリを手元の作業 PC 上に clone します。
astro
というリポジトリ名の場合は次のような感じのコマンドになるはずです。
git clone git@github.com:YOURNAME/astro.git
# clone したリポジトリに移動する
cd astro
5. Node と npm のインストール
もし手元の PC 上で node がインストールされていなければ、node をインストールします。
node -v
npm -v
それぞれ、バージョン情報が表示されれば OK です。最新安定版(2025年1月時点で node 22.x, npm 11.x)を使っていればなお良いです。
node のインストール手順が分からない方は @debiru_R までお尋ねください。mise などのパッケージ管理ソフトを使うとよいでしょう。
6. Astro 環境を自動で構築する
注意:以下のように外部シェルスクリプトを実行する際は、スクリプトの中身が安全かどうかを確かめてから実行するようにしてください。
スクリプトの中身は https://astro.debiru.net でも紹介しています。
curl -fsSLO https://astro.debiru.net/build/astro-starter-kit.sh
chmod +x astro-starter-kit.sh
# スクリプトの中身を確認する
cat astro-starter-kit.sh
# Astro Starter Kit をインストールする
# astro.debiru.net の部分は、実際に利用したいドメイン名を指定してください
# ./astro-starter-kit.sh astro.debiru.net
./astro-starter-kit.sh
git push
これでデプロイ処理が実行されます。デプロイには30秒ほどかかるかもしれません。
作成したリポジトリの GitHub 上のページにアクセスして、画面上部の最終コミットログにチェックマークが付いているかを確認してください。
チェックマークが付いていれば、指定したドメイン名の URL(https://astro.debiru.net のような URL)にアクセスすることで Astro のサイトが閲覧できるはずです。
内部処理について読まなくてもよいという方は「#おわりに」へお進みください。
次のセクションでは、このスターターキット自動スクリプトが内部的に何を行っているかについて説明します。
Astro 環境を手動で構築する
以下は手動での Astro 環境構築手順ですが、これはスターターキット自動スクリプトで実行している処理内容です。
Astro プロジェクトを作成する
npm create astro@latest project -- --template minimal --no-install --no-git
mv project/{*,.*} . && rm -r project
npm install
git commit しておく(1回目)
git add .
git commit -m "npm create astro@latest"
.gitignore を編集する
デフォルトでは dist/
と書かれていますが、これを /dist/
に変更します。
後々、public の中で dist ディレクトリを使いたいケースに対応できなくなるため、この変更を行っておきます。
diff --git a/.gitignore b/.gitignore
index 016b59e..a34f621 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
# build output
-dist/
+/dist/
# generated types
.astro
git commit しておく(2回目)
git add .
git commit -m "update .gitignore"
.github/workflows/deploy.yml を作成する
mkdir -p .github/workflows
touch .github/workflows/deploy.yml
.github/workflows/deploy.yml
を編集して、以下の内容にします。
もし、Git のブランチ名が main
でなければ、5行目のブランチ名の部分は変更してください。
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout your repository using git
uses: actions/checkout@v4
- name: Install, build, and upload your site
uses: withastro/action@v3
with:
node-version: 22
package-manager: npm@latest
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
git commit しておく(3回目)
git add .
git commit -m "add .github/workflows/deploy.yml"
src ディレクトリを空にする
デフォルトで作成される src ファイルを削除しておきます。
rm -r src && mkdir src
git commit しておく(4回目)
git add .
git commit -m "remove default src files"
package.json を更新する
diff --git a/package.json b/package.json
index 65e3364..9962f52 100644
--- a/package.json
+++ b/package.json
@@ -4,11 +4,13 @@
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
- "build": "astro build",
+ "build": "build/build.sh && astro build",
+ "watch": "build/watch.sh",
+ "stylelint": "build/stylelint.sh",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^5.1.10"
}
-}
\ No newline at end of file
+}
npm install -D glob js-beautify sass stylelint stylelint-config-standard
git commit しておく(5回目)
git add .
git commit -m "update package.json"
スターターキットを用意する
- sass, stylelint の実行を可能にする
- css, js, scss, img のアセットファイルを用意する
-
src/config/myExtIntegration.mjs
で Astro のビルド結果を加工する -
src/config/view.mjs
でページ共通の初期設定をする -
src/pages
でサンプルページを用意する
new file: .stylelintrc.json
modified: astro.config.mjs
new file: build/build.sh
new file: build/sass-compile.sh
new file: build/sass-watch.sh
new file: build/stylelint.sh
new file: build/watch.sh
new file: public/assets/css/global/reset.css
new file: public/assets/css/global/style.css
new file: public/assets/css/subpage/style.css
new file: public/assets/img/global/logo.png
new file: public/assets/img/global/og.png
new file: public/assets/js/global/base.js
new file: public/assets/js/subpage/script.js
new file: public/assets/scss/global/reset.scss
new file: public/assets/scss/global/style.scss
new file: public/assets/scss/subpage/style.scss
new file: public/favicon.ico
new file: src/config/Util.mjs
new file: src/config/myExtIntegration.mjs
new file: src/config/view.mjs
new file: src/layouts/Layout.astro
new file: src/pages/index.astro
new file: src/pages/subpage/index.astro
スターターキットの差分
ファイルの内容を示すために、上記ファイル群の git diff
の結果を貼っておきます。
-
astro.config.mjs
のsite: 'https://astro.debiru.net'
部分は、ご自身の GitHub Pages に設定したい URL を指定してください
diff --git a/.stylelintrc.json b/.stylelintrc.json
new file mode 100644
index 0000000..3832116
--- /dev/null
+++ b/.stylelintrc.json
@@ -0,0 +1,16 @@
+{
+ "extends": "stylelint-config-standard",
+ "rules": {
+ "alpha-value-notation": null,
+ "custom-property-pattern": null,
+ "declaration-block-no-redundant-longhand-properties": null,
+ "no-descending-specificity": null,
+ "no-empty-source": null,
+ "property-no-vendor-prefix": null,
+ "selector-class-pattern": null,
+ "selector-id-pattern": null,
+ "rule-empty-line-before": null,
+ "selector-attribute-quotes": null,
+ "value-keyword-case": null
+ }
+}
diff --git a/astro.config.mjs b/astro.config.mjs
index e762ba5..f333444 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -1,5 +1,13 @@
-// @ts-check
import { defineConfig } from 'astro/config';
+import myExtIntegration from '/src/config/myExtIntegration';
-// https://astro.build/config
-export default defineConfig({});
+// refs. https://astro.build/config
+export default defineConfig({
+ site: 'https://astro.debiru.net',
+ trailingSlash: 'ignore',
+ compressHTML: false,
+ integrations: [myExtIntegration()],
+ build: {
+ format: 'file',
+ },
+});
diff --git a/build/build.sh b/build/build.sh
new file mode 100755
index 0000000..7a7be25
--- /dev/null
+++ b/build/build.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+cd $(dirname $0)
+
+./sass-compile.sh
+./stylelint.sh
diff --git a/build/sass-compile.sh b/build/sass-compile.sh
new file mode 100755
index 0000000..dc59db8
--- /dev/null
+++ b/build/sass-compile.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+cd $(dirname $0)/..
+
+CSS_DIR="public/assets/css"
+SCSS_DIR="public/assets/scss"
+
+rm -r "${CSS_DIR}"
+npx sass --no-source-map "${SCSS_DIR}:${CSS_DIR}"
diff --git a/build/sass-watch.sh b/build/sass-watch.sh
new file mode 100755
index 0000000..194d364
--- /dev/null
+++ b/build/sass-watch.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+cd $(dirname $0)/..
+
+CSS_DIR="public/assets/css"
+SCSS_DIR="public/assets/scss"
+
+npx sass --watch --no-source-map "${SCSS_DIR}:${CSS_DIR}"
diff --git a/build/stylelint.sh b/build/stylelint.sh
new file mode 100755
index 0000000..2764123
--- /dev/null
+++ b/build/stylelint.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+cd $(dirname $0)/..
+
+npx stylelint "public/assets/css/**/*.css"
diff --git a/build/watch.sh b/build/watch.sh
new file mode 100755
index 0000000..3423ea6
--- /dev/null
+++ b/build/watch.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+cd $(dirname $0)
+
+./build.sh
+./sass-watch.sh
diff --git a/public/assets/css/global/reset.css b/public/assets/css/global/reset.css
new file mode 100644
index 0000000..bca856a
--- /dev/null
+++ b/public/assets/css/global/reset.css
@@ -0,0 +1,98 @@
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font: inherit;
+ font-size: 100%;
+ vertical-align: baseline;
+}
+
+html {
+ line-height: 1;
+}
+
+ol, ul {
+ list-style: none;
+}
+
+table {
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+caption, th, td {
+ text-align: left;
+ font-weight: normal;
+ vertical-align: middle;
+}
+
+q, blockquote {
+ quotes: none;
+}
+
+q::before, q::after, blockquote::before, blockquote::after {
+ content: "";
+ content: none;
+}
+
+a img {
+ border: none;
+}
+
+article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
+ display: block;
+}
+
+sup, sub {
+ font-size: 75%;
+}
+
+sup {
+ vertical-align: super;
+}
+
+sub {
+ vertical-align: sub;
+}
+
+textarea, pre {
+ font-family: monospace;
+}
+
+b, strong {
+ font-weight: bold;
+}
+
+i, em {
+ font-style: italic;
+}
+
+hr {
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+select {
+ font-size: 100%;
+}
+
+img, iframe, video {
+ vertical-align: top;
+}
+
+button {
+ cursor: pointer;
+}
diff --git a/public/assets/css/global/style.css b/public/assets/css/global/style.css
new file mode 100644
index 0000000..2babb3d
--- /dev/null
+++ b/public/assets/css/global/style.css
@@ -0,0 +1,64 @@
+html {
+ scroll-behavior: smooth;
+ font-size: 62.5%;
+}
+
+body {
+ -webkit-text-size-adjust: 100%;
+ font-size: 1.6rem;
+}
+
+.wbr {
+ display: inline-block;
+}
+
+.content-inner {
+ max-width: 1080px;
+ margin-inline: auto;
+ padding-inline: 10px;
+}
+
+#page-container {
+ display: grid;
+ grid-template-rows: auto 1fr auto;
+ grid-template-columns: 100%;
+ min-width: 100dvw;
+ min-height: 100dvh;
+}
+
+#page-header .content-inner {
+ border-bottom: 1px solid #ccc;
+}
+#page-header .siteName {
+ padding-block: 8px;
+}
+
+#page-main {
+ text-align: center;
+}
+#page-main .content-inner > * {
+ margin-top: 30px;
+}
+#page-main h1 {
+ font-family: serif;
+ font-weight: bold;
+ font-size: 3.2rem;
+}
+
+#page-footer {
+ border-top: 1px solid #999;
+ background: #f0f0f0;
+}
+#page-footer .footerArea {
+ padding: 4px 8px 8px;
+}
+#page-footer .footerArea .copyright {
+ padding-top: 4px;
+ text-align: center;
+ font-family: Verdana, sans-serif;
+ font-size: 1.4rem;
+}
+#page-footer .footerArea .copyright img {
+ margin-top: -4px;
+ vertical-align: middle;
+}
diff --git a/public/assets/css/subpage/style.css b/public/assets/css/subpage/style.css
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/public/assets/css/subpage/style.css
@@ -0,0 +1 @@
+
diff --git a/public/assets/img/global/logo.png b/public/assets/img/global/logo.png
new file mode 100644
index 0000000..b6bbfcf
Binary files /dev/null and b/public/assets/img/global/logo.png differ
diff --git a/public/assets/img/global/og.png b/public/assets/img/global/og.png
new file mode 100644
index 0000000..ca5f53b
Binary files /dev/null and b/public/assets/img/global/og.png differ
diff --git a/public/assets/js/global/base.js b/public/assets/js/global/base.js
new file mode 100644
index 0000000..bedd521
--- /dev/null
+++ b/public/assets/js/global/base.js
@@ -0,0 +1,3 @@
+(function() {
+ 'use strict';
+})();
diff --git a/public/assets/js/subpage/script.js b/public/assets/js/subpage/script.js
new file mode 100644
index 0000000..bedd521
--- /dev/null
+++ b/public/assets/js/subpage/script.js
@@ -0,0 +1,3 @@
+(function() {
+ 'use strict';
+})();
diff --git a/public/assets/scss/global/reset.scss b/public/assets/scss/global/reset.scss
new file mode 100644
index 0000000..bca856a
--- /dev/null
+++ b/public/assets/scss/global/reset.scss
@@ -0,0 +1,98 @@
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font: inherit;
+ font-size: 100%;
+ vertical-align: baseline;
+}
+
+html {
+ line-height: 1;
+}
+
+ol, ul {
+ list-style: none;
+}
+
+table {
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+caption, th, td {
+ text-align: left;
+ font-weight: normal;
+ vertical-align: middle;
+}
+
+q, blockquote {
+ quotes: none;
+}
+
+q::before, q::after, blockquote::before, blockquote::after {
+ content: "";
+ content: none;
+}
+
+a img {
+ border: none;
+}
+
+article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
+ display: block;
+}
+
+sup, sub {
+ font-size: 75%;
+}
+
+sup {
+ vertical-align: super;
+}
+
+sub {
+ vertical-align: sub;
+}
+
+textarea, pre {
+ font-family: monospace;
+}
+
+b, strong {
+ font-weight: bold;
+}
+
+i, em {
+ font-style: italic;
+}
+
+hr {
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+select {
+ font-size: 100%;
+}
+
+img, iframe, video {
+ vertical-align: top;
+}
+
+button {
+ cursor: pointer;
+}
diff --git a/public/assets/scss/global/style.scss b/public/assets/scss/global/style.scss
new file mode 100644
index 0000000..fd8f696
--- /dev/null
+++ b/public/assets/scss/global/style.scss
@@ -0,0 +1,73 @@
+html {
+ scroll-behavior: smooth;
+ font-size: 62.5%;
+}
+
+body {
+ -webkit-text-size-adjust: 100%;
+ font-size: 1.6rem;
+}
+
+.wbr {
+ display: inline-block;
+}
+
+.content-inner {
+ max-width: 1080px;
+ margin-inline: auto;
+ padding-inline: 10px;
+}
+
+#page-container {
+ display: grid;
+ grid-template-rows: auto 1fr auto;
+ grid-template-columns: 100%;
+ min-width: 100dvw;
+ min-height: 100dvh;
+}
+
+#page-header {
+ .content-inner {
+ border-bottom: 1px solid #ccc;
+ }
+ .siteName {
+ padding-block: 8px;
+ }
+}
+
+#page-main {
+ text-align: center;
+
+ .content-inner {
+ > * {
+ margin-top: 30px;
+ }
+ }
+
+ h1 {
+ font-family: serif;
+ font-weight: bold;
+ font-size: 3.2rem;
+ }
+}
+
+#page-footer {
+ border-top: 1px solid #999;
+ background: #f0f0f0;
+
+ .footerArea {
+ padding: 4px 8px 8px;
+
+ .copyright {
+ padding-top: 4px;
+ text-align: center;
+ font-family: Verdana, sans-serif;
+ font-size: 1.4rem;
+
+ img {
+ margin-top: -4px;
+ vertical-align: middle;
+ }
+ }
+ }
+}
diff --git a/public/assets/scss/subpage/style.scss b/public/assets/scss/subpage/style.scss
new file mode 100644
index 0000000..e69de29
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..c35fc5f
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/src/config/Util.mjs b/src/config/Util.mjs
new file mode 100644
index 0000000..9405025
--- /dev/null
+++ b/src/config/Util.mjs
@@ -0,0 +1,35 @@
+const Util = {
+ HTML: {
+ escape(str) {
+ const map = {
+ '&': '&',
+ "'": ''',
+ '"': '"',
+ '<': '<',
+ '>': '>',
+ };
+ return str.replace(/[&'"<>]/g, (m) => map[m]);
+ },
+ },
+ RegExp: {
+ escape(str) {
+ return str.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&');
+ },
+ },
+ sprintf(format, ...args) {
+ let p = 0;
+ return format.replace(/%./g, function(m) {
+ if (m === '%%') return '%';
+ if (m === '%s') return args[p++];
+ return m;
+ });
+ },
+ ltrim(str, char = '/') {
+ return str.replaceAll(new RegExp(Util.sprintf('^[%s]+', Util.RegExp.escape(char)), 'g'), '');
+ },
+ rtrim(str, char = '/') {
+ return str.replaceAll(new RegExp(Util.sprintf('[%s]+$', Util.RegExp.escape(char)), 'g'), '');
+ },
+};
+
+export default Util;
diff --git a/src/config/myExtIntegration.mjs b/src/config/myExtIntegration.mjs
new file mode 100644
index 0000000..0ec965a
--- /dev/null
+++ b/src/config/myExtIntegration.mjs
@@ -0,0 +1,33 @@
+import fs from 'fs';
+import { globSync } from 'glob';
+import beautify from 'js-beautify';
+
+function htmlFormatter(filePath) {
+ const config = {
+ end_with_newline: true,
+ extra_liners: [],
+ indent_char: ' ',
+ indent_empty_lines: false,
+ indent_inner_html: false,
+ indent_scripts: 'keep',
+ indent_size: 2,
+ wrap_line_length: 0,
+ };
+
+ const inputHtml = fs.readFileSync(filePath, { encoding: 'utf8' });
+ const outputHtml = beautify.html(inputHtml, config);
+ fs.writeFileSync(filePath, outputHtml);
+}
+
+export default function() {
+ return {
+ name: 'myExt:integration',
+ hooks: {
+ 'astro:build:generated': (options) => {
+ globSync(`${options.dir.pathname}**/*.html`).forEach((filePath) => {
+ htmlFormatter(filePath);
+ });
+ },
+ },
+ };
+};
diff --git a/src/config/view.mjs b/src/config/view.mjs
new file mode 100644
index 0000000..38eeae1
--- /dev/null
+++ b/src/config/view.mjs
@@ -0,0 +1,45 @@
+import Util from '/src/config/Util';
+
+export const args = {
+ siteName: 'Astro Site',
+ titleSuffix: 'Generated by astro.debiru.net',
+ description: 'Astro Site Starter Kit',
+ twitter: '@YOUR_TWITTER_ID',
+};
+
+export const app = {
+ init(Astro) {
+ app.Astro = Astro;
+ app.args = Astro.props.args ?? {};
+ app.url = Astro.url;
+ args.domain = app.url.hostname;
+ args.path = app.url.pathname.replace(/\.html$/, '');
+ args.url = app.url.origin + args.path;
+ args.cssList = app.args.cssList ?? [];
+ args.jsList = app.args.jsList ?? [];
+ args.titlePrefix = app.args.title;
+ args.title = (args.titlePrefix != null ? args.titlePrefix + ' - ' : '') + args.siteName + ' | ' + args.titleSuffix;
+ args.lang = 'ja';
+ args.locale = 'ja_JP';
+ args.og_type = args.path === '/' ? 'website' : 'article';
+ args.og_image = assetsUrl('img/global/og.png', true);
+ },
+};
+
+export const assets = (path, cacheBuster = false) => {
+ path = '/assets/' + Util.ltrim(path);
+ if (cacheBuster) path += '?' + Date.now();
+ return path;
+};
+
+export const assetsUrl = (path, cacheBuster = false) => {
+ return Util.rtrim(app.url.origin) + assets(path, cacheBuster);
+};
+
+export const img = (path) => {
+ return assets('img/' + Util.ltrim(path));
+};
+
+export const route = (path) => {
+ return '/' + Util.ltrim(path);
+};
diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro
new file mode 100644
index 0000000..3dc7e73
--- /dev/null
+++ b/src/layouts/Layout.astro
@@ -0,0 +1,58 @@
+---
+import Util from '/src/config/Util';
+import { app, args, assets, img, route } from '/src/config/view';
+app.init(Astro);
+---
+
+<!DOCTYPE html>
+<html lang={ args.lang } id={ args.path }>
+ <head>
+ <meta charset="UTF-8" />
+ <title>{ args.title }</title>
+ <meta name="description" content={ args.description }>
+
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+ <meta name="format-detection" content="telephone=no, email=no, address=no" />
+ <meta name="generator" content={ Astro.generator }>
+
+ <meta property="og:locale" content={ args.locale }>
+ <meta property="og:type" content={ args.og_type }>
+ <meta property="og:site_name" content={ args.siteName }>
+ <meta property="og:title" content={ args.title }>
+ <meta property="og:description" content={ args.description }>
+ <meta property="og:image" content={ args.og_image }>
+ <meta property="og:url" content={ args.url }>
+
+ <meta name="twitter:card" content="summary_large_image">
+ <meta name="twitter:title" content={ args.title }>
+ <meta name="twitter:description" content={ args.description }>
+ <meta name="twitter:site" content={ args.twitter }>
+
+ <link rel="stylesheet" href={ assets('css/global/reset.css', true) }>
+ <link rel="stylesheet" href={ assets('css/global/style.css', true) }>
+ <script src={ assets('js/global/base.js', true) }></script>{
+ (args.cssList.length > 0 || args.jsList.length > 0) && '\n'
+ }{
+ args.cssList.map(css => <Fragment set:html={Util.sprintf('\n<link rel="stylesheet" href="%s">', assets('css/' + Util.ltrim(css), true))} />)
+ }{
+ args.jsList.map(js => <Fragment set:html={Util.sprintf('\n<script src="%s"></script>', assets('js/' + Util.ltrim(js), true))} />)
+ }
+ </head>
+ <body>
+ <div id="page-container">
+ <header id="page-header">
+ <div class="content-inner">
+ <h1 class="siteName"><a href={ route('/') }><img src={ img('global/logo.png') } alt="Astro Site" width="100" height="100"></a></h1>
+ </div>
+ </header>
+ <main id="page-main"><slot /></main>
+ <footer id="page-footer">
+ <div class="content-inner">
+ <div class="footerArea">
+ <p class="copyright"><span class="wbr">Copyright 2025</span> <img src={ img('global/logo.png') } alt="Astro Site" width="30" height="30"> <span class="wbr">Powered by Astro</span></p>
+ </div>
+ </div>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/src/pages/index.astro b/src/pages/index.astro
new file mode 100644
index 0000000..624aae9
--- /dev/null
+++ b/src/pages/index.astro
@@ -0,0 +1,13 @@
+---
+import Layout from '/src/layouts/Layout.astro';
+import Util from '/src/config/Util';
+import { app, args, assets, img, route } from '/src/config/view';
+const pageArgs = {};
+---
+
+<Layout args={pageArgs}>
+ <div class="content-inner">
+ <h1>Welcome to Astro Site</h1>
+ <p class="sample-link"><a href={ route('/subpage') }>Subpage</a></p>
+ </div>
+</Layout>
diff --git a/src/pages/subpage/index.astro b/src/pages/subpage/index.astro
new file mode 100644
index 0000000..e474d31
--- /dev/null
+++ b/src/pages/subpage/index.astro
@@ -0,0 +1,16 @@
+---
+import Layout from '/src/layouts/Layout.astro';
+import Util from '/src/config/Util';
+import { app, args, assets, img, route } from '/src/config/view';
+const pageArgs = {
+ title: 'Subpage Title',
+ cssList: ['subpage/style.css'],
+ jsList: ['subpage/script.js'],
+};
+---
+
+<Layout args={pageArgs}>
+ <div class="content-inner">
+ <h1>Subpage</h1>
+ </div>
+</Layout>
git commit しておく(6回目)
git add .
git commit -m "generate starter kit"
package-lock.json
を再生成する
GitHub 上での Astro のビルドでは、npm を使用している場合 package-lock.json
ファイルが使われます。このファイルに問題があるとビルドが失敗するため、念のため再生成しておきます。
rm -r node_modules package-lock.json
npm install
git commit しておく(7回目)
差分が生じた場合はコミットしておきます。
git add .
git commit -m "update package-lock.json"
git push する
git push
おわりに
この手順書で完成するサイトは https://astro.debiru.net/ のようなものです。ソースコードは https://github.com/debiru/astro です。
冒頭でも述べましたが、このスターターキットでは BeautifulCode を実現します。BeautifulCode とは、出力される HTML, CSS, JS のソースコードの可読性を担保することを指します。出力ソースコードの圧縮などをせず、インデントの整った美しいソースコードを提供することを目指します。従来の MPA としての開発アプローチである静的な HTML, CSS, JS の読み込みによりサイトを構築しています。
Astro は SSG (Static Site Generator) として利用できるツールであり、PHP 等のサーバーサイドスクリプトが実行できない GitHub Pages のようなホスティング環境でも、デプロイ時の GitHub Actions を用いて動的に HTML を生成することで各ページで Header や Footer を共通化するなど、プログラマブルな Web サイトの開発を可能にします。
Astro に触れたことのない人でも、このスターターキットを用いて Astro で GitHub Pages を開設し、Astro の魅力を知ってもらえたら嬉しいです。
不明点や疑問、困ったことなどがあれば @debiru_R までお気軽にご連絡ください。