HMR error: Cannot access '...' before initialization
Describe the bug
The error happens when I try to edit component, that
- Wrap in
connectfunction (redux) - Is inside dependency loop
- There is another component inside dependency loop
Seems weird, but it's not so rare case when project uses routers like UiRouter or Universal router
I expect that component will be updated with HMR without errors or may be reload the page but not to throw an error
Reproduction
Repo: https://github.com/xSorc/test-vite-fast-refresh-loop-dependency
To reproduce this error you need to open the project and try to edit Component.tsx. You will see an error

System Info
Output of npx envinfo --system --npmPackages vite,@vitejs/plugin-vue --binaries --browsers:
System:
OS: Windows 10 10.0.19042
CPU: (6) x64 Intel(R) Core(TM) i5-8600K CPU @ 3.60GHz
Memory: 8.19 GB / 15.94 GB
Binaries:
Node: 14.15.3 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD
npm: 6.14.9 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Spartan (44.19041.423.0), Chromium (89.0.774.77)
Internet Explorer: 11.0.19041.1
npmPackages:
vite: ^2.1.5 => 2.1.5
Used package manager:
Logs
Before submitting the issue, please make sure you do the following
- [x] Read the Contributing Guidelines.
- [x] Read the docs.
- [x] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [x] Provide a description in this issue that describes the bug.
- [x] 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 https://github.com/vuejs/vue-next instead.
- [x] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
@xSorc Hello ~ I read your description and repeated the problem, I guess it might be the React Render problem

@ygj6 Hello. Why do you think that it is react problem? I think react only calls render fn. I don't have whole picture, but here some thoughts:
We can't access variable from module, that already depend on us. But this app works - because we access variable not instantly(during module loading), but during render. If we write smth like this - app will fall instantly
import { STATES_CONST } from './states';
console.log(STATES_CONST); // this line break all because we try access STATES_CONST during module loading
class Component extends PureComponent {
render() {
return <div>States const: {STATES_CONST}</div>;
}
}
maybe this issue has to be fixed like this(this is Vite code)?
try {
const newMod = await import(
/* @vite-ignore */
base +
path.slice(1) +
`?import&t=${timestamp}${query ? `&${query}` : ''}`);
moduleMap.set(dep, newMod);
}
catch (e) {
warnFailedFetch(e, dep);
location.reload(); // I was added this line
}
P.S. this hmr fails because during loading of dependencies of Component.tsx after hmr there is situation that ComponentOther.tsx loads before router.ts. And router.ts access variable during module loading(this is forbidden)

