Skip to content

Conversation

pyanderson
Copy link
Contributor

@pyanderson pyanderson commented Oct 17, 2025

Description

Migrates the frontend to Node.js v22, updates all runtime and dev dependencies, standardizes linting and formatting, unifies code configuration, and adjusts build/CI pipelines.

Also includes a small refactor of the API client layer.

Main changes:

  • Node/Build
    • Bumps Node requirement to v22 in package.json, Dockerfile, GitHub workflows, and CI matrix.
    • Updates CI to use pnpm and Node 22.
  • Code quality
    • Replaces legacy ESLint/Prettier setups with eslint.config.mjs and .prettierrc.js.
    • Adds new scripts: lint:fix and format in package.json.
    • Normalizes style to single quotes and unified import path aliases.
  • API/client
    • Refactors imports and loader logic to use the openapi-ts Axios plugin.
    • Renames fetch* functions to match the new naming convention (breaking for direct imports).
  • Project infrastructure
    • Tweaks webpack.config.js, jest.config.js, and various loaders for consistent quoting and formatting.
  • Tests
    • Updates test suites to reflect renamed API functions and unified code style.

Motivation and Context

  • Keeps the project aligned with modern Node 22 features and performance improvements.
  • Reduces security and deprecation warnings by updating dependencies.
  • Ensures a consistent code style across the repository for better collaboration.
  • Improves developer experience (DX) with unified lint/format scripts.
  • Keeps the CI pipeline fast and up-to-date using pnpm and proper caching.

Screenshots (if appropriate):

N/A

Steps to reproduce (if appropriate):

  • Create a new project using this branch as the template:
django-admin startproject new_styling --extension py,json,yml,yaml,toml --name Dockerfile,README.md,.env.example,.gitignore,Makefile,.npmrc --template=https://github.com/vintasoftware/django-react-boilerplate/archive/refs/heads/upgrade-node-and-other-libs.zip

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires documentation updates.
  • I have updated the documentation accordingly.
  • My change requires dependencies updates.
  • I have updated the dependencies accordingly.

Summary by Sourcery

Migrate the frontend to Node 22, bump all dependencies, standardize linting and formatting, unify code style, update build and CI configurations, and refactor API client usage.

Enhancements:

  • Upgrade runtime and dev dependencies to latest versions across the frontend
  • Add lint:fix and format scripts to the package.json for code consistency
  • Replace legacy ESLint and Prettier setups with a unified eslint.config.mjs and .prettierrc.js
  • Refactor API imports and loader logic to use the openapi-ts Axios plugin and rename fetch functions
  • Normalize code style to single quotes and update import path aliases project-wide

Build:

  • Bump Node engine requirement to v22 in package.json, Dockerfile, GitHub workflows, and CI matrix

CI:

  • Update CI workflows and pre-commit hooks to use pnpm commands and Node 22

Tests:

  • Adjust test suites to use renamed API functions and updated code style

Chores:

  • Tweak webpack.config.js, jest.config.js, and various loader files for consistent quoting and formatting

Summary by Sourcery

Migrate frontend to Node.js v22, refresh all dependencies, unify lint/format configs and code style, refactor API client to use openapi-ts/axios plugin, and update build and CI pipelines accordingly.

Enhancements:

  • Upgrade Node requirement to >=22 and update all runtime and dev dependencies to their latest versions
  • Replace legacy ESLint and Prettier setups with centralized eslint.config.mjs and .prettierrc.js and add lint:fix and format scripts in package.json
  • Standardize code style across the project (single quotes, unified import aliases, and consistent quoting)
  • Refactor API client layer to use openapi-ts Axios plugin with renamed fetch functions and updated loader logic

Build:

  • Bump Node engine to v22 in package.json, Dockerfile, and project configuration
  • Adjust webpack configuration for consistent module resolution and output naming

CI:

  • Migrate GitHub workflows, pre-commit hooks, and CI matrix to Node 22 and pnpm
  • Update Jest and SWC settings in CI to match new code style and dependencies

Tests:

  • Update test suites and Jest config to reflect renamed API functions and unified code style

@pyanderson pyanderson self-assigned this Oct 17, 2025
@pyanderson pyanderson added enhancement dependencies Pull requests that update a dependency file labels Oct 17, 2025
@sourcery-ai
Copy link

sourcery-ai bot commented Oct 17, 2025

Reviewer's Guide

This PR migrates the frontend to Node.js v22 and pnpm, refreshes all runtime and dev dependencies, introduces a unified lint/format setup, refactors the API client layer to use openapi-ts (Axios plugin), and normalizes code style and CI/build/test configurations across the project.

Sequence diagram for updated usersLoader API interaction

sequenceDiagram
  participant UsersPage
  participant usersLoader
  participant API

  UsersPage->>usersLoader: Request user list (with limit/offset)
  usersLoader->>API: Call usersList({query, throwOnError})
  API-->>usersLoader: Respond with { data: PaginatedUserList }
  usersLoader-->>UsersPage: Return data.results
  Note over usersLoader,API: On 401/403 error, usersLoader redirects to login
