Skip to content

Migrate d3_graph_generator from react-scripts (CRA) to Vite#112

Merged
dduugg merged 1 commit into
mainfrom
migrate-off-react-scripts
Jul 24, 2026
Merged

Migrate d3_graph_generator from react-scripts (CRA) to Vite#112
dduugg merged 1 commit into
mainfrom
migrate-off-react-scripts

Conversation

@dduugg

@dduugg dduugg commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Create React App is officially deprecated upstream — facebook/create-react-app's README now says "Create React App... is now in long-term stasis... we do not recommend starting production apps based on Create React App" — and react-scripts hasn't been released since April 2022. Its frozen webpack/babel/eslint toolchain is the entire reason d3_graph_generator kept accumulating Dependabot alerts on packages several levels deep in the tree (postcss, webpack-dev-server, minimatch, js-yaml, ajv, ...) that Dependabot can't bump directly, and that needed hand-maintained yarn resolutions overrides to patch (see #111).

This replaces react-scripts with Vite, removing that entire dependency subtree outright instead of continuing to patch it package-by-package.

Verified impact (measured against an actual install of the pre-migration commit, not estimated):

  • node_modules: 848 packages → 59
  • yarn.lock: 9,791 lines → 620
  • yarn audit: 199 vulnerabilities (2 critical / 125 high / 56 moderate / 16 low) → 0

