vite: HMR error: Cannot access '...' before initialization

Describe the bug

The error happens when I try to edit component, that

  1. Wrap in connect function (redux)
  2. Is inside dependency loop
  3. 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 image

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

  • 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.
  • Provide a description in this issue that describes the bug.
  • 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.
  • Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 67
  • Comments: 68 (9 by maintainers)

Commits related to this issue

Most upvoted comments

I found this solution which prevents HMR from breaking if there are circular dependencies, but I’m not sure what are the drawbacks

// vite.config.ts

export default defineConfig({
  plugins: [
    // your plugins,
    {
      name: "singleHMR",
      handleHotUpdate({ modules }) {
        modules.map((m) => {
          m.importedModules = new Set();
          m.importers = new Set();
        });

        return modules;
      },
    },
  ],
});

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>

STOP commenting “same” and upvote first comment please. Avoid this all over GitHub, your are sending useless notifications to everyone who had subscribed to the issue. Thanks.

still have this problem on vite@3.2.0

I have the same question when i use store and axios in route beforeEach

madge don’t find any circular dependencies for me and I’m still getting this error

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>

@michaeljohansen madge does not seem to work with Vue and <script setup> and especially if you use auto-imports.

I wish Vite itself showed a more appropriate error message about circular dependencies instead of Cannot access ... before initialization - which is misleading and meaningless. It would be nice if Vite showed where there are circular dependencies and even offered a solution how to fix it.

@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!

I have the same problem vite^3.0.4, vue^3.2.37, vue-router^4.1.3 (project generated by npm init vue@latest), error is shown on child component when hit save on parent, and changes does not reflect regardlessly.

@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 image

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 image 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

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).

I found this solution which prevents HMR from breaking if there are circular dependencies, but I’m not sure what are the drawbacks

// vite.config.ts

export default defineConfig({
  plugins: [
    // your plugins,
    {
      name: "singleHMR",
      handleHotUpdate({ modules }) {
        modules.map((m) => {
          m.importedModules = new Set();
          m.importers = new Set();
        });

        return modules;
      },
    },
  ],
});

woow! In my project I was having problems using use-sound inside a context and this configuration resolved! Thanks!!

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.

same, vite@4.1.4

Thanks @michaeljohansen!

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>

Here’s how I did it:

npx madge src/index.tsx --circular

This pointed me to entries like:

3) index.tsx > Foo.tsx

Foo.tsx had imported Context from index.tsx.

I fixed it by moving Context into its own Context.tsx file and importing it into index.tsx and Foo.tsx.

@SuspiciousLookingOwl did you ever find any negatives to doing that? I’m also seeing that this is fixing it for me, but unsure if it also breaks anything

I was able to fix this issue!!! Try to register the component globally in the main.js

import Tree from '../components/tree.vue'; app.component('Tree', Tree);

Hope this helps

Is there any progress regarding this issue at present?

same, vite@4.1.1

I found this solution which prevents HMR from breaking if there are circular dependencies, but I’m not sure what are the drawbacks

// vite.config.ts

export default defineConfig({
  plugins: [
    // your plugins,
    {
      name: "singleHMR",
      handleHotUpdate({ modules }) {
        modules.map((m) => {
          m.importedModules = new Set();
          m.importers = new Set();
        });

        return modules;
      },
    },
  ],
});

Solved the issue about ‘Cannot access …’ But now, when I change a className in a component, I manually have to refresh the page to see the CSS changes. I am using Tailwind. It hot reloads when I don’t use singleHMR as above

In my case, I had a hidden circular dependency cycle (madge couldn’t find it) with react-router and use-react-router-breadcrumbs. I had implemented a custom breadcrumbing system with those two and CRA at the time. I fixed it by upgrading to a newer version of react-router, which now supports breadcrumbs out of the box. By adjusting the breadcrumbs accordingly this issue was solved for me.

This is probably a specific case, but hopefully my findings can be useful to someone in a similar situation!

Anyone have any success finding the circular dependencies when madge doesn’t think there are any?

I have the same problem vite^3.0.4, vue^3.2.37, vue-router^4.1.3 (project generated by npm init vue@latest), error is shown on child component when hit save on parent, and changes does not reflect regardlessly.

Exactly the same here but in react, I have an array of components for a wizard and it gives me the error, I’m not even rendering them in the parent component, the simple fact of having them in the array gives me the error, which is not happening to me with CRA. When I comment these components the error disappears.

wizard

And the error that I get in the console is the following in loop.

error

I have the same question, any progress?

Getting same error

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)