Skip to content

Migrate to modern ESM dependencies#3311

Draft
RichDom2185 wants to merge 17 commits intomasterfrom
esm-modern
Draft

Migrate to modern ESM dependencies#3311
RichDom2185 wants to merge 17 commits intomasterfrom
esm-modern

Conversation

@RichDom2185
Copy link
Copy Markdown
Member

Description

  • es-toolkit is a mostly drop-in, faster, smaller replacement of lodash.
  • clsx is smaller, faster, and supports more features compared to classnames

Type of change

  • 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 not work as expected)
  • This change requires a documentation update
  • Code quality improvements

How to test

Checklist

  • I have tested this code
  • I have updated the documentation

@RichDom2185 RichDom2185 enabled auto-merge (squash) August 16, 2025 14:51
@RichDom2185 RichDom2185 marked this pull request as draft August 16, 2025 15:14
auto-merge was automatically disabled August 16, 2025 15:14

Pull request was converted to draft

@RichDom2185 RichDom2185 self-assigned this Aug 16, 2025
@RichDom2185 RichDom2185 marked this pull request as ready for review March 16, 2026 17:25
@RichDom2185 RichDom2185 requested review from Copilot and sayomaki March 16, 2026 17:25
Comment on lines +94 to 95
const updatedFetchOptions = cloneDeep(fetchOptions);
updatedFetchOptions.headers.set('Authorization', `Bearer ${newTokens.accessToken}`);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The cloneDeep function from es-toolkit doesn't support Headers objects, causing the token refresh flow to fail and log the user out when it tries to call .set().
Severity: HIGH

Suggested Fix

Manually handle the cloning of the Headers object instead of relying on cloneDeep. Create a new Headers instance from the old one before cloning the rest of the fetchOptions object. For example: const newHeaders = new Headers(fetchOptions.headers); const updatedFetchOptions = { ...cloneDeep(fetchOptions), headers: newHeaders };

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/commons/utils/RequestHelper.tsx#L94-L95

Potential issue: The migration from lodash to `es-toolkit`'s `cloneDeep` function
introduces a runtime error during the authentication token refresh process. When a token
expires and needs refreshing, the `cloneDeep` function is called on fetch options
containing a `Headers` Web API object. The `es-toolkit` implementation does not properly
clone this object, instead converting it to a plain JavaScript object. The subsequent
attempt to call `updatedFetchOptions.headers.set(...)` fails with a `TypeError`, as the
plain object lacks the `.set` method. This error is caught and incorrectly handled as a
refresh failure, causing the user to be logged out.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the frontend away from legacy CommonJS utilities (lodash, classnames) to modern ESM-friendly, smaller alternatives (es-toolkit, clsx), updating imports across the UI and saga/utils layers and adjusting dependency/resolution wiring.

Changes:

  • Replace classnames usages with clsx throughout the React UI.
  • Replace lodash utilities with es-toolkit / es-toolkit/compat equivalents across pages, commons utilities, features, and sagas.
  • Update package.json and yarn.lock (including a resolutions alias for classnamesclsx).

Reviewed changes

