Skip to content

Commit 8c6dd69

Browse files
fix: transpile JS for old browsers (KaiOS 2.x / Gecko 48)
- run both JS bundles through js.Babel (targets incl. firefox >= 48) - work around Hugo's minifier rewriting Math.pow/Math.sqrt as ** regardless of minify.tdewolff.js.version (scripts/babel-keep-math-calls.cjs) - polyfill NodeList.forEach, avoid it in the taxonomy inline script - install Babel and postcss-preset-env (legacy CSS) in the GitHub workflow Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent af09fe2 commit 8c6dd69

7 files changed

Lines changed: 134 additions & 13 deletions

File tree

‎.babelrc‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
{
2-
"presets": [
3-
[
4-
"@babel/preset-env",
5-
{
6-
"targets": ">0.5%, last 2 versions, Firefox ESR, not dead"
7-
}
8-
]
2+
// Used by js.Babel in layouts/partials/essentials/script.html.
3+
// "firefox >= 48" keeps KaiOS 2.x (Gecko 48) working, see also the
4+
// minify.tdewolff.js.version setting in hugo.toml.
5+
// The bundles are plain concatenated scripts (UMD plugins rely on a
6+
// top-level `this`), so they must not be parsed as ES modules.
7+
"sourceType": "script",
8+
"plugins": ["./scripts/babel-keep-math-calls.cjs"],
9+
"presets": [
10+
[
11+
"@babel/preset-env",
12+
{
13+
"targets": ">0.5%, last 2 versions, Firefox ESR, not dead, firefox >= 48",
14+
"modules": false
15+
}
916
]
10-
}
17+
]
18+
}

‎.github/workflows/website.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ jobs:
4040
uses: actions/configure-pages@v5
4141
- name: Install Node.js dependencies
4242
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
43-
- name: Install PostCSS, Tailwind and Autoprefixer
44-
run: npm install postcss postcss-cli tailwindcss autoprefixer
43+
- name: Install PostCSS, Tailwind, Autoprefixer and Babel
44+
run: npm install postcss postcss-cli postcss-preset-env tailwindcss autoprefixer @babel/cli @babel/core @babel/preset-env
4545
- name: Install Python
4646
run: sudo apt-get install python3
4747
- name: Build World-Map

‎assets/js/legacy-polyfills.js‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Polyfills for old browsers such as KaiOS 2.x (Gecko 48). Loaded first in the
2+
// main bundle (see hugo.toml), modern browsers skip them.
3+
4+
// NodeList.forEach (Firefox 50+), used e.g. by search.js and tab.js
5+
if (window.NodeList && !NodeList.prototype.forEach) {
6+
NodeList.prototype.forEach = Array.prototype.forEach;
7+
}

‎hugo.toml‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,18 @@ enable = true
4949
source = 'assets/notwatching/hugo_stats\.json'
5050
target = 'css'
5151

52+
# Keep minified JS at ES2015 syntax for old engines such as KaiOS 2.x (Gecko 48),
53+
# the default (latest) lets the minifier emit newer syntax. It does not cover its
54+
# Math.pow/Math.sqrt => ** rewrite, see scripts/babel-keep-math-calls.cjs.
55+
[minify.tdewolff.js]
56+
version = 2015
57+
5258
############################ Security ############################
5359
# Newer Hugo versions (0.165 fails, 0.159 still works) no longer allow the tailwindcss binary by default,
5460
# which breaks css.TailwindCSS in layouts/partials/essentials/style.html.
61+
# babel is needed by js.Babel in layouts/partials/essentials/script.html.
5562
[security.exec]
56-
allow = ['^(dart-)?sass$', '^go$', '^git$', '^node$', '^postcss$', '^tailwindcss$']
63+
allow = ['^(dart-)?sass$', '^go$', '^git$', '^node$', '^postcss$', '^tailwindcss$', '^babel$']
5764

5865
############################# Modules ############################
5966
[module]
@@ -144,6 +151,9 @@ lazy = true
144151

145152
# JS Plugins
146153
[[params.plugins.js]]
154+
link = "js/legacy-polyfills.js"
155+
lazy = false
156+
[[params.plugins.js]]
147157
link = "js/search.js"
148158
lazy = false
149159
[[params.plugins.js]]

‎layouts/_default/taxonomy.html‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@
3535
var activeTag = params.get('tag');
3636

