Modernise stack: Vite + React 19 + TS + MUI v9#20
Open
pleb wants to merge 6 commits into
Open
Conversation
Replace Create React App 5 with Vite 8, add TypeScript 6 strict mode, ESLint 9 flat config, Prettier 3, and Node 22 pinning. Drop the stale Snyk patch file (Lodash is gone) and the legacy .eslintrc / public/index.html (now at repo root for Vite).
Replace the Bulma + Redux + class-component stack with MUI v9 components
and react-hook-form. Custom MUI theme matches the previous dark-navy AppBar
and MakerX blue.
Security and correctness fixes surfaced during the migration:
- remove dangerouslySetInnerHTML from Signature and RepliesAndForwards;
phone numbers now render as React text nodes with nbsp spans
- validate the email before interpolating into the mailto href
- replace document.execCommand('copy') with the async Clipboard API,
returning Promise<boolean> so the Button can show success vs error state
- collapse the latent nested <tr> bug in the standard signature
- fix constants.brandGPTWLogo (was undefined) to constants.brandInfo.brandGPTWLogo
- add null guards on parseMobile callers
Performance: Signature components wrapped in React.memo, SignatureContainer
subscribes per-field via useWatch and defers the preview render with
useDeferredValue so typing stays responsive.
Embed mode: ?embedded=1 hides the AppBar for iframing.
Inline-styled <table> markup in the signature components is intentionally
preserved; comments explaining the email-client constraints are kept.
Replaces the single Button snapshot from the old Jest setup with: - parseMobile, isValidEmail, stripObject unit tests - Clipboard helper tests covering both write success and write rejection paths, so the Button error state has coverage - Form regression guard that the required asterisks render on initial mount - Button state transition tests (success label, error label, auto-revert) - Golden HTML assertions for Signature and RepliesAndForwards against a checked-in fixture; this is the primary regression gate against silent email-client output changes on future dep bumps
- Every action pinned to a full commit SHA with the version tag as a comment (checkout v6.0.2, setup-node v6.4.0, configure-pages v6.0.0, upload-pages-artifact v5.0.0, deploy-pages v5.0.0). SHAs re-verified via gh api before writing the workflows. - CI gains audit, lint, typecheck, and test steps before build; permissions reduced to contents:read. - CD migrates from JamesIves/github-pages-deploy-action + gh-pages branch to the native GitHub Pages flow (actions/configure-pages + upload-pages-artifact + deploy-pages). OIDC id-token:write is scoped to the deploy job only. Concurrency group prevents overlapping deploys. - public/CNAME preserves the signatures.makerx.tech custom domain in every artifact, replacing the gh-pages branch that previously held it. - Dependabot watches both npm and github-actions weekly, with minor+patch updates grouped per ecosystem. First-time setup required: repo Settings -> Pages -> Source = "GitHub Actions". Documented in README.
Drops the CRA boilerplate, documents the new Vite scripts, Node 22 requirement, embed mode (?embedded=1), and the one-time Pages source toggle required for first deploy. Notes the absence of pre-commit hooks and warns that MUI majors are not handled by grouped Dependabot patches. Also commits docs/upgrading.md, the modernisation process notes kept by the maintainer to drive future stack upgrades.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
End-to-end modernisation of the signature generator. CRA is unmaintained, the stack was mixing Bulma + Redux + class components for a tiny single-form app, the Snyk patch file dated from 2020, and every GitHub Action was pinned to a floating
@v2tag. This PR rebuilds on a current, secure toolchain while preserving the exact email-signature output that staff and Outlook care about.Stack changes
.nvmrc+enginesJamesIves/github-pages-deploy-action-> gh-pages branchactions/upload-pages-artifact+actions/deploy-pages(OIDC, no gh-pages branch)@v2Security & correctness
Surfaced and fixed during the migration:
dangerouslySetInnerHTMLin bothSignature.tsxandRepliesAndForwards.tsx. Phone numbers now render as React text nodes withnbspspans; no user-controlled string flows through__htmlany more.href={\mailto:${email}`}` (regex check; fall through to plain text on failure).document.execCommand('copy'). ReturnsPromise<boolean>so the Copy button can show an "error" state on rejection instead of silently flashing "Copied!".npm audit --audit-level=high --omit=devnow runs on every PR; production dep graph is clean (0 vulnerabilities).contents: readon the build job,id-token: writeconfined to the deploy job only.constants.brandGPTWLogo(undefined) ->constants.brandInfo.brandGPTWLogo; nested<tr>collapsed;parseMobilenull guards.Performance
SignatureandRepliesAndForwardswrapped inReact.memo.SignatureContainersubscribes per-field viauseWatchand defers the preview withuseDeferredValueso typing stays responsive.<link rel=\"preload\">for the Azure-hosted brand logos inindex.html.UX
*asterisks visible from initial render.?embedded=1query param hides the AppBar for iframing.#000c28) and MakerX blue (#003FB5).Test plan
npm run lintexits 0npm run typecheckexits 0npm test -- --run-> 22 / 22 passing (parseMobile, isValidEmail, stripObject, clipboard success+rejection, Form required asterisks, Button state transitions, Signature + RepliesAndForwards golden HTML)npm run buildclean (236 KB gzipped)npm audit --audit-level=high --omit=dev-> 0 vulnerabilities?embedded=1hides AppBar)One-time deploy setup required
Before the first merge to
maincan deploy successfully, in repo Settings -> Pages -> Source, choose GitHub Actions (the native flow replaces the gh-pages branch). The CD workflow will fail with a clear error until this is done. README documents this in its own section.The custom domain (
signatures.makerx.tech) is preserved bypublic/CNAME, which ships in every artifact.Out of scope / follow-ups
eslint-plugin-reacthas not yet published a v10-compatible release. Dependabot will pick this up when it lands.