Description
Describe the bug
When using manualChunks
to define a custom chunking strategy it is resulting in unexpected circular dependencies. In the repro provided, I am creating a separate chunk for each component and a framework
chunk. This is only for demonstration purposes, but the issue is present even with a less aggressive chunking strategy.
When building, the framework
chunk is dependent on a component chunk even if there are no implicit dependencies. However, the chunking moves some common code (originating from lodash/isString
into the component.Foo
chunk and the framework
chunk then imports it.
Ideally I would like to avoid these circular dependencies from occurring without having to be able to identify each one manually. For example, in this case I would not expect the following code to be added to the component:
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
I am unsure if this is a Vite or Rollup issue, so please excuse me if I opened the issue in the wrong repo.
Thank you
Reproduction
https://github.com/kevinfarrugia/vite-chunk-dependencies
Steps to reproduce
The scope of this project is to demonstrate the dependencies of a Vite project.
Installation
npm install
Usage
The dependencies of the project can be visualized using Madge. To generate a dependency graph, run:
npm run build && npx madge ./dist --json
The output will be:
{
"assets/app-D6GzwUaY.js": [
"assets/component.TodoForm-CZovwjkK.js",
"assets/component.TodoList-44ZiI1-M.js",
"assets/framework-CtvSml8s.js"
],
"assets/component.Foo-D0Zme1m7.js": [
"assets/component.Label-BySnBOvf.js",
"assets/framework-CtvSml8s.js"
],
"assets/component.Label-BySnBOvf.js": [
"assets/framework-CtvSml8s.js"
],
"assets/component.TodoForm-CZovwjkK.js": [
"assets/component.Foo-D0Zme1m7.js",
"assets/framework-CtvSml8s.js"
],
"assets/component.TodoItem-CzBrJbZI.js": [
"assets/component.Label-BySnBOvf.js",
"assets/framework-CtvSml8s.js"
],
"assets/component.TodoList-44ZiI1-M.js": [
"assets/component.Label-BySnBOvf.js",
"assets/component.TodoItem-CzBrJbZI.js",
"assets/framework-CtvSml8s.js"
],
"assets/framework-CtvSml8s.js": [
"assets/component.Foo-D0Zme1m7.js"
],
"assets/index-CWx-HeYK.js": [
"assets/app-D6GzwUaY.js",
"assets/component.Foo-D0Zme1m7.js",
"assets/component.Label-BySnBOvf.js",
"assets/component.TodoForm-CZovwjkK.js",
"assets/component.TodoItem-CzBrJbZI.js",
"assets/component.TodoList-44ZiI1-M.js",
"assets/framework-CtvSml8s.js"
]
}
As can be seen from the preceding output, the assets/framework-CtvSml8s.js
file is dependent on assets/component.Foo-D0Zme1m7.js
, which is a component that is used in the assets/app-D5DJEYJu.js
file. This is not desired because it creates a circular dependency. The assets/framework-CtvSml8s.js
file should not depend on any components, as it is meant to be a framework file that provides utility functions and does not need to know about the components.
Looking at the contents of the framework-CtvSml8s.js
file, we can see that it imports the getDefaultExportFromCjs
from the component.Foo
chunk:
import { g as getDefaultExportFromCjs } from "./component.Foo-D0Zme1m7.js";
This is defined as:
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
This function is used within the component.Foo
chunk in the following line:
const isString = /* @__PURE__ */ getDefaultExportFromCjs(isStringExports);
where isString
is imported from lodash/isString
. Removing the lodash/isString
dependency from src/components/Foo/index.jsx
will remove the circular dependency.
System Info
System:
OS: Linux 6.11 Ubuntu 24.04.2 LTS 24.04.2 LTS (Noble Numbat)
CPU: (24) x64 AMD Ryzen AI 9 HX 370 w/ Radeon 890M
Memory: 43.97 GB / 62.09 GB
Container: Yes
Shell: 5.2.21 - /bin/bash
Binaries:
Node: 22.15.0 - ~/.nvm/versions/node/v22.15.0/bin/node
npm: 10.9.2 - ~/.nvm/versions/node/v22.15.0/bin/npm
Browsers:
Chrome: 137.0.7151.55
Used Package Manager
npm
Logs
No response
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- The provided reproduction is a minimal reproducible example of the bug.