maybe it's project problem, but I think Vite should reload the page in this case?
I think there is a bug in plugin-react-refresh, but we can not reload on error. Check out the warning message "This could be due to syntax errors or importing non-existent modules.". When the user is typing and there is an error, we want to wait until a successful run to update the page with HMR, or the state will be lost after the full reload while the user is typing (for example if it is using auto save)
@patak-js how about this idea?
We can't update this module because of imports loop, but we can prevent our page to be broken. Now every module call performReactRefresh during loading. We can change it and call react refresh only after successful import. Something like this:
current code here: plugin-react-refresh/index.js
const runtimeCode = `
const exports = {}
${fs.readFileSync(runtimeFilePath, 'utf-8')}
let queue = false;
exports.queueReactRefresh = () => (queue = true); // do not debounce. Only set flag
window.flushReactRefresh = () => { // set window fn to flush updates. We call them *after* successful import
if (queue) {
exports.performReactRefresh();
queue = false;
}
}
export default exports
...
const footer = `
if (import.meta.hot) {
window.$RefreshReg$ = prevRefreshReg;
window.$RefreshSig$ = prevRefreshSig;
${
isReasonReact || isRefreshBoundary(result.ast)
? `import.meta.hot.accept();`
: ``
}
RefreshRuntime.queueReactRefresh(); // call here queue instead of debounce performReactRefresh
}`
current code here: vite/dist/client/client.js
try {
const newMod = await import(
/* @vite-ignore */
base +
path.slice(1) +
`?import&t=${timestamp}${query ? `&${query}` : ''}`);
window.flushReactRefresh?.(); // flush updates after successful import
moduleMap.set(dep, newMod);
}
catch (e) {
warnFailedFetch(e, dep);
}
There is another option how to fix this by one line. We can make something like this:
try {
const newMod = await import(
/* @vite-ignore */
base +
path.slice(1) +
`?import&t=${timestamp}${query ? `&${query}` : ''}`);
moduleMap.set(dep, newMod);
}
catch (e) {
clearTimeout(window.__vite_plugin_react_timeout); // I added this line
warnFailedFetch(e, dep);
}
I understood that we can't write code connected to react inside Vite client... Needs more complex solution
I have the same question, any progress?
I have the same question when i use store and axios in route beforeEach
I have the same question, any progress?
So do i, wait for a solution
I have the same question, any progress?
I have the same question, any progress?
I have the same question, any progress?
I have the same question, any progress?
@xSorc were you able to identify the source of this issue? I'm sure there are thousands of Vite apps with react and connected components, so there must be something specific that is causing this issue. I've had to turn off HMR for the app to load properly.
@tzusman I can't understand the whole picture. All I know that the problem is caused by imports loop.
For example you have this structure

That works during first load. But when I tried to change Component 1, an error Cannot access 'STATES' before initialization happend.
The most strange thing is if I change in Component 1 line
function connect(Cmp: ComponentType) {
return Cmp
}
class Component extends PureComponent {
render() {
return <div>States const: {STATES_CONST}</div>;
}
}
export default connect(Component);
to lines
function connect(Cmp: ComponentType) {
return Cmp
}
class Component extends PureComponent {
render() {
return <div>States const: {STATES_CONST}</div>;
}
}
const a = connect(Component);
export default a;
the problem is gone. I have no idea how this works
The structure may be simplified to this
so it may be different
My advice is to remove a dependency loop. I've done it in my project. This is the easiest way to handle it right now
This also happen to me on development. Build and serve is work well.

Getting same error
the same
Stumbled onto some tips from parceljs that may help with this issue:
- Avoid class components – Fast Refresh only works with function components (and Hooks).
- Export only React components – If a file exports a mix of React components and other types of values, its state will be reset whenever it changes. To preserve state, only export React components and move other exports to a different file if possible.
- Avoid unnamed default exports – Declaring components using a default exported arrow function will cause state to be reset when it is changed. Use a named function, or assign the arrow function to a variable instead.
- Keep entry components in their own files – Entry components should be in a separate file from the one that calls ReactDOM.render or they will be remounted on every change. For more tips, see the official React Fast Refresh docs. https://reactnative.dev/docs/fast-refresh
I actually was getting a hard refresh way more than I was expecting before following each of those tips, now I'm seeing fast refresh everywhere and haven't seen that error yet.
I have the same question, any progress?
@matt-erhart I had the same issue but your last tip really helped me resolve the issue, thank you so much!
What I had:
//main.tsx
const AppProviders: React.FC = (props) => {...}
ReactDOM.render(
<React.StrictMode>
<AppProviders>
<App />
</AppProviders>
</React.StrictMode>,
document.getElementById('root')
);
Changed it to:
// AppProviders.tsx
const AppProviders: React.FC = (props) => {...}
// main.tsx
ReactDOM.render(
<React.StrictMode>
<AppProviders>
<App />
</AppProviders>
</React.StrictMode>,
document.getElementById('root')
);
So I just moved AppProviders to a separate file and everything started working. Thanks again!
For future travelers: If you see the ReferenceError: Cannot access (…) before initialization error then you may have circular dependencies that need to be resolved. Discover them with a tool like Madge: madge --circular <path>
vs code extension to help find circular dependencies https://marketplace.visualstudio.com/items?itemName=iulian-radu-at.find-unused-exports
source https://twitter.com/alecdotbiz/status/1461729042604998664?t=MJApPe1FxTzI6zMMXXSktQ&s=19
I have the same question, any progress?
I have the same question, any progress?
I have the same question, any progress?
I had this problem too and it was caused by circular dependencies. As others suggested, madge can help you find the files where this is happening, but in my case I had a project with TypeScript and JavaScript files, so I used this command instead:
npx madge --ts-config ./tsconfig.json --warning --circular ./src
You need to specify the location of your tsconfig.json. Otherwise, the .ts files will be ignored (they will generate a warning instead) and any circular dep in those files will be skipped. The ---warning flag just provides more information (like if you have .json files being used as modules).
Hello im having the same issue. i have been on it all day and still no answer. i keep getting it no matter what
@ishaiavrahami as others have mentioned try to run npx madge --circular /src/components/Store.vue to find out the circular dependency.
madge don't find any circular dependencies for me and I'm still getting this error
How do I fix this issue! Been stuck all this 2 days now