Loading

Class diagram for refactored API client usage

classDiagram
  class RestService {
    <<deprecated>>
    +restRestCheckRetrieve()
    +usersList()
  }
  class restRestCheckRetrieve {
    <<function>>
  }
  class usersList {
    <<function>>
    +queryLimit: number
    +queryOffset: number
    +throwOnError: boolean
  }
  RestService --|> restRestCheckRetrieve : replaced by
  RestService --|> usersList : replaced by

  class PaginatedUserList {
    +results: User[]
    +count: number
  }
  class User {
    +id: number
    +username: string
    +...other fields
  }
  PaginatedUserList "1" -- "*" User : contains
Loading

File-Level Changes

Change Details Files
Upgrade Node engine and CI build environment
  • Bump Node.js requirement to v22 across package.json, Dockerfile, GitHub workflows, and CI matrix
  • Switch CI and pre-commit hooks to pnpm commands and remove legacy dedupe step
package.json
frontend/Dockerfile
.github/workflows/shared-build/action.yml
proj_main.yml
.pre-commit-config.yaml
Bulk upgrade of runtime and development dependencies
  • Update versions for all production dependencies to latest compatible releases
  • Update versions for all devDependencies including build, test, and tooling libraries
package.json
Introduce unified linting and formatting configuration
  • Replace legacy ESLint/Prettier setups with a single eslint.config.mjs and .prettierrc.js
  • Add lint:fix and format scripts to package.json and update pre-commit hooks
eslint.config.mjs
.prettierrc.js
package.json
.pre-commit-config.yaml
Refactor API client to use openapi-ts generated Axios plugin
  • Configure openapi-ts with the Axios plugin in openapi-ts.config.ts
  • Rename RestService calls to generated functions (restRestCheckRetrieve, usersList)
  • Adjust loader error handling to use AxiosError in usersLoader
openapi-ts.config.ts
frontend/js/pages/Home.tsx
frontend/js/loaders/users.ts
frontend/js/routes/index.ts
frontend/js/pages/Users.tsx
Normalize code style and import paths project-wide
  • Convert all string literals to single quotes and unify import alias ‘@’
  • Standardize quoting and formatting in webpack.config.js, jest.config.js, tsconfig.json, types, assets definitions, utils, components, routes, and CSS
webpack.config.js
jest.config.js
tsconfig.json
frontend/js/pages/Home.tsx
frontend/js/components/TopNav.tsx
frontend/js/types/assets.d.ts
frontend/assets/images/index.d.ts
frontend/js/utils/index.ts
frontend/js/index.tsx
frontend/js/routes/index.ts
frontend/css/style.css
Tweak build and test pipeline configurations
  • Adjust webpack.config.js plugins, resolver, output, and loader rules for consistency
  • Update jest.config.js moduleNameMapper, transform settings, and ignore patterns
  • Include openapi-ts.config.ts in tsconfig.json and remove stale ESLint config files
webpack.config.js
jest.config.js
tsconfig.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@pyanderson pyanderson changed the title [WIP] Migrate Node and all frontend dependencies [WIP] Migrate Node and update all frontend dependencies Oct 17, 2025
@pyanderson pyanderson changed the title [WIP] Migrate Node and update all frontend dependencies Migrate Node and update all frontend dependencies Oct 20, 2025
@pyanderson pyanderson marked this pull request as ready for review October 20, 2025 13:22
@pyanderson pyanderson requested a review from fjsj October 20, 2025 13:22
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • The catch block in usersLoader checks error.status on AxiosError, but AxiosError stores the HTTP status on error.response.status—update the code to use error.response?.status.
  • You’ve introduced the '@' import alias in webpack and Jest but didn’t add matching compilerOptions.paths in tsconfig.json, so the TypeScript compiler won’t resolve those modules correctly—please sync your tsconfig.json paths with your alias.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The catch block in usersLoader checks error.status on AxiosError, but AxiosError stores the HTTP status on error.response.status—update the code to use error.response?.status.
- You’ve introduced the '@' import alias in webpack and Jest but didn’t add matching compilerOptions.paths in tsconfig.json, so the TypeScript compiler won’t resolve those modules correctly—please sync your tsconfig.json paths with your alias.

## Individual Comments

### Comment 1
<location> `frontend/js/loaders/users.ts:17` </location>
<code_context>
-      error instanceof ApiError &&
-      (error?.status === 401 || error?.status === 403)
-    ) {
+    if (error instanceof AxiosError && (error?.status === 401 || error?.status === 403)) {
       const url = new URL(request.url);
       const next = url.pathname + url.search + url.hash;
</code_context>

<issue_to_address>
**issue (bug_risk):** Using error?.status on AxiosError may not work as AxiosError uses 'response.status'.

Update the condition to use 'error.response?.status' instead for accurate status code checking.
</issue_to_address>

### Comment 2
<location> `frontend/js/loaders/users.ts:20` </location>
<code_context>
+    if (error instanceof AxiosError && (error?.status === 401 || error?.status === 403)) {
       const url = new URL(request.url);
       const next = url.pathname + url.search + url.hash;
       throw redirectDocument(`/admin/login/?next=${encodeURIComponent(next)}`);
</code_context>

<issue_to_address>
**suggestion:** Redirecting on 401/403 is appropriate, but other error types are not handled.

Please add handling for other error types, such as network failures and server errors (e.g., 500s), to improve user feedback and resilience.
</issue_to_address>

### Comment 3
<location> `frontend/js/pages/__tests__/Home.spec.tsx:13-17` </location>
<code_context>
+  restRestCheckRetrieve: jest.fn(),
 }));

