perf(frontend): migrate lodash imports to lodash-es for tree-shaking - #41511
Conversation
Replaces bare `import { x } from 'lodash'` with `from 'lodash-es'` across the
frontend (173 source files). lodash-es is an ES-module build that webpack
tree-shakes natively at the method level, so bundles include only the lodash
functions actually used.
This also removes the frontend's reliance on babel-plugin-lodash, which is
unmaintained and incompatible with Babel 8 (it calls the removed `path.hoist`
API). Native tree-shaking via lodash-es is the modern replacement and does not
require a build-time Babel plugin.
- Codemod is limited to named imports (`import { debounce } from 'lodash'`),
which map 1:1 to lodash-es. There were no default (`import _ from 'lodash'`)
or namespace (`import * as _`) imports, which lodash-es does not support.
- `lodash-es` added to the manifests of every workspace that imports it, plus
`@types/lodash-es` at the root. `lodash` is retained for the remaining
per-method `lodash/x` imports and transitive consumers.
- lodash-es is already covered by jest's transformIgnorePatterns.
Validated with the production webpack build, the Jest unit suite, and
`tsc --noEmit` (no type errors introduced; @types/lodash-es matches
@types/lodash).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review Agent Run #0e3b94
Actionable Suggestions - 1
-
superset-frontend/plugins/plugin-chart-cartodiagram/src/components/OlChartMap.tsx - 1
- Dead import statement · Line 27-27
Review Details
-
Files reviewed - 173 · Commit Range:
15648fa..15648fa- superset-frontend/packages/superset-core/src/theme/Theme.tsx
- superset-frontend/packages/superset-core/src/utils/isBlank.ts
- superset-frontend/packages/superset-ui-chart-controls/src/components/CertifiedIconWithTooltip.tsx
- superset-frontend/packages/superset-ui-chart-controls/src/operators/sortOperator.ts
- superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/sharedControls.tsx
- superset-frontend/packages/superset-ui-chart-controls/src/utils/getColorFormatters.ts
- superset-frontend/packages/superset-ui-chart-controls/test/operators/histogramOperator.test.ts
- superset-frontend/packages/superset-ui-core/src/color/CategoricalColorNamespace.ts
- superset-frontend/packages/superset-ui-core/src/components/DropdownButton/index.tsx
- superset-frontend/packages/superset-ui-core/src/components/DropdownContainer/DropdownContainer.stories.tsx
- superset-frontend/packages/superset-ui-core/src/components/InfoTooltip/index.tsx
- superset-frontend/packages/superset-ui-core/src/components/MetadataBar/MetadataBar.tsx
- superset-frontend/packages/superset-ui-core/src/components/Modal/Modal.tsx
- superset-frontend/packages/superset-ui-core/src/components/SafeMarkdown/SafeMarkdown.tsx
- superset-frontend/packages/superset-ui-core/src/components/Select/AsyncSelect.tsx
- superset-frontend/packages/superset-ui-core/src/components/Select/Select.tsx
- superset-frontend/packages/superset-ui-core/src/components/TableView/TableView.tsx
- superset-frontend/packages/superset-ui-core/src/connection/callApi/parseResponse.ts
- superset-frontend/packages/superset-ui-core/src/query/normalizeOrderBy.ts
- superset-frontend/packages/superset-ui-core/src/query/normalizeTimeColumn.ts
- superset-frontend/packages/superset-ui-core/src/time-comparison/fetchTimeRange.ts
- superset-frontend/packages/superset-ui-core/src/time-comparison/getTimeOffset.ts
- superset-frontend/packages/superset-ui-core/src/utils/convertKeysToCamelCase.ts
- superset-frontend/packages/superset-ui-core/src/utils/merge.ts
- superset-frontend/packages/superset-ui-core/test/components/SafeMarkdown.test.tsx
- superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Vis.ts
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTable/index.tsx
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTableChart.tsx
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/buildQuery.ts
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/controlPanel.tsx
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/transformProps.ts
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/utils/extent.ts
- superset-frontend/plugins/plugin-chart-ag-grid-table/src/utils/getInitialFilterModel.ts
- superset-frontend/plugins/plugin-chart-cartodiagram/src/components/OlChartMap.tsx
- superset-frontend/plugins/plugin-chart-cartodiagram/src/util/transformPropsUtil.ts
- superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/PopKPI.tsx
- superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/buildQuery.ts
- superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/controlPanel.ts
- superset-frontend/plugins/plugin-chart-echarts/src/BigNumber/BigNumberPeriodOverPeriod/useOverflowDetection.ts
- superset-frontend/plugins/plugin-chart-echarts/src/Gauge/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/src/Histogram/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/controlPanel.tsx
- superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/src/utils/annotation.ts
- superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts
- superset-frontend/plugins/plugin-chart-echarts/src/utils/themeOverrides.ts
- superset-frontend/plugins/plugin-chart-echarts/src/utils/treeBuilder.ts
- superset-frontend/plugins/plugin-chart-handlebars/src/components/Handlebars/HandlebarsViewer.tsx
- superset-frontend/plugins/plugin-chart-handlebars/src/consts.ts
- superset-frontend/plugins/plugin-chart-handlebars/src/plugin/controls/orderBy.tsx
- superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
- superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
- superset-frontend/plugins/plugin-chart-table/src/buildQuery.ts
- superset-frontend/plugins/plugin-chart-table/src/controlPanel.tsx
- superset-frontend/plugins/plugin-chart-table/src/transformProps.ts
- superset-frontend/plugins/plugin-chart-table/src/utils/extent.ts
- superset-frontend/plugins/plugin-chart-table/test/TableChart.test.tsx
- superset-frontend/plugins/plugin-chart-word-cloud/src/chart/WordCloud.tsx
- superset-frontend/plugins/plugin-chart-word-cloud/src/plugin/controls/ColorSchemeControl/index.tsx
- superset-frontend/plugins/preset-chart-deckgl/src/DeckGLContainer.tsx
- superset-frontend/plugins/preset-chart-deckgl/src/Multi/Multi.tsx
- superset-frontend/plugins/preset-chart-deckgl/src/factory.tsx
- superset-frontend/plugins/preset-chart-deckgl/src/utilities/HandlebarsRenderer.tsx
- superset-frontend/plugins/preset-chart-deckgl/src/utilities/TooltipTemplateControl.tsx
- superset-frontend/src/SqlLab/actions/sqlLab.ts
- superset-frontend/src/SqlLab/components/App/index.tsx
- superset-frontend/src/SqlLab/components/AppLayout/index.tsx
- superset-frontend/src/SqlLab/components/PopEditorTab/index.tsx
- superset-frontend/src/SqlLab/components/QueryAutoRefresh/index.tsx
- superset-frontend/src/SqlLab/components/QueryHistory/index.tsx
- superset-frontend/src/SqlLab/components/ResultSet/index.tsx
- superset-frontend/src/SqlLab/components/SaveDatasetModal/index.tsx
- superset-frontend/src/SqlLab/components/ShareSqlLabQuery/ShareSqlLabQuery.test.tsx
- superset-frontend/src/SqlLab/components/SqlEditor/index.tsx
- superset-frontend/src/SqlLab/components/TemplateParamsEditor/index.tsx
- superset-frontend/src/SqlLab/hooks/useQueryEditor/index.ts
- superset-frontend/src/SqlLab/middlewares/persistSqlLabStateEnhancer.ts
- superset-frontend/src/SqlLab/reducers/sqlLab.ts
- superset-frontend/src/SqlLab/utils/reduxStateToLocalStorageHelper.ts
- superset-frontend/src/components/AlteredSliceTag/index.tsx
- superset-frontend/src/components/Chart/ChartRenderer.tsx
- superset-frontend/src/components/Chart/DrillBy/DrillByModal.test.tsx
- superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
- superset-frontend/src/components/Chart/DrillDetail/utils.ts
- superset-frontend/src/components/Chart/chartReducer.ts
- superset-frontend/src/components/Chart/useDrillDetailMenuItems/index.tsx
- superset-frontend/src/components/Datasource/FoldersEditor/index.tsx
- superset-frontend/src/components/DynamicPlugins/index.tsx
- superset-frontend/src/components/ListView/Filters/CompactSelectPanel.tsx
- superset-frontend/src/components/ListView/utils.ts
- superset-frontend/src/dashboard/actions/dashboardState.ts
- superset-frontend/src/dashboard/actions/nativeFilters.ts
- superset-frontend/src/dashboard/components/ColorSchemeSelect.tsx
- superset-frontend/src/dashboard/components/DashboardBuilder/DashboardContainer.tsx
- superset-frontend/src/dashboard/components/DashboardBuilder/DashboardWrapper.tsx
- superset-frontend/src/dashboard/components/FiltersBadge/index.tsx
- superset-frontend/src/dashboard/components/Header/useHeaderActionsDropdownMenu.tsx
- superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
- superset-frontend/src/dashboard/components/SliceAdder.tsx
- superset-frontend/src/dashboard/components/SyncDashboardState/index.tsx
- superset-frontend/src/dashboard/components/dnd/handleHover.ts
- superset-frontend/src/dashboard/components/gridComponents/Chart/Chart.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/utils.ts
- superset-frontend/src/dashboard/components/nativeFilters/FilterBar/Vertical.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FilterBar/index.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FilterBar/utils.ts
- superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts
- superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigModal.tsx
- superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/hooks/useItemStateManager.ts
- superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/hooks/useModalSaveLogic.ts
- superset-frontend/src/dashboard/hooks/useDownloadScreenshot.ts
- superset-frontend/src/dashboard/reducers/datasources.ts
- superset-frontend/src/dashboard/util/activeAllDashboardFilters.ts
- superset-frontend/src/dashboard/util/activeDashboardFilters.ts
- superset-frontend/src/dashboard/util/charts/getFormDataWithExtraFilters.ts
- superset-frontend/src/dashboard/util/crossFilters.ts
- superset-frontend/src/dashboard/util/getDashboardUrl.ts
- superset-frontend/src/dashboard/util/getFilterScopeFromNodesTree.ts
- superset-frontend/src/dashboard/util/getFilterScopeNodesTree.ts
- superset-frontend/src/dataMask/reducer.ts
- superset-frontend/src/embedded/utils.test.ts
- superset-frontend/src/embedded/utils.ts
- superset-frontend/src/explore/actions/saveModalActions.ts
- superset-frontend/src/explore/components/Control.tsx
- superset-frontend/src/explore/components/ControlPanelsContainer.tsx
- superset-frontend/src/explore/components/DataTableControl/index.tsx
- superset-frontend/src/explore/components/DataTablesPane/components/DataTableControls.tsx
- superset-frontend/src/explore/components/ExploreViewContainer/index.tsx
- superset-frontend/src/explore/components/controls/BoundsControl.tsx
- superset-frontend/src/explore/components/controls/ColorSchemeControl/index.tsx
- superset-frontend/src/explore/components/controls/ColumnConfigControl/ControlForm/index.tsx
- superset-frontend/src/explore/components/controls/ComparisonRangeLabel.tsx
- superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnMetricSelect.tsx
- superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
- superset-frontend/src/explore/components/controls/DndColumnSelectControl/useResizeButton.tsx
- superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopover/index.tsx
- superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterEditPopoverSimpleTabContent/useAdvancedDataTypes.ts
- superset-frontend/src/explore/components/controls/MetricControl/MetricsControl.tsx
- superset-frontend/src/explore/components/controls/TextAreaControl.tsx
- superset-frontend/src/explore/components/controls/TextControl/index.tsx
- superset-frontend/src/explore/components/controls/TimeOffsetControl.tsx
- superset-frontend/src/explore/components/controls/ViewQueryModalFooter.tsx
- superset-frontend/src/explore/controlUtils/getControlValuesCompatibleWithDatasource.ts
- superset-frontend/src/explore/controlUtils/getFormDataWithDashboardContext.ts
- superset-frontend/src/explore/controlUtils/standardizedFormData.ts
- superset-frontend/src/explore/reducers/exploreReducer.ts
- superset-frontend/src/features/databases/DatabaseModal/SSHTunnelSwitch.tsx
- superset-frontend/src/features/databases/DatabaseModal/index.tsx
- superset-frontend/src/features/home/RightMenu.tsx
- superset-frontend/src/features/home/SubMenu.tsx
- superset-frontend/src/features/reports/ReportModal/actions.ts
- superset-frontend/src/features/reports/ReportModal/reducer.ts
- superset-frontend/src/features/themes/ThemeModal.tsx
- superset-frontend/src/filters/components/Range/RangeFilterPlugin.tsx
- superset-frontend/src/filters/components/Select/SelectFilterPlugin.tsx
- superset-frontend/src/hooks/apiResources/sqlEditorTabs.ts
- superset-frontend/src/pages/ChartList/index.tsx
- superset-frontend/src/pages/Home/index.tsx
- superset-frontend/src/pages/SqlLab/SqlLab.test.tsx
- superset-frontend/src/reduxUtils.ts
- superset-frontend/src/types/bootstrapTypes.ts
- superset-frontend/src/utils/DebouncedMessageQueue.ts
- superset-frontend/src/utils/colorScheme.ts
- superset-frontend/src/utils/downloadAsImage.tsx
- superset-frontend/src/utils/downloadAsPdf.ts
- superset-frontend/src/utils/getChartFormDiffs/index.ts
- superset-frontend/src/utils/sanitizeFormData/index.ts
- superset-frontend/src/utils/urlUtils.ts
- superset-frontend/src/views/CRUD/utils.tsx
-
Files skipped - 13
- superset-frontend/package-lock.json - Reason: Filter setting
- superset-frontend/package.json - Reason: Filter setting
- superset-frontend/packages/superset-core/package.json - Reason: Filter setting
- superset-frontend/packages/superset-ui-chart-controls/package.json - Reason: Filter setting
- superset-frontend/packages/superset-ui-core/package.json - Reason: Filter setting
- superset-frontend/plugins/legacy-preset-chart-nvd3/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-ag-grid-table/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-cartodiagram/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-echarts/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-handlebars/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-table/package.json - Reason: Filter setting
- superset-frontend/plugins/plugin-chart-word-cloud/package.json - Reason: Filter setting
- superset-frontend/plugins/preset-chart-deckgl/package.json - Reason: Filter setting
-
Tools
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
- Eslint (Linter) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #41511 +/- ##
=======================================
Coverage 64.56% 64.57%
=======================================
Files 2664 2664
Lines 146355 146359 +4
Branches 33842 33842
=======================================
+ Hits 94495 94504 +9
+ Misses 50142 50137 -5
Partials 1718 1718
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
CI surfaced failures in 5 suites that mocked `jest.mock('lodash/debounce')`.
That only worked because babel-plugin-lodash rewrote barrel imports to
per-method paths. With the lodash-es migration those mocks no longer intercept
the components' `import { debounce } from 'lodash-es'`, so the real (async)
debounce ran and assertions on synchronous side effects failed.
- Remove babel-plugin-lodash from babel.config.js and package.json. After the
lodash-es migration no bare `from 'lodash'` barrel imports remain for it to
rewrite, and it is unmaintained / incompatible with Babel 8.
- Add a jest moduleNameMapper aliasing `lodash-es` -> CJS `lodash`. lodash-es
is `type: module` (native ESM), which jest.mock cannot intercept; the CJS
build is API-identical and mockable.
- Update the 5 debounce mocks to mock the `lodash` barrel.
Verified: the 5 suites pass, and a broad slice (1094 tests across explore,
nativeFilters, and Chart) is green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review Agent Run #638b83
Actionable Suggestions - 3
-
superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.test.tsx - 1
- CWE-435: Mock Targets Wrong Import Path · Line 40-47
-
superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx - 1
- CWE-435: Mock Target Module Mismatch · Line 107-107
-
superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx - 1
- Import path mismatch between mock and component · Line 22-22
Review Details
-
Files reviewed - 7 · Commit Range:
15648fa..a2a2bbd- superset-frontend/babel.config.js
- superset-frontend/jest.config.js
- superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.test.tsx
- superset-frontend/src/dashboard/components/SliceAdder.test.tsx
- superset-frontend/src/explore/components/DataTableControl/FilterInput.test.tsx
- superset-frontend/src/explore/components/ExploreViewContainer/ExploreViewContainer.test.tsx
- superset-frontend/src/explore/components/controls/TimeSeriesColumnControl/TimeSeriesColumnControl.test.tsx
-
Files skipped - 2
- superset-frontend/package-lock.json - Reason: Filter setting
- superset-frontend/package.json - Reason: Filter setting
-
Tools
- Eslint (Linter) - ✔︎ Successful
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
SUMMARY
Migrates the frontend's bare lodash imports to
lodash-esfor native, method-level tree-shaking.import { debounce } from 'lodash'→import { debounce } from 'lodash-es'across 173 source files.lodash(the CommonJS build) doesn't tree-shake — importing a single method pulls in the whole library unless a build-time transform rewrites it. The repo relied onbabel-plugin-lodashfor that rewrite, but that plugin is unmaintained and incompatible with Babel 8 (it calls the removedpath.hoistAPI).lodash-esis the modern replacement: webpack tree-shakes it natively, no Babel plugin required.This pairs with the Babel 8 upgrade (#41510), which removes
babel-plugin-lodash. Doing the lodash-es migration here keeps the app's bundle lean without that plugin. The two PRs are independent and can merge in either order.Why this is low-risk:
import { x } from 'lodash'), which map 1:1 tolodash-es. There were zero default (import _ from 'lodash') or namespace (import * as _) imports — the shapeslodash-esdoesn't support.@types/lodash-esprovides the same type signatures as@types/lodash, so no type changes (tsc --noEmitclean).lodash-esis already in jest'stransformIgnorePatterns.lodashis retained as a dependency for the handful of remaining per-methodlodash/ximports and transitive consumers.lodash-esdeclared in every workspace manifest that imports it (plus@types/lodash-esat the root) for published-package correctness.TESTING INSTRUCTIONS
Validated locally: production webpack build compiles (pre-existing echarts/bundle-size warnings only), Jest unit suite passes, and
tsc --noEmitreports no type errors from the change.ADDITIONAL INFORMATION
Related: #41510 (Babel 8 upgrade, which removes
babel-plugin-lodash)🤖 Generated with Claude Code