3737
if (activeTag) {
38-
document.querySelectorAll('#taxonomy-post-list .post-card').forEach(function (card) {
38+
// [].forEach.call: runs before the NodeList.forEach polyfill (old engines, e.g. KaiOS)
39+
[].forEach.call(document.querySelectorAll('#taxonomy-post-list .post-card'), function (card) {
3940
var tags = card.dataset.tags ? card.dataset.tags.split(',') : [];
4041
card.style.display = tags.indexOf(activeTag) === -1 ? 'none' : '';
4142
});
4243
}
4344

44-
document.querySelectorAll('.tag-filter-link').forEach(function (link) {
45+
[].forEach.call(document.querySelectorAll('.tag-filter-link'), function (link) {
4546
var linkTag = new URL(link.href).searchParams.get('tag');
4647
if (linkTag === activeTag) {
4748
link.classList.remove('bg-white', 'dark:bg-darkmode-body');
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<!-- JS Plugins + Main script -->
2+
{{ $scripts := slice }}
3+
{{ $scriptsLazy := slice }}
4+
{{ range site.Params.plugins.js }}
5+
{{ if findRE "^http" .link }}
6+
<script
7+
src="{{ .link | relURL }}"
8+
type="application/javascript"
9+
{{ .attributes | safeHTMLAttr }}></script>
10+
{{ else }}
11+
{{ if not .lazy }}
12+
{{ $scripts = $scripts | append (resources.Get .link) }}
13+
{{ else }}
14+
{{ $scriptsLazy = $scriptsLazy | append (resources.Get .link) }}
15+
{{ end }}
16+
{{ end }}
17+
{{ end }}
18+
19+
20+
<!-- main script -->
21+
{{ $scripts = $scripts | append (resources.Get "js/main.js") }}
22+
{{ $scripts = $scripts | resources.Concat "js/script.js" }}
23+
24+
{{ $scriptsLazy = $scriptsLazy | resources.Concat "js/script-lazy.js" }}
25+
26+
{{/* Transpile for old engines such as KaiOS 2.x (Gecko 48), see .babelrc.
27+
Overrides the theme's partial only to add this step. */}}
28+
{{ $babelOpts := dict "config" ".babelrc" }}
29+
{{ $scripts = $scripts | js.Babel $babelOpts }}
30+
{{ $scriptsLazy = $scriptsLazy | js.Babel $babelOpts }}
31+
32+
{{ if hugo.IsProduction }}
33+
{{ $scripts = $scripts | minify | fingerprint }}
34+
{{ $scriptsLazy = $scriptsLazy | minify | fingerprint }}
35+
{{ end }}
36+
37+
{{/* scripts */}}
38+
<script
39+
crossorigin="anonymous"
40+
integrity="{{ $scripts.Data.Integrity }}"
41+
src="{{ $scripts.RelPermalink }}"></script>
42+
43+
{{/* scripts lazy */}}
44+
<script
45+
defer
46+
async
47+
crossorigin="anonymous"
48+
integrity="{{ $scriptsLazy.Data.Integrity }}"
49+
src="{{ $scriptsLazy.RelPermalink }}"></script>
50+
51+
<!-- progressive web app -->
52+
{{ partialCached "pwa.html" . }}
53+
54+
55+
<!-- cookie consent -->
56+
{{ partialCached "cookie-consent.html" . }}
57+
58+
59+
<!-- google adsense -->
60+
{{ partialCached "adsense-script.html" . }}
61+
62+
63+
<!-- cookie consent -->
64+
{{ partialCached "announcement-script.html" . }}

‎scripts/babel-keep-math-calls.cjs‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Babel plugin, see .babelrc: rewrites Math.pow(a, b) / Math.sqrt(x) as
2+
// Math["pow"](a, b) / Math["sqrt"](x).
3+
//
4+
// Hugo's JS minifier (tdewolff/minify) turns Math.pow(a, b) into a**b and
5+
// Math.sqrt(x) into x**.5, ignoring minify.tdewolff.js.version. The **
6+
// operator is a SyntaxError in old engines such as KaiOS 2.x (Gecko 48) and
7+
// takes the whole bundle down. The bracket form is not matched by that
8+
// optimization, the minifier still prints it as Math.pow(...) / Math.sqrt(...).
9+
const NAMES = new Set(["pow", "sqrt"]);
10+
11+
module.exports = function ({ types: t }) {
12+
return {
13+
name: "keep-math-calls",
14+
visitor: {
15+
CallExpression(path) {
16+
const callee = path.node.callee;
17+
if (
18+
t.isMemberExpression(callee) &&
19+
!callee.computed &&
20+
t.isIdentifier(callee.object, { name: "Math" }) &&
21+
t.isIdentifier(callee.property) &&
22+
NAMES.has(callee.property.name) &&
23+
!path.scope.getBinding("Math")
24+
) {
25+
callee.property = t.stringLiteral(callee.property.name);
26+
callee.computed = true;
27+
}
28+
},
29+
},
30+
};
31+
};

0 commit comments

Comments
 (0)