mirror of
https://git.sr.ht/~seirdy/seirdy.one
synced 2024-11-27 14:12:09 +00:00
CI: test with lighthouse, webhint in staging
This commit is contained in:
parent
34ba9e30cf
commit
51a6d4edde
9 changed files with 175 additions and 61 deletions
15
.build.yml
15
.build.yml
|
@ -2,10 +2,11 @@
|
||||||
image: alpine/edge
|
image: alpine/edge
|
||||||
packages:
|
packages:
|
||||||
- rsync
|
- rsync
|
||||||
- hugo
|
|
||||||
- zopfli
|
- zopfli
|
||||||
- git # for Hugo's gitInfo
|
- git # for Hugo's gitInfo
|
||||||
- make
|
- make
|
||||||
|
- npm
|
||||||
|
- chromium
|
||||||
sources:
|
sources:
|
||||||
- https://git.sr.ht/~seirdy/seirdy.one
|
- https://git.sr.ht/~seirdy/seirdy.one
|
||||||
secrets:
|
secrets:
|
||||||
|
@ -15,7 +16,13 @@ triggers:
|
||||||
condition: always
|
condition: always
|
||||||
to: seirdy@seirdy.one
|
to: seirdy@seirdy.one
|
||||||
tasks:
|
tasks:
|
||||||
|
- deps: |
|
||||||
|
echo "StrictHostKeyChecking=no" >> ~/.ssh/config
|
||||||
|
rsync deploy@seirdy.one:/home/deploy/binaries.tar.gz .
|
||||||
|
tar x -ozC /bin -f binaries.tar.gz
|
||||||
|
npm i -g npm pnpm
|
||||||
|
pnpm i -g @lhci/cli hint @hint/configuration-web-recommended @hint/hint-doctype @hint/hint-https-only @hint/hint-performance-budget @hint/formatter-codeframe
|
||||||
- build_deploy: |
|
- build_deploy: |
|
||||||
cd seirdy.one
|
cd seirdy.one
|
||||||
echo "StrictHostKeyChecking=no" >> ~/.ssh/config
|
make DOMAIN=staging.seirdy.one test-staging
|
||||||
make build deploy
|
make clean deploy
|
||||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,6 +1,8 @@
|
||||||
public/
|
public/
|
||||||
public_*/
|
public_*/
|
||||||
hint-report/
|
hint-report/
|
||||||
.hintrc-local
|
.hintrc-*
|
||||||
*.report.html
|
*.report.html
|
||||||
*.report.json
|
*.report.json
|
||||||
|
.lighthouseci
|
||||||
|
lighthouse-reports
|
||||||
|
|
27
.hintrc
27
.hintrc
|
@ -1,22 +1,21 @@
|
||||||
{
|
{
|
||||||
"extends": [
|
|
||||||
"web-recommended"
|
|
||||||
],
|
|
||||||
"connector": {
|
"connector": {
|
||||||
"name": "puppeteer",
|
"name": "puppeteer",
|
||||||
"options": {
|
"options": {
|
||||||
"headless": true,
|
"browser": "Chromium",
|
||||||
"browser": "Chromium"
|
"headless": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extends": [
|
||||||
|
"web-recommended"
|
||||||
|
],
|
||||||
|
"formatters": [
|
||||||
|
"codeframe"
|
||||||
|
],
|
||||||
"hints": {
|
"hints": {
|
||||||
|
"apple-touch-icons": "off",
|
||||||
"axe/other": "error",
|
"axe/other": "error",
|
||||||
"https-only": "error",
|
|
||||||
"doctype": "error",
|
|
||||||
"performance-budget": "error",
|
|
||||||
"compat-api/css": "error",
|
"compat-api/css": "error",
|
||||||
"manifest-is-valid": "error",
|
|
||||||
"manifest-file-extension": "error",
|
|
||||||
"compat-api/html": [
|
"compat-api/html": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
@ -27,6 +26,7 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"doctype": "error",
|
||||||
"http-compression": [
|
"http-compression": [
|
||||||
"warning",
|
"warning",
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,11 @@
|
||||||
"brotli": false
|
"brotli": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"https-only": "error",
|
||||||
|
"manifest-file-extension": "error",
|
||||||
|
"manifest-is-valid": "error",
|
||||||
|
"performance-budget": "error",
|
||||||
|
"ssllabs": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
59
.lighthouserc.yml
Normal file
59
.lighthouserc.yml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
ci:
|
||||||
|
assert:
|
||||||
|
preset: lighthouse:recommended
|
||||||
|
assertions:
|
||||||
|
errors-in-console: "off" # false positive for CSP violation
|
||||||
|
installable-manifest: "off" # not a PWA
|
||||||
|
offline-start-url: "off" # not a PWA
|
||||||
|
performance-budget: "error"
|
||||||
|
render-blocking-resources:
|
||||||
|
- warn
|
||||||
|
# the CSS file.
|
||||||
|
# My site doesn't use JS so it doesn't use the recommended async hack
|
||||||
|
- maxLength: 1
|
||||||
|
robots-txt: "off" # Lighthouse is incompatible with a hardened CSP
|
||||||
|
service-worker: "off" # not a PWA
|
||||||
|
splash-screen: "off" # not a PWA
|
||||||
|
themed-omnibox: "off" # antifeature, not a PWA
|
||||||
|
works-offline: "off" # not a PWA. Use caching.
|
||||||
|
is-crawlable: "off" # staging server won't be indexed
|
||||||
|
timing-budget: "off" # buggy; manually use the below assertions instead
|
||||||
|
speed-index:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 3000
|
||||||
|
largest-contentful-paint:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 3000
|
||||||
|
first-contentful-paint:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 3000
|
||||||
|
first-meaningful-paint:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 3000
|
||||||
|
total-blocking-time:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 0
|
||||||
|
cumulative-layout-shift:
|
||||||
|
- warn
|
||||||
|
- maxNumericValue: 0
|
||||||
|
collect:
|
||||||
|
method: node
|
||||||
|
settings:
|
||||||
|
budgetPath: budget.json
|
||||||
|
chromeFlags: "--disable-gpu --no-sandbox --disable-extensions --no-first-run --headless"
|
||||||
|
skipAudits:
|
||||||
|
- robots-txt
|
||||||
|
- canonical
|
||||||
|
throttling:
|
||||||
|
cpuSlowdownMultiplier: 2
|
||||||
|
throttlingMethod: devtools
|
||||||
|
url:
|
||||||
|
- https://staging.seirdy.one/
|
||||||
|
- https://staging.seirdy.one/about.html
|
||||||
|
- https://staging.seirdy.one/2020/11/23/website-best-practices.html
|
||||||
|
numberOfRuns: 5
|
||||||
|
upload:
|
||||||
|
outputDir: lighthouse-reports
|
||||||
|
reportFilenamePattern: lighthouse-report-%%DATE%%.%%EXTENSION%%
|
||||||
|
target: filesystem
|
68
Makefile
68
Makefile
|
@ -1,39 +1,65 @@
|
||||||
CSS_DIR = themes/etch-custom/assets/css
|
CSS_DIR = themes/etch-custom/assets/css
|
||||||
|
DEVSERVER_URL="http://localhost:1313/"
|
||||||
|
|
||||||
USER = deploy@seirdy.one
|
DOMAIN = seirdy.one
|
||||||
WWW_ROOT = /var/www/seirdy.one
|
HUGO_BASEURL = "https://$(DOMAIN)/"
|
||||||
GEMINI_ROOT = /srv/gemini/seirdy.one
|
USER = deploy@$(DOMAIN)
|
||||||
|
WWW_ROOT = /var/www/$(DOMAIN)
|
||||||
|
GEMINI_ROOT = /srv/gemini/$(DOMAIN)
|
||||||
|
|
||||||
WWW_RSYNC_DEST = $(USER):$(WWW_ROOT)
|
WWW_RSYNC_DEST = $(USER):$(WWW_ROOT)
|
||||||
GEMINI_RSYNC_DEST = $(USER):$(GEMINI_ROOT)
|
GEMINI_RSYNC_DEST = $(USER):$(GEMINI_ROOT)
|
||||||
|
|
||||||
OUTPUT_DIR = public
|
OUTPUT_DIR = public
|
||||||
|
|
||||||
RSYNCFLAGS += -rlvz --zc=zstd
|
RSYNCFLAGS += -rlvz --zc=zstd
|
||||||
|
|
||||||
hugo:
|
.PHONY: hugo
|
||||||
hugo --gc --enableGitInfo
|
hugo: clean
|
||||||
|
hugo --gc -b $(HUGO_BASEURL)
|
||||||
|
|
||||||
# .hintrc-local for linting local files
|
# .hintrc-local for linting local files
|
||||||
# same as regular .hintrc but with a different connector.
|
# same as regular .hintrc but with a different connector.
|
||||||
.hintrc-local: .hintrc
|
.hintrc-local: .hintrc
|
||||||
jq --tab '.connector .name = "local" | del(.connector .options)' <.hintrc >.hintrc-local
|
jq --tab '.connector .name = "local" | del(.connector .options)' <.hintrc >.hintrc-local
|
||||||
|
|
||||||
|
.hintrc-devserver: .hintrc
|
||||||
|
jq --tab '.extends = ["development"] | .hints["http-compression","https-only","ssllabs","sri"] = "off"' <.hintrc >.hintrc-devserver
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OUTPUT_DIR) .hintrc-local
|
rm -rf $(OUTPUT_DIR) .lighthouseci lighthouse-reports
|
||||||
|
|
||||||
|
.PHONY: lint-css
|
||||||
lint-css:
|
lint-css:
|
||||||
stylelint $(CSS_DIR)/main.css $(CSS_DIR)/dark.css
|
stylelint --di --rd --rdd $(CSS_DIR)/main.css $(CSS_DIR)/dark.css
|
||||||
csslint $(CSS_DIR)
|
csslint --quiet $(CSS_DIR)
|
||||||
|
|
||||||
lint: lint-css hugo .hintrc-local
|
.PHONY: hint
|
||||||
|
hint: hugo .hintrc-local
|
||||||
hint --config .hintrc-local -f codeframe $(OUTPUT_DIR)
|
hint --config .hintrc-local -f codeframe $(OUTPUT_DIR)
|
||||||
|
rm .hintrc-local
|
||||||
|
|
||||||
|
.PHONY: lint-local
|
||||||
|
lint-local: lint-css hint
|
||||||
|
|
||||||
|
# dev server
|
||||||
|
.PHONY: serve
|
||||||
|
serve:
|
||||||
|
hugo serve --disableLiveReload
|
||||||
|
|
||||||
|
.PHONY: hint-devserver
|
||||||
|
hint-devserver: .hintrc-devserver
|
||||||
|
hint --config .hintrc-devserver -f codeframe $(DEVSERVER_URL)
|
||||||
|
rm .hintrc-devserver
|
||||||
|
|
||||||
|
.PHONY: check-links
|
||||||
check-links: hugo
|
check-links: hugo
|
||||||
lychee --verbose $(find public -type f -name '*.html' -o -name '*.gmi' -o -name '*.txt') content/posts/*.md content/posts/*.gmi
|
lychee --verbose $(find public -type f -name '*.html' -o -name '*.gmi' -o -name '*.txt') content/posts/*.md content/posts/*.gmi
|
||||||
|
|
||||||
test: lint check-links
|
.PHONY: test
|
||||||
|
test: lint-css hint-devserver check-links
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
build: hugo
|
build: hugo
|
||||||
# gzip_static + max zopfli compression
|
# gzip_static + max zopfli compression
|
||||||
ifndef NO_GZIP_STATIC
|
ifndef NO_GZIP_STATIC
|
||||||
|
@ -43,11 +69,23 @@ ifndef NO_GZIP_STATIC
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
deploy: build
|
.PHONY: deploy-html
|
||||||
|
deploy-html: build
|
||||||
rsync $(RSYNCFLAGS) --exclude 'gemini' --exclude '*.gmi' --exclude-from .rsyncignore $(OUTPUT_DIR)/ $(WWW_RSYNC_DEST) --delete
|
rsync $(RSYNCFLAGS) --exclude 'gemini' --exclude '*.gmi' --exclude-from .rsyncignore $(OUTPUT_DIR)/ $(WWW_RSYNC_DEST) --delete
|
||||||
rsync $(RSYNCFLAGS) --exclude '*.html' --exclude '*.xml' --exclude-from .rsyncignore $(OUTPUT_DIR)/gemini/ $(OUTPUT_DIR)/about $(OUTPUT_DIR)/posts $(OUTPUT_DIR)/publickey.txt $(GEMINI_RSYNC_DEST)/ --delete
|
|
||||||
|
.PHONY: deploy-gemini
|
||||||
|
deploy-gemini: hugo
|
||||||
|
rsync $(RSYNCFLAGS) --exclude '*.html' --exclude '*.xml' --exclude '*.gz' --exclude-from .rsyncignore $(OUTPUT_DIR)/gemini/ $(OUTPUT_DIR)/about $(OUTPUT_DIR)/posts $(OUTPUT_DIR)/publickey.txt $(GEMINI_RSYNC_DEST)/ --delete
|
||||||
rsync $(RSYNCFLAGS) $(OUTPUT_DIR)/posts/gemini.xml $(GEMINI_RSYNC_DEST)/feed.xml
|
rsync $(RSYNCFLAGS) $(OUTPUT_DIR)/posts/gemini.xml $(GEMINI_RSYNC_DEST)/feed.xml
|
||||||
|
|
||||||
all: clean test deploy
|
.PHONY: deploy
|
||||||
|
deploy: deploy-html deploy-gemini
|
||||||
|
|
||||||
.PHONY: clean lint-css lint check-links test hugo build deploy all
|
## stuff for the staging server
|
||||||
|
.PHONY: test-staging
|
||||||
|
test-staging: deploy-html
|
||||||
|
yq e '.ci .collect .url | .[]' .lighthouserc.yml | xargs hint -f codeframe
|
||||||
|
lhci autorun
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: test deploy
|
||||||
|
|
37
budget.json
37
budget.json
|
@ -3,7 +3,7 @@
|
||||||
"options": {
|
"options": {
|
||||||
"firstPartyHostnames": [
|
"firstPartyHostnames": [
|
||||||
"seirdy.one",
|
"seirdy.one",
|
||||||
"localhost"
|
"staging.seirdy.one"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"timings": [
|
"timings": [
|
||||||
|
@ -14,6 +14,14 @@
|
||||||
{
|
{
|
||||||
"metric": "cumulative-layout-shift",
|
"metric": "cumulative-layout-shift",
|
||||||
"budget": 0
|
"budget": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric": "interactive",
|
||||||
|
"budget": 3200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metric": "largest-contentful-paint",
|
||||||
|
"budget": 3200
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"resourceSizes": [
|
"resourceSizes": [
|
||||||
|
@ -48,32 +56,5 @@
|
||||||
"budget": 0
|
"budget": 0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/index.html",
|
|
||||||
"timings": [
|
|
||||||
{
|
|
||||||
"metric": "largest-contentful-paint",
|
|
||||||
"budget": 1000
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"resourceSizes": [
|
|
||||||
{
|
|
||||||
"resourceType": "total",
|
|
||||||
"budget": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceType": "document",
|
|
||||||
"budget": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceType": "image",
|
|
||||||
"budget": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"resourceType": "stylesheet",
|
|
||||||
"budget": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
23
config.toml
23
config.toml
|
@ -4,7 +4,8 @@ title = "Seirdy's Home"
|
||||||
theme = "etch-custom"
|
theme = "etch-custom"
|
||||||
|
|
||||||
enableInlineShortcodes = true
|
enableInlineShortcodes = true
|
||||||
# disablePathToLower = true
|
enableGitInfo = true
|
||||||
|
disableHugoGeneratorInject = true # first item in <head> should be charset=utf-8
|
||||||
uglyurls = true
|
uglyurls = true
|
||||||
pygmentsCodeFences = true
|
pygmentsCodeFences = true
|
||||||
pygmentsUseClasses = true
|
pygmentsUseClasses = true
|
||||||
|
@ -76,3 +77,23 @@ path = "gemini/"
|
||||||
|
|
||||||
[outputs]
|
[outputs]
|
||||||
section = ["HTML", "RSS", "GEMRSS"]
|
section = ["HTML", "RSS", "GEMRSS"]
|
||||||
|
|
||||||
|
[server]
|
||||||
|
[[server.headers]]
|
||||||
|
for = "/**.{css,png,webp,webm}"
|
||||||
|
[server.headers.values]
|
||||||
|
X-Content-Type-Options = "nosniff"
|
||||||
|
Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
|
||||||
|
Cache-Control = "max-age=31557600, immutable"
|
||||||
|
[[server.headers]]
|
||||||
|
for = "/**"
|
||||||
|
[server.headers.values]
|
||||||
|
X-Content-Type-Options = "nosniff"
|
||||||
|
Strict-Transport-Security = "max-age=31536000; includeSubDomains; preload"
|
||||||
|
Referrer-Policy = "no-referrer"
|
||||||
|
X-XSS-Protection = "1; mode=block"
|
||||||
|
X-FROG-UNSAFE = "1"
|
||||||
|
X-UA-Compatible = "IE=edge"
|
||||||
|
Content-Security-Policy = "default-src 'none'; img-src 'self'; style-src 'self'; script-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'; manifest-src 'self'; upgrade-insecure-requests;"
|
||||||
|
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()"
|
||||||
|
Cache-Control = "max-age=120, no-transform"
|
||||||
|
|
|
@ -2,5 +2,6 @@ insecure = true
|
||||||
method = "get"
|
method = "get"
|
||||||
exclude = [
|
exclude = [
|
||||||
"^gemini://.*",
|
"^gemini://.*",
|
||||||
|
"mailto:.*",
|
||||||
"git@git.*",
|
"git@git.*",
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
{{ $webmanifest := resources.Get "/manifest.webmanifest" | resources.ExecuteAsTemplate "manifest.webmanifest" . | resources.Fingerprint "md5" -}}
|
{{ $webmanifest := resources.Get "/manifest.webmanifest" | resources.ExecuteAsTemplate "manifest.webmanifest" . | resources.Fingerprint "md5" -}}
|
||||||
{{ printf `<link rel="manifest" href="%s">` $webmanifest.RelPermalink | safeHTML }}
|
{{ printf `<link rel="manifest" href="%s">` $webmanifest.RelPermalink | safeHTML }}
|
||||||
<link rel="alternate" type="application/rss+xml" href="{{ .Site.BaseURL }}posts/index.xml" title="{{ $.Site.Title }}">
|
<link rel="alternate" type="application/rss+xml" href="{{ .Site.BaseURL }}posts/index.xml" title="{{ $.Site.Title }}">
|
||||||
{{ if eq .Site.BaseURL "https://envs.net/~seirdy/" -}}
|
{{ if ne .Site.BaseURL "https://seirdy.one/" -}}
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
{{ else -}}
|
{{ else -}}
|
||||||
<link rel="canonical" href="https://seirdy.one{{ .RelPermalink }}">
|
<link rel="canonical" href="https://seirdy.one{{ .RelPermalink }}">
|
||||||
|
|
Loading…
Reference in a new issue