Changes

  • package.json: drop react-scripts and its transitive baggage, plus @observablehq/stdlib, web-vitals, and @testing-library/* (all confirmed unused — no test files exist, no reportWebVitals call, no stdlib import anywhere in src/). Add vite + @vitejs/plugin-react. The eslintConfig/browserslist blocks are removed since they configured react-scripts' bundled tooling specifically.
  • vite.config.js (new): configures the React plugin, keeps the dev server on port 3000 (matching the documented workflow) and build output in build/ (matching the existing .gitignore entry).
  • index.html: moved from public/ to the project root per Vite convention. Dropped the stale, insecure http://d3js.org/d3.v3.min.js CDN script tag — the app only ever uses the npm-installed d3@7 via ESM imports (import * as d3 from "d3" in buildGraph.js), so this was dead, unused, mixed-content markup, not a functional dependency. Replaced %PUBLIC_URL% templating with root-relative paths and added the module entry script tag.
  • src/index.jssrc/index.jsx: renamed so esbuild's default JSX loader picks it up (it's the only source file with JSX in a .js extension; the other components were already .jsx). No content changes — confirmed byte-identical aside from the rename.
  • README.md: yarn startyarn install (first time) + yarn dev.

No application source files (App.jsx, ForceGraph.jsx, NodeDetails.jsx, buildGraph.js, index.css) were touched. d3_graph_generator has no coupling to the rest of the Ruby gem or to CI — nothing else in the repo references its build output, filenames, or manifest.

Test plan

Verified independently (fresh clones, not just re-running my own working directory):

  • yarn install — zero errors, zero peer-dependency warnings (the old CRA tree had several)
  • yarn build — succeeds in ~280ms, emits build/index.html + hashed JS/CSS assets + copied public/ assets
  • yarn preview — served index.html, the JS bundle, the CSS bundle, and /manifest.json, all HTTP 200 with real (non-empty, non-error) content
  • yarn dev — serves on port 3000 as configured/documented, / and /src/index.jsx both HTTP 200
  • Diff-reviewed for regressions: no leftover CRA references anywhere in the tree, dropped dependencies re-confirmed unused by grep (not just trusted), index.html changes confirmed semantically equivalent to the original
  • Merge and have a human click around the actual graph in a browser (ruby parse_packwerk_integration.rb against a real repo, then yarn dev) — nothing in this migration should change runtime behavior, but I don't have a way to visually confirm the rendered force graph from this environment

Create React App is officially deprecated upstream (facebook/create-react-app
README: "now in long-term stasis... we do not recommend starting production
apps based on Create React App") and react-scripts hasn't been released
since April 2022. Its frozen webpack/babel/eslint toolchain is the entire
reason d3_graph_generator kept accumulating Dependabot alerts on packages
several levels deep in the tree (postcss, webpack-dev-server, minimatch,
js-yaml, ajv, ...) that Dependabot can't bump directly and that needed
hand-maintained yarn `resolutions` overrides to patch.

Replacing it with Vite removes that entire dependency subtree outright
(node_modules: ~800+ packages -> 59; yarn.lock: ~2000 -> 620 lines) instead
of continuing to patch it package-by-package.

Changes:
- package.json: drop react-scripts and its transitive baggage, plus
  @observablehq/stdlib, web-vitals, and @testing-library/* (all confirmed
  unused - no test files exist, no reportWebVitals call, no stdlib import).
  Add vite + @vitejs/plugin-react. eslintConfig/browserslist blocks removed
  since they configured react-scripts' bundled tooling specifically.
- vite.config.js: new, configures the React plugin, keeps dev server on
  port 3000 (matching the documented workflow) and build output in
  `build/` (matching the existing .gitignore entry).
- index.html: moved from public/ to the project root per Vite convention.
  Dropped the stale, insecure `http://d3js.org/d3.v3.min.js` CDN script tag
  - the app only ever uses the npm-installed d3@7 via ESM imports, so this
    was dead, unused, mixed-content markup. Replaced %PUBLIC_URL% templating
    with root-relative paths and added the module entry script tag.
- src/index.js -> src/index.jsx: renamed so esbuild's default JSX loader
  picks it up (it's the only source file with JSX in a .js extension; the
  other components were already .jsx). No content changes.

Verified locally: `yarn install` (zero peer-dependency warnings, versus
several with react-scripts), `yarn build`, and both `yarn dev` and
`yarn preview` actually serving working HTML/JS/CSS (curled and checked
response codes, not just that the build produced files).
@dduugg
dduugg requested a review from a team as a code owner July 24, 2026 23:43
@github-project-automation github-project-automation Bot moved this to Triage in Modularity Jul 24, 2026
@dduugg
dduugg merged commit f0343c6 into main Jul 24, 2026
11 checks passed
@dduugg
dduugg deleted the migrate-off-react-scripts branch July 24, 2026 23:52
@github-project-automation github-project-automation Bot moved this from Triage to Done in Modularity Jul 24, 2026
dduugg added a commit that referenced this pull request Jul 25, 2026
* Fix missing-workflow-permissions alerts and integrate zizmor

Resolves 6 of the 7 open code scanning alerts
(https://github.com/rubyatscale/visualize_packs/security/code-scanning),
all actions/missing-workflow-permissions findings on workflows that had
no explicit permissions block and so defaulted to the repository's token
permissions:

- ci.yml: root-level `contents: read` (checkout + bundle exec only,
  across all three jobs)
- cd.yml: `contents: write` on the shared-config caller job - the called
  reusable workflow pushes a release tag (discourse/publish-rubygems-action)
  and creates a GitHub release (`gh release create`), both of which need
  contents:write
- stale.yml: `issues: write` + `pull-requests: write` - required by
  actions/stale to label/close stale issues and PRs
- triage.yml: `issues: write` - the called reusable workflow's own
  `label_issues` job requires this from the caller

The 7th alert (js/functionality-from-untrusted-source, the insecure
`http://d3js.org/d3.v3.min.js` CDN script tag in
d3_graph_generator/public/index.html) is already fixed on the open
Vite migration branch (#112) via removing that dead script tag entirely;
it isn't duplicated here since that PR deletes the file this alert
points at.

Also adds .github/workflows/zizmor.yml, copied from shared-config's
existing zizmor integration (the org's canonical pattern - this is the
first repo to adopt it). Running it locally against this repo's own
workflows surfaced additional real findings beyond CodeQL's actions
coverage, all fixed here so the new job starts green instead of red:

- unpinned `actions/checkout@v4` / `ruby/setup-ruby@v1` in ci.yml -
  pinned to SHA (matching the convention already used in codeql.yml)
- missing `persist-credentials: false` on checkout steps in ci.yml and
  codeql.yml
- stale/incorrect version comments on already-pinned SHAs in ci.yml,
  codeql.yml, and the copied zizmor.yml - e.g. a SHA commented "# v6"
  that's actually tagged v7.0.0 today (floating major tags move), and
  "# v3.37.3" on a SHA that's actually v4.37.3 (a leftover from an
  earlier find-and-replace pass across the org). Caught by zizmor's
  ref-version-mismatch audit in online mode (--gh-token), not offline.
- three findings suppressed with `# zizmor: ignore[...]` comments for
  patterns that are deliberate, org-wide conventions rather than bugs:
  workflow_run-triggered CD (dangerous-triggers), unpinned @main
  references to shared-config's own reusable workflows (unpinned-uses -
  pinning these would defeat the point of centralizing them, since
  shared-config updates wouldn't propagate), and secrets: inherit on
  the cd.yml caller (secrets-inherit - matches shared-config's own
  precedent for this exact pattern).

Verified with `zizmor .github/workflows/` locally, both offline and
with --gh-token (online mode catches the ref-version-mismatch findings
that offline mode misses): 0 findings, all ignores/suppressions
resolving correctly.

* Group GitHub Actions dependabot updates into a single monthly PR

Matches the existing bundler grouping in this same file: one PR a
month for all github-actions bumps together, instead of a separate PR
per action. Especially relevant now that this PR pins several actions
to a SHA (actions/checkout, ruby/setup-ruby, github/codeql-action,
zizmorcore/zizmor-action) for the first time, which is what makes them
trackable by dependabot's github-actions ecosystem in the first place.

* Add cooldown to dependabot config, fixing zizmor's new alert

The new zizmor.yml added earlier in this PR caught its own
dependabot-cooldown finding on the github-actions entry this PR just
added (alert #11), and the same check flags the pre-existing bundler
entry too - it just never ran against this repo before since zizmor.yml
didn't exist until this PR. Fixed both with zizmor --fix=safe, matching
shared-config's own dependabot.yml convention (cooldown: default-days: 7).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant