ごみばこいんは今年に入って裏側をまるっと刷新した。 これまでのごみばこいんの思い出とシーズン3 ので、それをもう少し掘り下げた記事。
目次
全体
- ブログの土台
- リポジトリ
- GitHub (いろいろあって非公開)
- デプロイ
- GitHub Actions
- Webサーバ
- nginx
- 基本的にはすべてのアクセスをnginxでハンドル
-
sters/onstatic: onstatic is static page hosting controller.
- onstaticへのリクエストは基本的には行わない
- nginx
- その他
- Issueから記事を追加できる
- 予約投稿
Hugoテンプレートは自作
archives/年/月/記事
archives/年/月/記事
という構造にしたかったので結構面倒。Wordpressからの名残でそうしてるけど別にそうしなくてもいいんだよな。。。
具体的にはこのような記述をarchives/list.html
で書いたりしている。
{{ if findRE "archives/\\d+/\\d+/" .File }}
{{ range .Pages }}
{{/* Page: /archives/xxxx/yy/ */}}
...
{{ end }}
{{ else if findRE "archives/\\d+/" .File }}
{{/* Page: /archives/xxxx/ */}}
{{ range .Pages }}
{{ range .Pages }}
...
{{end}}
{{ end }}
{{ else }}
{{/* Page: /archives/ */}}
...
{{ end }}
テンプレートの分離
以前までのWordpress管理でも、なるべく各パーツを別々のファイルで管理していたので、Hugoテンプレートでもどうようにpartialsを使って部分ごとに分離している。分離している理由は、違う箇所でも同じ見た目を簡単にキープできるように。
記事のヘッダー部分、記事の本文、記事のフッター、タグ、日付。などなど。
外部へのリンクにはnoreferrerをつけたい
つけたいりゆうはこういうところ。
noopener と noreferrer の整理、結局どっちを使えば良いのか
_default/_markup/render-link.html
をいじっている。
{{ if findRE "^(https?:)?(//)?gomiba.co/" .Destination }}
<a href="{{ .Destination | safeURL }}" target="_blank">{{ .Text | safeHTML }}</a>
{{ else if findRE "^/[^/]" .Destination }}
<a href="{{ .Destination | safeURL }}" target="_blank">{{ .Text | safeHTML }}</a>
{{ else }}
<a href="{{ .Destination | safeURL }}" target="_blank" rel="noreferrer">{{ .Text | safeHTML }}</a>
{{ end }}
JSON-LD
JSON-LD - JSON for Linking Data
記事の情報を教えるのに便利なやつで、ごみばこいんブログでも利用している。 Hugoと合わせて使うと、indexのような連番を降るやりかたがわからなかったけど変数でこねたらできた。
たとえばパンくずリストはこうしている。
{{ $index := 0 }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": {{ $index = add $index 1 }}{{ $index }},
"name": {{ .Site.Title }},
"item": {{ absURL "/" }}
},
{
"@type": "ListItem",
"position": {{ $index = add $index 1 }}{{ $index }},
"name": "記事一覧",
"item": {{ absURL "/archives/" }}
},
{
"@type": "ListItem",
"position": {{ $index = add $index 1 }}{{ $index }},
"name": {{ .Page.LinkTitle }},
"item": {{ .Page.Permalink }}
}
]
}
</script>
デプロイ
以下のようなことをGitHub Actionsでやっている。
- masterブランチでトリガ
hugo --minify --gc
で静的ファイルにビルド- ビルド結果を別ブランチにコミット&プッシュ
- onstaticで該当のブランチを取得
つまりこんな感じのワークフローになっている。
name: Deploy blog content
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-20.04
steps:
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
- uses: actions/checkout@v2
- name: Build blog content
run: hugo --minify --gc
- name: Commit built branch
run: |
set +e
git config user.name github-actions
git config user.email [email protected]
cp -R build /tmp/build
git fetch
git checkout -f -b built origin/built
rm -rf ./*
cp -R /tmp/build/* .
git add .
git commit -m "built"
git push origin built
- name: deploy
run: |
curl -i \
-X POST \
-H "X-ONSTATIC-KEY: ${{ secrets.ONSTATIC_KEY }}" \
-H "X-ONSTATIC-REPONAME: ${{ secrets.ONSTATIC_REPO }}" \
-H "X-ONSTATIC-BRANCH-NAME: built" \
${{ secrets.ONSTATIC_ENDPOINT }}
サーバ
使っているサーバがいわゆるコンテナで動くものとか、コードをアップしたら動くものとかではなくまるっとサーバー、というかVPSなので、Ansibleでいろいろ設定している。 Ansible Galaxyというroleを共通化できるものがあるので、なるべくこれを利用して、ほとんど自分でロールを書くことなく設定を書くだけでいいようにしている。
実際の構成変更の適用はローカルからでもできるし、GitHub Actionsでsecretに鍵を入れているのでCI上からも行えるようになっている。 たとえばちょっとこれを、みたいなものをGitHub上でシュッと変更してコミットすればそのまま反映される。
HTTP/HTTPSを受けるサーバにはnginxを使っている。
NGINX | High Performance Load Balancer, Web Server, & Reverse Proxy
基本的にすべてのリクエストをnginxで受けている。 理由としてはTLSのそれとか、もろもろの制限とか、キャッシュとかを設定している。
ごみばこいんブログのデプロイなどのために、onstaticをデーモンとして動かしていて、一部のリクエストはそこにリバースプロキシをしている。
ドメイン
もともとValueDomainで取得したけれど、管理しやすそうだったのでGoogleDomainに移管して、運用中。
フロントエンド
CSSは愛のあふれる手書きでFLOCSSを踏襲している。
hiloki/flocss: CSS organization methodology.
コードブロックのシンタックスハイライトにはprismを使っている。
- Prism
- prism - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers
cdnjsで、言語別の定義ファイルが提供されているので、コードブロックの内容から言語を検出してそれらを非同期に読み込んでいる。 言語の検出はお手製のざっくりしたものだけど、そもそも言語が違ったからといって見た目が大きく崩れるわけでもないし大丈夫かな、と思っている。
sters/prismloader-js: Dynamic prism.js language files loader on web browser.
JavaScriptでやりたいことってそんなに多くない(DOMを生成するとかはいらない)ので、DOMContentLoadedではなくLoadイベントで処理を始めている。 加えてその中でも requestAnimationFrameをつかって非同期にやれるようにしている。
というかそもそもやることがそんなに多くないので微々すぎるけれど画面を出すまでをなるべく早くして、リッチにするものを順次作業する(ただしレイアウトを崩さない)、みたいな考え方。
アイコンはsimple-iconsを使っている。これもcdnjsで提供されている。
- Simple Icons
- simple-icons - Libraries - cdnjs - The #1 free and open source CDN built to make life easier for developers
Issueから記事を追加できる
Issueで記事を書けるようにしたのは、エディタがない環境(スマホとか普段と違うPCとか)でも記事を書けるようにしたかったため。と思ったけど Codespaces があるのでいらないかもしれない。
とはいえ、hugoのディレクトリはなかなかいろんなファイルがあって、記事までたどり着くのがややこしい(特に記事ページが階層構造になっているため。。)ので、シンプルに記事だけ書けるインタフェースがどこかにほしい、というのはあった。
で、どういう仕組みになっているかというと:
- Issue本文に記事を書く
/publish
とコメントするとGitHubActionがトリガ- ISSUE_BODYを受け取ってファイルを設置、コミット&プッシュ
Issueの本文には以下のようなフォーマットで記事を書いている。
---
date: 2021-06-09T12:23:26+09:00
title: 記事タイトル
draft: true
reserved: true
tags:
- タグタグ
---
記事コンテンツ
GitHub Actionsを使うと、Issueへのコメントなどをトリガにワークフローを起動することができる。
具体的には
GitHub Actionsでスラッシュコマンド
をして /publish
というコマンドを見ている。
で、そのときに、ISSUE_BODYでIssue本文が受け取れるので、自作のスクリプトに渡して、適切なディレクトリにファイルを設置している。あとはデプロイのときと同様に、コミットしてプッシュしている。
予約投稿
Hugoで予約投稿を行う をしている。 GitHubActionsではcronが設定できるので、これを使って未公開の予約記事を公開状態に切り替えている。
ただし、そのままプッシュしただけでは他のワークフローがトリガされない。
actions/checkout@v2
では任意のトークンを指定できるので、自分のアカウントで発行したものをSecretにいれて利用している。このトークンにはリポジトリへの書き込み権限、GitHubActionsのWorkflowの権限がついている。ので慎重に扱う必要がある。
(これはIssueからコミットしているときも同じ)
name: Check and publish reserved articles
on:
schedule:
- cron: '0 1,9,12,18,23 * * *'
jobs:
sync:
runs-on: ubuntu-20.04
steps:
# https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token
- uses: actions/checkout@v2
with:
token: ${{ secrets.GH_PAT }}
- run: go get github.com/sters/hugo-publish-reserved-content/cmd/hugo-publish-reserved-content
- name: Check reserved content
run: |
export PATH=${PATH}:`go env GOPATH`/bin
hugo-publish-reserved-content -basePath content/
# https://github.com/actions/checkout
# https://docs.github.com/ja/free-pro-team@latest/actions/reference/context-and-expression-syntax-for-github-actions
- name: Commit and Push
run: |
set +e
git config user.name github-actions
git config user.email [email protected]
git add .
git commit -m "publish reserved article"
git push
そうすると、この予約投稿の内容がmasterブランチに自動的にコミットされ、masterブランチにコミットされることでトリガされるデプロイのGitHubActionsがトリガされ、デプロイまで行われる。ピタゴラスイッチ感。