From d2de86d16600c346762314f72d709e0a8df05a1a Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Fri, 9 Oct 2026 23:56:18 +0200 Subject: [PATCH 1/2] fix: clean up guide deployment assets and configuration Serve the guide public directory so robots.txt reaches the deployed Worker. Import shared favicon assets through Vite and verify robots and icon responses in the Wrangler CI smoke check. Remove the unused build/client-to-out copy and stale TODO checklist. Document the actual deployment directory and keep outstanding launch work in the README. Fixes #1406. Part of #1421. --- .github/workflows/pull-request.yml | 4 ++ .gitignore | 1 - apps/guide/README.md | 17 +++-- apps/guide/TODO.md | 73 ------------------- apps/guide/app/root.jsx | 112 +++++++++++++++++------------ apps/guide/app/root.res | 16 ++++- apps/guide/app/root.resi | 1 + apps/guide/react-router.config.mjs | 5 -- apps/guide/vite.config.mjs | 2 - 9 files changed, 97 insertions(+), 134 deletions(-) delete mode 100644 apps/guide/TODO.md diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index e11c81136..941da3094 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -84,6 +84,10 @@ jobs: for _ in {1..15}; do if curl --max-time 2 --fail --silent http://127.0.0.1:8789/ > /dev/null; then + curl --max-time 2 --fail --silent http://127.0.0.1:8789/robots.txt | cmp public/robots.txt - + for guide_icon in build/client/assets/*.avif; do + curl --max-time 2 --fail --silent "http://127.0.0.1:8789/${guide_icon#build/client/}" | cmp "$guide_icon" - + done exit 0 fi sleep 1 diff --git a/.gitignore b/.gitignore index 001b864b5..177e198e7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ node_modules/ .next/ out/ apps/docs/out/ -apps/guide/out/ index_data/*.json apps/docs/index_data/*.json diff --git a/apps/guide/README.md b/apps/guide/README.md index 4dd962e6e..f536d4e86 100644 --- a/apps/guide/README.md +++ b/apps/guide/README.md @@ -16,6 +16,7 @@ contract only. Lesson copy belongs to the guide author. | `app/GuideHome.res` | Guide workspace UI | | `app/GuideCompilerBridgeHook.res` | Browser compiler and execution integration | | `styles/main.css` | Guide-only visual system and responsive behavior | +| `public/` | Guide static assets, including `robots.txt` | | `__tests__/` | Browser and unit coverage for the guide | ## Lesson Contract @@ -71,9 +72,12 @@ yarn build:guide yarn workspace @rescript-lang/guide ci:test ``` -`yarn build:guide` compiles ReScript, pre-renders `/`, and copies the client -assets to `apps/guide/out/` for Wrangler. The guide fetches available compiler -versions from `https://cdn.rescript-lang.org` during pre-rendering; the +`yarn build:guide` compiles ReScript and pre-renders `/` into +`apps/guide/build/client/`, the assets directory configured in `wrangler.toml`. +Vite serves and copies the guide's `public/` directory, including `robots.txt`. +The root route imports the shared docs favicons so Vite emits them with the +guide's other assets. The guide fetches available compiler versions from +`https://cdn.rescript-lang.org` during pre-rendering; the interactive compiler and runtime then run in the learner's browser. ## Current Capability @@ -92,7 +96,7 @@ show a stop screen rather than a usable guide. ## Production Checklist -Before launch, complete and verify the following: +Track outstanding guide launch work in this checklist: - [ ] Author, review, and run every lesson using its real expected output. - [ ] Add a content-validation test for the complete lesson set, including @@ -108,6 +112,7 @@ Before launch, complete and verify the following: compiler and checkpoint changes. - [ ] Choose mobile support or explicitly publish the desktop-only constraint with an alternate learning path. +- [ ] Define the supported browsers and initial page-load performance budget. - [ ] Split or defer the initial compiler/editor code so the initial route is within the agreed performance budget. - [ ] Replace the deprecated Vite `envFile` configuration and resolve the @@ -121,6 +126,6 @@ Before launch, complete and verify the following: ## Deployment The `deploy-guide` job in `.github/workflows/deploy.yml` builds the guide and -deploys it with Wrangler. Pushes to `master` deploy the production Worker; -non-Dependabot pull requests from this repository receive a preview Worker +deploys its `build/client/` assets with Wrangler. Pushes to `master` deploy the +production Worker; non-Dependabot pull requests from this repository receive a preview Worker version and a link in the pull request. diff --git a/apps/guide/TODO.md b/apps/guide/TODO.md deleted file mode 100644 index b4b7c2011..000000000 --- a/apps/guide/TODO.md +++ /dev/null @@ -1,73 +0,0 @@ -# Guide MVP Launch TODO - -This checklist is for making the interactive guide ready to launch. It does not -cover writing or editing lesson content. - -## 1. Define The Launch Boundary - -- [ ] Decide the public guide URL and Cloudflare Worker custom domain. -- [ ] Record that the initial release requires a desktop browser. -- [ ] Define the supported browsers and the performance budget for the initial - page load. -- [ ] Assign ownership for deployment, CDN/compiler availability, learner - support, and production incident response. - -## 2. Complete The Exercise System - -- [ ] Choose a completion strategy for exercises that cannot be checked with - one exact runtime-output line. -- [ ] Implement that strategy without allowing an incomplete lesson to unlock - the next one. -- [ ] Decide whether learners need an explicit reset action for one exercise, - all progress, or both. -- [ ] Decide how published lesson or exercise identifier changes preserve or - intentionally reset browser-local progress. - -## 3. Make Lesson Structure Safe To Publish - -- [ ] Add build-time validation that lesson IDs, exercise IDs, and positions - are unique. -- [ ] Add tests for the complete lesson collection rather than fixtures only. -- [ ] Add tests for invalid or incomplete lesson frontmatter. -- [ ] Verify every published exercise against the production compiler version - and its expected runtime output. -- [ ] Establish a human review path for lesson accuracy, progression, and - accessibility. Lesson writing remains author-owned. - -## 4. Finish The Product Surface - -- [ ] Add the production document metadata, favicon, social preview asset, and - canonical URL. -- [ ] Decide and implement robots and sitemap/discovery behavior for the guide - domain. -- [ ] Add keyboard-operable pane resizing or replace resize controls with an - accessible alternative. -- [ ] Add visible focus styles and announce compiler errors, output changes, - and checkpoint state changes to assistive technology. -- [x] Show a clear small-screen warning that the guide requires a desktop - browser. - -## 5. Reduce Delivery Risk - -- [ ] Split or defer the compiler/editor bundle to meet the agreed initial-load - budget. The current initial guide route is 1.61 MB uncompressed (463 KB - gzip). -- [ ] Replace the deprecated Vite `envFile` option. -- [ ] Resolve the guide workspace's `@types/react` peer-dependency warning. -- [ ] Decide whether compiler-version metadata should be available at build - time, at runtime, or both when the CDN is unavailable. -- [ ] Add graceful user-visible handling for compiler-CDN and runtime failures. - -## 6. Prove The Release Path - -- [ ] Ensure the pinned Playwright Chromium browser is installed in local and - CI environments, then run `yarn workspace @rescript-lang/guide ci:test`. -- [ ] Add a production-preview smoke test covering page load, compiler - availability, one successful checkpoint, hash deep link, persisted draft, - and final navigation. -- [ ] Test the Cloudflare preview Worker with the intended production domain - configuration and SPA fallback behavior. -- [ ] Define rollback steps and verify that a prior Worker version can be - restored. -- [ ] Record the final launch decision and remaining accepted risks in the - release pull request. diff --git a/apps/guide/app/root.jsx b/apps/guide/app/root.jsx index 798528bea..d08a1138e 100644 --- a/apps/guide/app/root.jsx +++ b/apps/guide/app/root.jsx @@ -3,56 +3,80 @@ import * as ReactRouter from "react-router"; import * as JsxRuntime from "react/jsx-runtime"; import MainCssurl from "../styles/main.css?url"; +import FaviconX16AvifurlnoInline from "../../docs/public/favicon/favicon-16x16.avif?url&no-inline"; +import FaviconX32AvifurlnoInline from "../../docs/public/favicon/favicon-32x32.avif?url&no-inline"; +import AppleTouchIconAvifurlnoInline from "../../docs/public/favicon/apple-touch-icon.avif?url&no-inline"; let mainCss = MainCssurl; +let appleTouchIcon = AppleTouchIconAvifurlnoInline; + +let favicon32 = FaviconX32AvifurlnoInline; + +let favicon16 = FaviconX16AvifurlnoInline; + function Root$default(props) { - return ( - - - - - - - - - - - - - - {"ReScript Guide"} - - - - - - - - ); + return + + + + + + + + + + + + + + {"ReScript Guide"} + + + + + + + + ; } let $$default = Root$default; -export { $$default as default }; +export { + $$default as default, +} /* mainCss Not a pure module */ diff --git a/apps/guide/app/root.res b/apps/guide/app/root.res index d90e70733..d817565df 100644 --- a/apps/guide/app/root.res +++ b/apps/guide/app/root.res @@ -1,6 +1,16 @@ @module("../styles/main.css?url") external mainCss: string = "default" +// Share the official icons while keeping the guide's own public directory. +@module("../../docs/public/favicon/apple-touch-icon.avif?url&no-inline") +external appleTouchIcon: string = "default" + +@module("../../docs/public/favicon/favicon-32x32.avif?url&no-inline") +external favicon32: string = "default" + +@module("../../docs/public/favicon/favicon-16x16.avif?url&no-inline") +external favicon16: string = "default" + @react.component let default = () => { @@ -13,9 +23,9 @@ let default = () => { - - - + + + {React.string("ReScript Guide")} diff --git a/apps/guide/app/root.resi b/apps/guide/app/root.resi index 47fa1ac2e..7e91a2ebb 100644 --- a/apps/guide/app/root.resi +++ b/apps/guide/app/root.resi @@ -1,2 +1,3 @@ +// Keep build asset bindings private; React Router consumes the root component. @react.component let default: unit => React.element diff --git a/apps/guide/react-router.config.mjs b/apps/guide/react-router.config.mjs index df41a8ad8..634528bc5 100644 --- a/apps/guide/react-router.config.mjs +++ b/apps/guide/react-router.config.mjs @@ -1,9 +1,4 @@ -import * as fs from "node:fs"; - export default { ssr: false, prerender: ["/"], - buildEnd: async () => { - fs.cpSync("./build/client", "./out", { recursive: true }); - }, }; diff --git a/apps/guide/vite.config.mjs b/apps/guide/vite.config.mjs index fc20d334c..b6e1594e1 100644 --- a/apps/guide/vite.config.mjs +++ b/apps/guide/vite.config.mjs @@ -42,8 +42,6 @@ export default defineConfig(({ mode }) => { return { envDir: "../..", - // Reuse the official favicon set without duplicating branding assets. - publicDir: "../docs/public/favicon", plugins: [ env({ prefix: "PUBLIC_" }), ...(isTest ? [] : [reactRouter()]), From c75fe0e45d4707d47a87d0bf13367fec46a33c3e Mon Sep 17 00:00:00 2001 From: Florian Hammerschmidt Date: Sat, 10 Oct 2026 00:00:06 +0200 Subject: [PATCH 2/2] fix: exclude generated guide app JSX from formatting The guide root and route outputs are tracked compiler files. Keep their compiler formatting authoritative instead of requiring hand-formatting after compilation. --- .oxfmtrc.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.oxfmtrc.json b/.oxfmtrc.json index c94351978..f4e51e821 100644 --- a/.oxfmtrc.json +++ b/.oxfmtrc.json @@ -12,6 +12,7 @@ "*.swo", "*.swp", "apps/docs/app/**/*.mjs", + "apps/guide/app/**/*.jsx", "build", "data/api/**/*.json", "apps/docs/data/api/**/*.json",