Skip to content

4.0.0#698

Open
ionwyn wants to merge 45 commits into
masterfrom
4.0.0
Open

4.0.0#698
ionwyn wants to merge 45 commits into
masterfrom
4.0.0

Conversation

@ionwyn
Copy link
Copy Markdown
Collaborator

@ionwyn ionwyn commented May 12, 2026

No description provided.

ionwyn added 30 commits May 5, 2026 14:46
No source imports jquery anywhere in client/.
node-sass is deprecated and fails to build on Node 18+. Dart sass is
the official successor and is a drop-in for the @import/@use syntax
already in src/scss/.
IE11 reached end-of-life in 2022. Removing the polyfill imports and the
"ie 11" entry from browserslist.development reduces bundle weight and
unblocks the move off CRA.
The CRA-generated serviceWorker.js was only ever called via
unregister(); it has never registered a worker. Removing the file and
its import.
vite + @vitejs/plugin-react replace react-scripts as the build tool.
Config ports the dev proxy from src/setupProxy.js (which is removed in
a later commit alongside react-scripts itself), honors GENERATE_SOURCEMAP
from .env.production, and pins build.outDir to 'build' so the existing
Dockerfile/nginx pipeline keeps working unchanged.

The REACT_APP_ env prefix is preserved here; renames to VITE_ land in a
follow-up commit so the env-var migration is reviewable in isolation.
Vite's React plugin requires a .jsx extension on files containing JSX
syntax (CRA was forgiving here). Pure rename, no content change.
Vite expects index.html at the project root (rather than public/) and
treats it as the build entry. Files in public/ are still served at the
URL root, so absolute paths like /images/... and /js/env.config.js
continue to resolve.

Also adds the <script type="module" src="/src/index.jsx"> tag that Vite
uses as the module graph entry, and trims CRA-era boilerplate comments.
Replace %PUBLIC_URL%/... refs (CRA template syntax) with absolute paths.
Files in public/ are still served at the URL root by Vite, so
/images/..., /manifest.json, and /js/env.config.js continue to resolve.

