diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fe9609c..5b9bbbf 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -55,6 +55,21 @@ jobs: mkdir _site cp -r index.html article.html game.html lab.html 404.html .nojekyll assets data articles builders badges _site/ + # Browsers keep scripts and styles for up to ten minutes; a version on their URLs makes each deploy load + # its own files instead of new HTML running last deploy's scripts. + - name: Version script and style URLs + run: | + python3 - "${GITHUB_SHA::8}" <<'PY' + import pathlib, re, sys + v = sys.argv[1] + pat = re.compile(r'((?:src|href)="(?:\.\./|/)?assets/(?:js|css)/[\w.-]+\.(?:js|css))"') + for p in pathlib.Path("_site").rglob("*.html"): + t = p.read_text(encoding="utf-8") + n = pat.sub(lambda m: f'{m.group(1)}?v={v}"', t) + if n != t: + p.write_text(n, encoding="utf-8") + PY + - name: Publish to gh-pages uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4 with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20c4d7b..2dd0e8e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,6 +89,10 @@ python3 scripts/builder_cards.py `assets/js/track.js`의 `hubTrack(이름, 파라미터)`가 GA4로 이벤트를 보냅니다. GA4가 설치되지 않았으면 아무 일도 하지 않습니다. 이벤트 이름과 파라미터는 PM 문서의 이벤트 사전을 따르고, 새 이벤트를 넣을 때는 사전에도 같이 적습니다. HTML에서는 `data-event="click_join" data-event-params='{"target":"template","source":"builder_page"}'`처럼 속성만으로도 보낼 수 있습니다. 로컬에서 확인하려면 콘솔에서 `window.HUB_DEBUG = true`를 켭니다. +## 배포 + +`main`에 머지되면 Deploy site 워크플로가 사이트를 만들어 `gh-pages` 브랜치에 올리고, GitHub Pages가 그 브랜치를 공개합니다. **`gh-pages`는 지우지 마세요.** 지우면 Pages 설정이 꺼지고 사이트 전체가 404가 됩니다. 머지된 브랜치를 한꺼번에 지울 때도 `gh-pages`와 `main`은 남겨 두세요. + ## 로컬에서 보기 ```bash diff --git a/assets/js/ga.js b/assets/js/ga.js index b296bf3..21cffcf 100644 --- a/assets/js/ga.js +++ b/assets/js/ga.js @@ -2,10 +2,9 @@ counted. Incoming utm_* (from shared links or other team sites) reach GA through page_location and are then removed from the address bar so the URL people copy stays clean. */ (() => { - /* ID is the hub's GA4 stream. Google serves no tag script for that ID on its own (gtag/js?id=ID is a 404); - the stream's Google tag is TAG, so the script loads from TAG and only ID is configured, which keeps the - hub's events in the hub's property. */ - const ID = "G-C5V0X2SGD3"; + /* The hub's GA4 stream (measurement ID G-C5V0X2SGD3) is reached through its Google tag, TAG: Google serves + the script only for TAG (gtag/js?id=G-C5V0X2SGD3 is a 404), and a page only sends when TAG itself is + configured. GA's own install guide for the stream gives this snippet; hits land in the hub property. */ const TAG = "G-BEBVKYH8HL"; if (location.hostname === "causalinferencelab.github.io") { const s = document.createElement("script"); @@ -15,7 +14,7 @@ window.dataLayer = window.dataLayer || []; window.gtag = function gtag() { window.dataLayer.push(arguments); }; window.gtag("js", new Date()); - window.gtag("config", ID, { page_location: location.href, allow_google_signals: false, allow_ad_personalization_signals: false }); + window.gtag("config", TAG, { page_location: location.href, allow_google_signals: false, allow_ad_personalization_signals: false }); } try { const u = new URL(location.href); diff --git a/scripts/update_stats.py b/scripts/update_stats.py index 8f88fe7..74169e2 100644 --- a/scripts/update_stats.py +++ b/scripts/update_stats.py @@ -6,6 +6,7 @@ import json import os import sys +import urllib.error import urllib.parse import urllib.request from collections import Counter @@ -90,4 +91,8 @@ def main(out_path): if __name__ == "__main__": - main(sys.argv[1] if len(sys.argv) > 1 else "data/stats.json") + # A refused or failed GitHub call keeps last week's stats rather than stopping the deploy. + try: + main(sys.argv[1] if len(sys.argv) > 1 else "data/stats.json") + except (urllib.error.HTTPError, urllib.error.URLError) as e: + print(f"stats not refreshed, kept as is: {e}", file=sys.stderr)