Copilot reviewed 84 out of 85 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
yarn.lock Updates lockfile for new deps (es-toolkit, clsx) and removals (lodash, classnames, @types/lodash).
package.json Swaps deps to clsx + es-toolkit, removes lodash/classnames, adds resolutions alias.
src/pages/stories/Story.tsx Replace classnames with clsx.
src/pages/sourcecast/Sourcecast.tsx Replace classnames with clsx.
src/pages/sicp/subcomponents/SicpToc.tsx Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/pages/sicp/Sicp.tsx Replace classnames with clsx.
src/pages/playground/Playground.tsx Replace classnames with clsx; replace lodash/isEqual with es-toolkit/isEqual.
src/pages/notFound/NotFound.tsx Replace classnames with clsx.
src/pages/missionControl/MissionControl.tsx Replace classnames with clsx.
src/pages/login/NusLogin.tsx Replace classnames with clsx.
src/pages/login/LoginVscodeCallback.tsx Replace classnames with clsx.
src/pages/login/LoginPage.tsx Replace classnames with clsx.
src/pages/login/LoginCallback.tsx Replace classnames with clsx.
src/pages/githubCallback/GitHubCallback.tsx Replace classnames with clsx.
src/pages/createStore.ts Replace lodash/throttle with es-toolkit/throttle.
src/pages/academy/sourcereel/Sourcereel.tsx Replace classnames with clsx.
src/pages/academy/groundControl/subcomponents/GroundControlDropzone.tsx Replace classnames with clsx.
src/pages/academy/grading/subcomponents/gradingSubmissionsTableUtils.tsx Replace classnames with clsx in ag-grid class props.
src/pages/academy/grading/subcomponents/GradingWorkspace.tsx Replace classnames with clsx.
src/pages/academy/grading/subcomponents/GradingSubmissionsTable.tsx Replace classnames with clsx; replace lodash/debounce with es-toolkit/debounce.
src/pages/academy/grading/subcomponents/GradingColumnCustomHeaders.tsx Replace classnames with clsx.
src/pages/academy/grading/subcomponents/GradingBadges.tsx Replace classnames with clsx.
src/pages/academy/gameSimulator/subcomponents/assetViewer/AssetViewerUtils.tsx Replace lodash/set with es-toolkit/compat/set.
src/pages/academy/gameSimulator/subcomponents/assetViewer/AssetViewer.tsx Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/pages/academy/dashboard/Dashboard.tsx Replace lodash/startCase with es-toolkit/startCase.
src/pages/academy/adminPanel/subcomponents/assessmentConfigPanel/AssessmentConfigPanel.tsx Replace lodash utils with es-toolkit equivalents.
src/pages/academy/adminPanel/subcomponents/AddUserPanel.tsx Replace lodash/uniqBy with es-toolkit/uniqBy.
src/pages/academy/adminPanel/subcomponents/AddStoriesUserPanel.tsx Replace lodash/uniqBy with es-toolkit/uniqBy.
src/pages/academy/academyRoutes.ts Replace lodash/memoize with es-toolkit/memoize.
src/pages/academy/Academy.tsx Replace classnames with clsx.
src/features/remoteExecution/RemoteExecutionDeviceDialog.tsx Replace classnames with clsx.
src/features/remoteExecution/PeripheralContainer.tsx Replace classnames with clsx.
src/features/gameSimulator/GameSimulatorService.ts Replace lodash/sortBy with es-toolkit/compat/sortBy.
src/features/game/utils/StyleUtils.ts Replace lodash helpers with es-toolkit / es-toolkit/compat.
src/features/game/save/GameSaveRequests.ts Replace lodash/isEmpty with es-toolkit/compat/isEmpty.
src/features/game/chapter/GameChapterHelpers.ts Replace lodash/sortBy with es-toolkit/compat/sortBy.
src/features/cseMachine/CseMachineUtils.ts Replace lodash helpers with es-toolkit / es-toolkit/compat.
src/commons/workspace/tests/WorkspaceReducer.test.ts Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/commons/utils/RequestHelper.tsx Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/commons/utils/MemoizeHelper.ts Replace lodash/isEqual with es-toolkit/isEqual.
src/commons/utils/JsSlangHelper.ts Replace lodash helpers with es-toolkit / es-toolkit/compat.
src/commons/sourceRecorder/SourceRecorderTable.tsx Replace lodash/sortBy with es-toolkit/compat/sortBy.
src/commons/sourceRecorder/SourceRecorderEditor.tsx Replace lodash/isEqual with es-toolkit/isEqual.
src/commons/sideContent/content/remoteExecution/SideContentRemoteExecution.tsx Replace classnames with clsx.
src/commons/sideContent/content/githubAssessments/SideContentEditableTestcaseCard.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentToneMatrix.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentTestcaseCard.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentSubstVisualizer.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentSessionManagement.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentResultCard.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentLeaderboardCard.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentDataVisualizer.tsx Replace classnames with clsx.
src/commons/sideContent/content/SideContentCseMachine.tsx Replace classnames with clsx; replace lodash/debounce with es-toolkit/debounce.
src/commons/sideContent/content/SideContentContestVoting.tsx Replace classnames with clsx.
src/commons/sideContent/SideContentHelper.ts Replace lodash runtime provider with es-toolkit/compat provider mapping.
src/commons/sideBar/SideBar.tsx Replace classnames with clsx.
src/commons/sagas/WorkspaceSaga/helpers/runTestCase.ts Replace lodash/random with es-toolkit/random.
src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts Replace lodash/pick with es-toolkit/pick.
src/commons/sagas/RemoteExecutionSaga.ts Replace lodash/pickBy with es-toolkit/compat/pickBy.
src/commons/sagas/BackendSaga.ts Replace lodash key transforms with es-toolkit / es-toolkit/compat.
src/commons/repl/ReplInput.tsx Replace classnames with clsx.
src/commons/repl/Repl.tsx Replace classnames with clsx.
src/commons/navigationBar/NavigationBar.tsx Replace classnames with clsx.
src/commons/mocks/StoreMocks.ts Replace lodash merge helpers with es-toolkit/compat equivalents.
src/commons/mobileWorkspace/mobileSideContent/MobileSideContent.tsx Replace classnames with clsx.
src/commons/grading/GradingText.tsx Replace classnames with clsx.
src/commons/gitHubOverlay/RepositoryDialog.tsx Replace classnames with clsx.
src/commons/gitHubOverlay/FileExplorerDialog.tsx Replace classnames with clsx.
src/commons/fileSystemView/FileSystemViewContextMenu.tsx Replace classnames with clsx.
src/commons/editor/tabs/EditorTab.tsx Replace classnames with clsx.
src/commons/editor/EditorContainer.tsx Replace lodash/pick with es-toolkit/pick usage.
src/commons/editingWorkspace/EditingWorkspace.tsx Replace classnames with clsx.
src/commons/dialogs/ConfirmDialog.tsx Replace classnames with clsx.
src/commons/controlBar/ControlBar.tsx Replace classnames with clsx.
src/commons/assessmentWorkspace/AssessmentWorkspace.tsx Replace classnames with clsx; replace lodash/isEqual with es-toolkit/isEqual.
src/commons/assessment/AssessmentOverviewCard.tsx Replace classnames with clsx.
src/commons/assessment/AssessmentNotFound.tsx Replace classnames with clsx.
src/commons/assessment/Assessment.tsx Replace lodash/sortBy with es-toolkit/sortBy.
src/commons/application/ApplicationWrapper.tsx Replace classnames with clsx.
src/commons/achievement/utils/AchievementInferencer.ts Replace lodash helpers with es-toolkit equivalents.
src/commons/achievement/control/goalEditor/EditableGoal.tsx Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/commons/achievement/control/achievementEditor/achievementSettings/EditablePrerequisiteUuids.tsx Replace lodash/without with es-toolkit/without.
src/commons/achievement/control/achievementEditor/achievementSettings/EditableGoalUuids.tsx Replace lodash/without with es-toolkit/without.
src/commons/achievement/control/achievementEditor/EditableCard.tsx Replace lodash/cloneDeep with es-toolkit/cloneDeep.
src/commons/Markdown.tsx Replace classnames with clsx.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

} from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';
import { sortBy } from 'lodash';
import { sortBy } from 'es-toolkit';
Comment on lines +14 to 16
import clsx from 'clsx';
import { debounce } from 'es-toolkit';
import { t } from 'i18next';
@RichDom2185 RichDom2185 marked this pull request as draft March 16, 2026 17:33
@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 23157220461

Details

  • 8 of 10 (80.0%) changed or added relevant lines in 7 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.002%) to 42.148%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/commons/assessment/AssessmentNotFound.tsx 0 1 0.0%
src/commons/navigationBar/NavigationBar.tsx 1 2 50.0%
Totals Coverage Status
Change from base Build 23155829026: 0.002%
Covered Lines: 5761
Relevant Lines: 12641

💛 - Coveralls

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