Add <script type="module" src="/src/index.jsx"> as Vite's module-graph
entry, and trim CRA-era boilerplate comments.
Vite only exposes env vars prefixed with VITE_ to the client bundle (via
import.meta.env). Renaming the build-time env vars and their consumers
in Constants.js and Keycloak.js. Also drops the BROWSER=none CRA-ism
(Vite doesn't auto-open the browser).

The runtime-injected window.RUNTIME_REACT_APP_* globals (set by
nginx-start/start.sh at container startup) are deliberately untouched —
they live outside the build and are how prod environments override
host/realm/client without rebuilding.
PUBLIC_URL was a CRA build-time placeholder. Vite serves the public
directory at the URL root, so absolute paths like /images/... and the
default browser-history basename ('/') are equivalent.
CRA is fully replaced. Drops:
- react-scripts dep
- src/setupProxy.js (proxy now lives in vite.config.js server.proxy)
- eslintConfig.extends="react-app" (CRA-specific preset)
- overrides.autoprefixer (transitive CRA pin, no effect once webpack chain is gone)
- "test" and "eject" scripts (no test infra; nothing to eject from)

The "start" script is kept (mapped to "vite") so `npm start` keeps
working for anyone wired to the CRA convention. Adds "preview" for
testing the production build locally. The Dockerfile keeps invoking
`npm run build` unchanged.
Was pinned to v10.15.2 (2019), four LTS lines behind. Node 18 reached
EOL in April 2025 and Node 20 in April 2026, so anything older than 22
is unsupported. Going to 24 (current active LTS, supported until April
2028) to match local dev and the planned d3d940-tools/node ImageStream
update.
Result of `npm install` against the rewritten package.json. Tree size
drops from CRA's webpack/jest sprawl to 276 packages. Audit reports
10 vulns (3 moderate, 7 high), down from 72 in pre-upgrade-log.txt;
the bulk of CRA-only transitive vulns are already gone. Remaining
vulns will be cleaned up in chunks B/E.
CRA was lenient about file extensions and accepted JSX inside .js files;
the codebase relies on this in ~50 components. Vite's defaults are
stricter: esbuild's dep scanner picks a loader from the extension and
fails on JSX in .js, and the React plugin only transforms .jsx by
default.

Two-part fix:
- plugins: [react({ include: /\.(js|jsx)$/ })] — the React plugin's
  Babel transform now runs on .js files too, so HMR works.
- optimizeDeps.esbuildOptions.loader = { '.js': 'jsx' } — the dep
  pre-bundler scans .js files as JSX, unblocking startup.

A future cleanup could rename JSX-bearing .js files to .jsx, but that's
out of scope for the migration.
The earlier dev-mode fix only patched optimizeDeps' esbuild scanner.
Production builds use Rollup, where the React plugin's babel transform
wasn't reaching .js files in time for vite:build-import-analysis. Adding
esbuild.loader='jsx' with include=src/**/*.jsx? makes Vite's esbuild
transform run on .js files there too, producing valid JS before
import-analysis sees it.

Also reverts the redundant include override on react() — its default
filter (/\.[jt]sx?$/) already matches .js files.
The leading ~ was a webpack/sass-loader convention that resolved bare
specifiers from node_modules. Vite's sass integration uses standard
module resolution, so the unprefixed path is what works. Without this
change, sass errors with "Can't find stylesheet to import."
The MyriadWebPro font files moved from src/fonts/ (committed earlier)
to public/fonts/ so they are served as plain static assets — same
pattern as public/images/. The SCSS \$bcgov-font-path now points at the
absolute /fonts/ URL instead of a relative ../../fonts/ path.

Without this, vite build couldn't resolve the relative font references
through Sass's variable interpolation and would emit them unchanged,
producing 404s at runtime.
…piAccess

The Async Clipboard API (navigator.clipboard.writeText) is supported by
every browser we still target (IE11 was dropped earlier in this chunk).
Both copy buttons now use a Reactstrap Button that awaits writeText and
fires the existing toast on success — same UX, no extra dep.
…ubmission detail

Same swap as ApiAccess: Reactstrap Button + navigator.clipboard.writeText.
The "Copy errors to clipboard" action in the submission-detail modal now
uses the native API instead of react-clipboard.js.
Both consumers were migrated in earlier commits.
Replacement for the abandoned react-dates. Peer-deps React 16-19, so
compatible with the current React 16 baseline. Lock file is regenerated
at the end of this chunk.
… SingleDateField

react-datepicker uses native Date objects rather than moment. The
wrapper translates at the boundary so callers (Formik values stored as
moment) don't need to change. The isOutsideRange (moment) prop is
adapted to react-datepicker's filterDate (Date) by inverting the
predicate and converting back to moment for the caller's logic.

UX deltas vs react-dates:
- Date format string syntax changes ('YYYY-MM-DD' moment -> 'yyyy-MM-dd'
  date-fns).
- The "default input icon" and explicit clear button are replaced by
  react-datepicker's built-in clearable affordance (isClearable).
- The "focused" class wrapper is dropped — react-datepicker has its own
  popover/focus styling.
… DeleteButton

Same translation pattern as SingleDateField — moment <-> Date at the
picker boundary, drop the manual focus-state tracking. Local component
state (not Formik) so no schema changes required.
… fields in DateRangeField

react-datepicker doesn't have a unified two-field range picker, but its
selectsStart / selectsEnd props on two separate pickers preserve the
two-input UX from before (Date From / Date To). The pickers share a
range view via startDate/endDate, and the second picker's minDate is
bound to the first so the user can't pick an end before the start.

Validation surface unchanged: still uses Formik's errors[fromName] ||
errors[toName] and renders FormFeedback. Drops the local "touched"
tracking and visual focusedInput class — react-datepicker handles its
own focus styling, and submitCount alone is enough to gate the error
display once Formik has been submitted.
…WorkReportingSubmissions

The inline submission-search range filter was the last react-dates
consumer. Same selectsStart/selectsEnd two-picker pattern as
DateRangeField, but binding to local React state and triggering the
existing handleDateChanged so search results refresh on every change.

The startDateLimit + future-date guard (was isOutsideRange) is rewritten
as filterDate, with moment(date) wrapping to keep the existing date
math.
All five react-dates consumers were migrated in earlier commits. This
finishes the removal:
- App.js drops react-dates/initialize and the bundled CSS, replaces
  with react-datepicker/dist/react-datepicker.css.
- _datepicker.scss is rewritten from 136 lines of react-dates DOM
  styling to a minimal react-datepicker theme that preserves the
  primary/info color scheme for selected days and ranges.
- react-dates removed from package.json.
The original package was deprecated and explicitly redirected to
@redux-devtools/extension (npm warned about this on every install).
The /developmentOnly subpath and composeWithDevTools API are unchanged,
so store.js needs only the import path updated.
…velopmentOnly

The new @redux-devtools/extension@3.x doesn't expose a top-level
/developmentOnly export like the legacy redux-devtools-extension did;
the actual file is at lib/esm/developmentOnly.js and the package.json
has no exports map to alias it. Pointing the import directly at the
ESM path so Rollup can resolve it.
Net change from npm install:
- removed 74 packages (react-dates and its airbnb-prop-types/moment-
  range tree, react-clipboard.js, redux-devtools-extension)
- added 13 packages (react-datepicker + date-fns, @redux-devtools/
  extension)
- audit: 9 vulnerabilities (down from 10)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Comment thread .pipeline/.nvmrc Outdated
@@ -1 +1 @@
v10.15.2 No newline at end of file
24
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be 24 or 25?

We can’t have 15 due to compliance issues

Signed-off-by: Ionwyn Sean <ionwynsean@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants