배포하기
Wikven은 서버나 데이터베이스 없이 자체 완결된 정적 파일 dist/ 디렉터리를 생성합니다. 정적 파일을 제공하는 곳이라면 어디서나 호스팅할 수 있습니다.
빌드가 쓰는 것
사이트에 필요한 모든 것이 dist/ 안에 있으며, 그중 어느 것도 열람 시점에 다른 곳에서 가져오지 않습니다.
dist/
├── index.html the main page, served at the site root
├── Getting_Started.html one file per page
├── Guide/
│ └── Setup.html a page whose title has a slash becomes a directory
├── File:Logo.png.html file description pages
├── assets/ everything the build generates, together
│ ├── site.styles.css MediaWiki:Common.css and the skin's own CSS
│ ├── startup-static.js the module loader, with its network fetch removed
│ ├── modules-static.js every module the pages need, bundled
│ ├── img-1a2b3c4d5e6f.png every image, from a page or from CSS
│ └── webfonts.css only with WikvenBundleWebfonts set
├── fonts/ the webfont files themselves, likewise
├── pagefind/ the search index
└── citizen/ a complete copy of the site, per extra skin
그 배치에서 호스트를 가리키기 전에 알아 둘 것이 둘 있습니다. 문서 사이의 링크는 상대 경로이므로 사이트가 도메인 루트에 있든 하위 디렉터리에 있든, 심지어 파일 시스템에서 열어도 작동합니다. 다만 문서가 아니라 사이트 루트를 기준으로 주소를 잡는 것은 — 가장 눈에 띄는 것이 검색 번들입니다 — 기준 경로를 알려 주어야 합니다. 아래 GitHub Pages 항목의 주의가 그것입니다. 그리고 스킨마다 생기는 디렉터리는 완전한 사본이므로 스킨이 셋인 사이트는 파일이 대략 세 배입니다. 스킨을 참고하십시오.
GitHub Pages
이 워크플로는 푸시할 때마다 사이트를 다시 빌드하고 게시합니다. Wikven 복합 액션으로 소스를 빌드한 뒤 dist/를 Pages에 업로드합니다.
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
# Whole history, so each page is dated at the commit that last changed
# its source file. A shallow checkout knows only the latest commit.
fetch-depth: 0
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- uses: chaotic-ground/wikven/actions/bake@v1.3.0
with:
source: src
output: dist
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: dist
- id: deploy
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
액션은 릴리스된 버전으로 고정되어 있고, @v1.3.0가 현재 릴리스입니다. image는 일부러 지정하지 않았습니다. 기본값에 맡긴 액션은 자신이 잘려 나온 릴리스의 이미지를 실행하므로, 둘이 어긋날 수가 없습니다. 이미지까지 직접 고정하려면 image: ghcr.io/chaotic-ground/wikven:1.3.0을 덧붙이십시오. 깃 태그에는 v가 붙고 이미지 태그에는 붙지 않습니다. 릴리스 전의 변경을 미리 써 보려면 릴리스 페이지에서 날짜가 붙은 nightly-YYYY-MM-DD 사전 릴리스를 골라 두 곳 모두에 지정하십시오. 나이틀리 태그는 main의 어느 커밋을 가리키고 그 이미지도 같은 커밋에서 만들어지므로, 둘을 같은 나이틀리로 지정하면 서로 붙어 있습니다.
저장소의 Settings → Pages → Build and deployment → Source: GitHub Actions에서 Pages를 활성화하세요. 이 문서 사이트도 이렇게 게시됩니다.
GitHub 프로젝트 페이지는 하위 디렉터리(username.github.io/repo/)에서 제공됩니다. Wikven은 문서 간 링크를 상대 경로로 작성하므로 페이지 사이의 링크는 계속 동작하지만, 절대 경로가 필요한 것은 그 기본 경로를 포함해야 합니다. 검색의 SifterSearchBundlePath를 /repo/pagefind/로 설정하세요 (이 사이트는 /wikven/pagefind/를 사용합니다). 사용자/조직 페이지(도메인 루트에서 제공)에는 그런 설정이 필요 없습니다.
임의의 정적 호스트
dist/는 그저 파일 모음이므로, 어떤 정적 호스트(Netlify, Cloudflare Pages, S3 같은 객체 저장소, 또는 평범한 웹 서버)에서도 제공할 수 있습니다. CI나 로컬에서 사이트를 빌드한 뒤, 호스트가 dist/ 디렉터리를 가리키게 하거나 그 내용을 서버의 문서 루트에 업로드하세요.
호스트마다 주소를 어떻게 다루는가
문서는 곧 파일입니다. Wikven은 Getting_Started/index.html이 아니라 Getting_Started.html을 쓰고, 문서가 지니는 링크는 모두 그 파일이 놓인 자리를 기준으로 한 상대 주소입니다. 그래서 파일을 제공하는 호스트라면 어디서든 설정할 것 없이 사이트가 동작합니다.
어떤 호스트는 확장자 없는 주소에도 답해서, /Getting_Started가 /Getting_Started.html과 같은 문서에 닿습니다. GitHub Pages, GitLab Pages, Cloudflare Pages는 그렇게 하고, Codeberg Pages와 객체 저장소, 평범한 웹 서버는 그렇게 하지 않습니다. Wikven이 쓰는 링크에는 확장자가 붙어 있으므로 어느 쪽이든 사이트는 동작합니다. 이 차이는 누군가 손으로 적거나 공유한 주소에서만 드러납니다.
Netlify는 무언가를 꺼야 하는 유일한 곳입니다. 기본으로 켜져 있는 Pretty URLs가 /Getting_Started를 /Getting_Started/로 넘기고, /Getting_Started.html도 같은 주소로 다시 씁니다. Wikven은 Getting_Started/ 디렉터리를 만들지 않으므로, 그 주소에서 제공되는 문서는 자기 링크가 기대하는 것보다 한 단계 깊은 곳에 놓이고 스타일시트와 그림이 아무 데도 닿지 않습니다. Project configuration → Build & deploy → Post processing에 있습니다.
Cloudflare Pages는 끊어진 링크를 감춥니다. 사이트에 404.html이 없으면, 사이트에 없는 주소에 대해 그 사이트를 단일 페이지 애플리케이션으로 보고 대문을 200으로 돌려줍니다. 그러면 낡았거나 잘못 적힌 링크가 멀쩡한 링크처럼 보입니다.
그러니 오류 문서가 필요한지는 호스트에 달렸습니다. 자기 오류 문서를 보여 주는 곳도 있고, Cloudflare Pages는 당신의 오류 문서 아니면 당신의 대문을 보여 줍니다. 소스 트리에 404라는 이름의 문서를 두면 빌드가 dist/404.html을 쓰고, GitHub Pages와 GitLab Pages, Codeberg Pages가 없는 주소에 대해 그 파일을 제공합니다. 그 문서에는 __NOINDEX__를 넣으십시오. 사이트맵은 색인해 달라는 초대이고, 오류 문서는 누구도 초대할 문서가 아닙니다.
사이트맵에 올라 있는 것과 색인에 오르는 것은 다르며, 어떤 빌드도 사이트를 색인에 넣어 주지는 못합니다. 다음으로 읽을 것은 검색 엔진입니다.
로컬에서 미리 보기
dist/index.html을 직접 열거나, 링크와 자산이 프로덕션에서와 똑같이 해석되도록 디렉터리를 제공하세요. Wikven에는 이를 위한 serve 명령이 내장되어 있습니다.
이미지도 같은 명령을 실행합니다. 포트를 공개하고, 빌드 출력이 마운트된 dist/에 이미 있어야 합니다:
docker run --rm -p 8080:8080 \
-v "$(pwd)/dist:/workspace/dist" \
ghcr.io/chaotic-ground/wikven serve
임의의 정적 서버도 됩니다. 예를 들어 cd dist && python3 -m http.server처럼요.
날짜, 작성자, 재현 가능한 빌드
각 문서의 "마지막 편집" 줄은 그 문서의 소스 파일을 마지막으로 바꾼 커밋을 가리키고, 그 커밋의 작성자를 함께 밝힙니다. 빌드가 채우는 위키에는 자체 역사가 없으므로(모든 문서가 한 번의 가져오기 과정에서 쓰입니다) 저장소의 역사가 그 두 가지 사실의 출처입니다.
그 역사에 닿을 수 있어야 합니다. bake 액션이 러너에서 역사를 읽어 빌드에 넘겨주지만, 얕은 체크아웃은 마지막 커밋 하나만 알고 있습니다. 위 워크플로가 fetch-depth: 0으로 체크아웃하는 까닭입니다. 전체 역사가 없어도 실패하지는 않습니다. 다만 모든 문서가 빌드 중인 커밋으로 날짜가 찍히고 작성자는 아무도 아니게 됩니다. 그런 일이 생기면 액션이 로그에 그렇게 적으며, 그 한 줄이 유일한 경고입니다.
나머지도 같은 생각에서 따라옵니다. 빌드는 시계를 SOURCE_DATE_EPOCH에 — 액션이 설정할 때는 커밋 자신의 날짜에 — 얼려 둔 채 실행되므로, 한 커밋을 두 번 빌드하면 문서 안의 시각까지 바이트 단위로 동일한 출력이 나옵니다. 내용이 바뀌지 않은 재배포는 호스트에서 아무것도 바꾸지 않고, 두 빌드의 차이는 실제로 편집한 것만 보여 준다는 뜻입니다. Wikven의 지속적 통합은 이 사이트를 두 번 구워 결과를 비교하는 것으로 이를 검증합니다.
고정한 소스를 최신으로 유지하기
그 빌드를 재현 가능하게 만들어 주는 핀은, 아무도 여러분을 대신해 옮겨 주지 않는 핀이기도 합니다. 정확하게 고정한 WikvenRepositories 핀은 여러분이 바꿀 때까지 그대로 남고, 어떤 봇도 그것을 바꿔 주지 않습니다. .wikven.yaml은 Wikven 자체의 파일이고, Dependabot은 자기가 아는 생태계만 지켜보기 때문입니다. 그래서 모든 검사가 초록인 채로도 사이트가 스킨 하나를 몇 년씩 묵힐 수 있습니다.
그 상황에서 어느 쪽을 택할지는 여러분의 몫이며, 둘은 같은 거래가 아닙니다.
- 핀을 정확하게 두고 의도적으로 옮기기.
commit이나sha256을 붙인tarball은 오늘과 내일이 같은 사이트를 빌드하며, 배포하는 것이 달라질 때마다 누군가 승인한 diff가 남습니다. 대신 치르는 값은 대응 시간입니다. 보안 릴리스는 누군가 핀을 옮겨 줄 때까지 상류에 머무릅니다. - 움직이는 것을 가리키기.
REL1_46같은 릴리스 브랜치를 가리키는reference는 빌드가 돌 때 그 브랜치에 있는 것을 그대로 가져오므로, 수정이 다음 베이크에 아무것도 병합하지 않고 도착합니다. 대신 치르는 값은 재현성입니다. 같은 소스 트리를 두 번 구워도 결과가 다를 수 있고, 무엇이 달라졌는지는 트리 어디에도 남지 않습니다.
나머지 절에서 다루는 것은 첫 번째 쪽을 택할 만큼 값싸게 만드는 방법입니다.
updatecli가 바로 그 빈틈을 메우며, 여러분의 파일을 알아볼 필요가 아예 없다는 것이 그 방법입니다. 핀이 어디 있는지는 여러분이 알려 주면 됩니다. 매니페스트는 source(현재 버전이 게시되는 곳)와 target(어느 파일의 어느 키가 핀을 담고 있는지)을 지정하며, 이를 적용하면 source의 값을 target에 써 넣고 그래서 바뀐 것이 있으면 풀 리퀘스트를 엽니다. 지속적 통합에서 일정에 걸어 두면 뒤처진 핀이 검토할 수 있는 풀 리퀘스트로 찾아옵니다. 아래는 핀 하나를 위한 매니페스트 전체로, 릴리스 태그를 따라가는 리포지터리입니다:
---
name: "build(deps): bump Citizen"
pipelineid: citizen
scms:
default:
kind: github
spec:
owner: yourname
repository: some-repository
branch: main
user: github-actions[bot]
email: 41898282+github-actions[bot]@users.noreply.github.com
actions:
default:
kind: github/pullrequest
scmid: default
sources:
citizen:
kind: githubrelease
spec:
owner: StarCitizenTools
repository: mediawiki-skins-Citizen
versionfilter:
kind: semver
targets:
citizen:
name: 'build(deps): bump Citizen to {{ source "citizen" }}'
kind: yaml
scmid: default
sourceid: citizen
spec:
file: .wikven.yaml
key: $.config.WikvenRepositories.Citizen.reference
브랜치를 따라가는 commit은 source만 바꾼 같은 매니페스트입니다. kind: gitcommit에 리포지터리 URL과 따라갈 브랜치를 주고, reference가 아니라 commit으로 끝나는 키에 씁니다. tarball과 그 sha256은 여기서 다루지 않습니다. 두 키가 함께 움직여야 하는데, Special:ExtensionDistributor가 내주는 아카이브 이름에는 어떤 버전 피드도 게시하지 않는 빌드 해시가 들어 있어 source가 읽을 것이 없습니다. 지켜보게 하고 싶은 것은 repository로 선언하세요. 그리고 매니페스트를 쓰지 않고 넘어갈 우회로는 없습니다. updatecli의 자동 탐색은 자기가 아는 생태계(npm, cargo, dockerfile, maven 등)를 훑지만, 자체 형식의 설정 파일은 결코 그런 생태계가 아니므로 이 파일에 대해서는 손으로 쓴 매니페스트가 전부입니다.
이 사이트가 바로 그 실제 예입니다. 매니페스트는 updatecli/updatecli.d/에 있고(reference 핀마다 릴리스 태그 하나, commit 핀마다 브랜치 헤드 하나), 주간 워크플로가 이를 적용하며 파이프라인마다 풀 리퀘스트 하나를 엽니다. 위의 두 형태를 넘어 매니페스트가 할 수 있는 모든 것은 업스트림 자체 문서가 다룹니다.