-describe("Home", () => {
+describe('Home', () => {
   beforeEach(() => {
-    (RestService.restRestCheckRetrieve as jest.Mock).mockResolvedValue({
-      message: "Test Result",
+    (restRestCheckRetrieve as jest.Mock).mockResolvedValue({
+      data: {
+        message: 'Test Result',
+      },
     });
   });

</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test for error handling in the Home page.

Please add a test that simulates an API error and checks that the Home page displays an appropriate error message or handles the failure without crashing.

Suggested implementation:

```typescript
describe('Home', () => {
  beforeEach(() => {
    (restRestCheckRetrieve as jest.Mock).mockResolvedValue({
      data: {
        message: 'Test Result',
      },
    });
  });

  it('displays an error message when the API call fails', async () => {
    (restRestCheckRetrieve as jest.Mock).mockRejectedValue(new Error('API Error'));

    // Render the Home component
    const { findByText } = render(<Home />);

    // Assert that the error message is displayed
    expect(await findByText(/error/i)).toBeInTheDocument();
  });

```

- If your Home component does not currently display an error message, you will need to update it to do so when the API call fails (e.g., by setting an error state and rendering an error message).
- You may need to import `render` and any other required testing utilities from your test library (e.g., `@testing-library/react`).
</issue_to_address>

### Comment 4
<location> `eslint.config.mjs:18` </location>
<code_context>
+import unicornPlugin from "eslint-plugin-unicorn";
+import jestPlugin from "eslint-plugin-jest";
+
+export default defineConfig([
+  // Base JS rules, with browser + node globals
+  {
</code_context>

<issue_to_address>
**issue (complexity):** Consider consolidating the multiple config overrides into a single, top-level ESLint config using 'extends' and 'env' for improved maintainability.

Here’s one way to collapse all of that ceremony into a single, maintainable config that still gives you all the same rules/plugins/globals:

```js
// .eslintrc.js
import { defineConfig } from "eslint/config";

const COMMON_ENV = {
  browser: true,
  node:    true,
  jest:    true,
};

export default defineConfig({
  root:           true,
  env:            COMMON_ENV,
  ignorePatterns: ["node_modules/", "dist/", "build/", "frontend/js/api/", "openapi-ts.config.ts"],

  parser:       "@typescript-eslint/parser",
  parserOptions: {
    project:           "./tsconfig.json",
    tsconfigRootDir:   __dirname,
    ecmaVersion:       "latest",
    sourceType:        "module",
    ecmaFeatures:      { jsx: true },
  },

  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",     // TS rules
    "plugin:react/recommended",                  // React rules
    "plugin:react-hooks/recommended",
    "plugin:import/recommended",
    "plugin:jsx-a11y/recommended",
    "plugin:promise/recommended",
    "plugin:sonarjs/recommended",
    "plugin:unicorn/recommended",
    "plugin:jest/recommended",
  ],

  settings: {
    react: { version: "detect" },
  },

  rules: {
    // TS tweaks
    "no-undef":                      "off",
    "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],

    // React tweaks
    "react/prop-types":              "off",
    "react/react-in-jsx-scope":      "off",

    // import/order
    "import/order": [
      "warn",
      {
        groups:           [
          "builtin",
          "external",
          "internal",
          "parent",
          "sibling",
          "index",
          "object",
          "type",
        ],
        "newlines-between": "always",
        alphabetize:       { order: "asc", caseInsensitive: true },
      },
    ],

    // other
    "unicorn/prefer-module":        "off",
  },
});
```

What changed?

1. Switched to a single top-level config instead of four almost-identical overrides.  
2. Replaced all those `import`+`globals` spreads with a simple `env: { browser, node, jest }`.  
3. Dropped manual plugin registrations and rule-by-rule copies in favor of `extends: […]` bundles (TypeScript, React, import, jsx-a11y, promise, sonarjs, unicorn, jest).  

Everything you had is still in place, but now it’s under 50 lines instead of 200+.
</issue_to_address>

### Comment 5
<location> `frontend/js/pages/Home.tsx:12-14` </location>
<code_context>

</code_context>

<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/avoid-function-declarations-in-blocks))

<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@pyanderson pyanderson merged commit 5be93cd into main Oct 20, 2025
3 checks passed
@pyanderson pyanderson deleted the upgrade-node-and-other-libs branch October 20, 2025 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update all frontend dependencies to latest (React 19, Jest 30, etc.) Migrate Node.js from 18.x to 22.x (current LTS)

2 participants