diff --git a/.gitignore b/.gitignore index 26816642a7..1939ff555a 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,6 @@ bskyweb/static/media/*.svg # superpowers plugin plans/specs — local-only workspace docs/superpowers/ + +# worktrees +.claude/worktrees/ diff --git a/bskyweb/.gitignore b/bskyweb/.gitignore index a63a381f94..81a5fc6980 100644 --- a/bskyweb/.gitignore +++ b/bskyweb/.gitignore @@ -6,17 +6,12 @@ test-coverage.out /embedr # Don't accidentally commit JS-generated code -static/js/*.js -static/js/*.map -static/js/*.js.LICENSE.txt -static/js/empty.txt -static/css/*.css -static/css/*.map -static/css/*.css.LICENSE.txt -static/css/empty.txt +static/_expo/ +static/assets/ static/media/*.png static/media/empty.txt templates/scripts.html +templates/fonts.html templates/*-embed.html static/embed/*.html static/embed/assets/*.js diff --git a/bskyweb/cmd/bskyweb/server.go b/bskyweb/cmd/bskyweb/server.go index fcaef6d740..1236e49e88 100644 --- a/bskyweb/cmd/bskyweb/server.go +++ b/bskyweb/cmd/bskyweb/server.go @@ -260,8 +260,8 @@ func serve(cctx *cli.Context) error { path := c.Request().URL.Path maxAge := 1 * (60 * 60) // default is 1 hour - // all assets in /static/js, /static/css, /static/media are content-hashed and can be cached for a long time - if strings.HasPrefix(path, "/static/js/") || strings.HasPrefix(path, "/static/css/") || strings.HasPrefix(path, "/static/media/") { + // all assets in /static/_expo, /static/assets, /static/media are content-hashed and can be cached for a long time + if strings.HasPrefix(path, "/static/_expo/") || strings.HasPrefix(path, "/static/assets/") || strings.HasPrefix(path, "/static/media/") { maxAge = 365 * (60 * 60 * 24) // 1 year } diff --git a/bskyweb/static.go b/bskyweb/static.go index 38adb83335..4b59f27d76 100644 --- a/bskyweb/static.go +++ b/bskyweb/static.go @@ -2,7 +2,10 @@ package bskyweb import "embed" -//go:embed static/* +// `all:` disables the default exclusion of files/dirs beginning with `_` or `.`, +// which is needed because Metro emits chunks like `__common-...js` and +// `__expo-metro-runtime-...js`. +//go:embed all:static var StaticFS embed.FS //go:embed embedr-static/* diff --git a/bskyweb/static/css/.gitkeep b/bskyweb/static/css/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html index e33479e697..fab7664730 100644 --- a/bskyweb/templates/base.html +++ b/bskyweb/templates/base.html @@ -13,7 +13,7 @@ - + {% include "fonts.html" %} +` +console.log(`Writing ${fontsTemplateFile}`) +fs.writeFileSync(fontsTemplateFile, fontsHtml) + // Clean previous build output to avoid stale files function cleanDir(dir) { if (fs.existsSync(dir)) { @@ -71,11 +117,10 @@ function cleanDir(dir) { } } -cleanDir(path.join(bskywebStatic, 'js', 'web')) -cleanDir(path.join(bskywebStatic, 'css')) +cleanDir(path.join(bskywebStatic, '_expo')) cleanDir(path.join(bskywebStatic, 'assets')) -// Recursively copy a directory, skipping source map files +// Recursively copy a directory. function copyDir(sourceDir, targetDir) { if (!fs.existsSync(sourceDir)) { console.log(`Skipping ${sourceDir} (does not exist)`) @@ -88,26 +133,18 @@ function copyDir(sourceDir, targetDir) { const targetPath = path.join(targetDir, entry.name) if (entry.isDirectory()) { copyDir(sourcePath, targetPath) - } else if (!entry.name.endsWith('.map')) { + } else { fs.copyFileSync(sourcePath, targetPath) console.log(`Copied ${sourcePath} to ${targetPath}`) } } } -// Copy JS chunks -copyDir( - path.join(distDir, '_expo', 'static', 'js', 'web'), - path.join(bskywebStatic, 'js', 'web'), -) +// Copy Metro's _expo/ tree wholesale so JS chunks (including lazy chunks +// referenced by hash) and source maps resolve at the same paths the runtime expects. +copyDir(path.join(distDir, '_expo'), path.join(bskywebStatic, '_expo')) -// Copy CSS -copyDir( - path.join(distDir, '_expo', 'static', 'css'), - path.join(bskywebStatic, 'css'), -) - -// Copy assets (fonts, images, icons, etc.) +// Copy assets (fonts, images, icons, etc.) referenced as /static/assets/... by the bundle. copyDir(path.join(distDir, 'assets'), path.join(bskywebStatic, 'assets')) // Upload source maps to Sentry