Skip to content

Configure an HMR update strategy for multiple files #4500

@posva

Description

@posva

Clear and concise description of the problem

When developing a library with HMR support, I want to be able to support HMR with the least code from the end user

Suggested solution

When working with a library that is meant to be used in many files like Pinia for Vue, each HMR code needs to be placed inside of the store file to be able to handle the HMR. If placed outside, let's say in the main.ts entry point, you need to manually import all of the stores (using a glob doesn't seem to work):

import { acceptHMRUpdate, defineStore } from 'pinia'

export const useCounter = defineStore({
  // optios
})

if (import.meta.hot) {
  // acceptHMRUpdate creates a function that handles the update of the store in place
  import.meta.hot.accept(acceptHMRUpdate(useCounter, import.meta.hot))
}

That useCounter is imported in Vue component or JS files all across the app.

When reading the docs, I feel like this limitation is intended but it makes it quite cumbersome to add HMR support for stores. It would be nice if we could do something like this in the entry point or one single file of the app:

import.meta.hot!.accept(import.meta.glob('./stores/*.ts',
(newModule) => {
  // handle the update
})

Alternative

I tried importing all of the modules with a glob in the entrypoint (main.ts) but that doesn't work:

// src/main.ts
import { acceptHMRUpdate, createPinia, isUseStore } from 'pinia'

// rest of the code

if (import.meta.hot) {
  const stores = import.meta.glob('./stores/*.ts')
  for (const filePath in stores) {
    console.log('configuring HMR for', filePath)

    stores[filePath]().then((mod) => {
      for (const exportName in mod) {
        const storeDef = mod[exportName]
        if (isUseStore(storeDef)) {
          console.log(`Detected store "${storeDef.$id}"`)
          import.meta.hot!.accept(
            filePath,
            acceptHMRUpdate(storeDef, import.meta.hot)
          )
        }
      }
    })
  }

It doesn't even enter the function returned by acceptHMRUpdate().


I imagine that creating a vite plugin to rewrite all of the files in a specific folder to add support for HMR is possible but it means users need to add a vite plugin when installing the lib and differently from .vue files, stores have js or ts extensions, so they need to be filtered based on their content.

Additional context

The code from above is testable at https://github.com/posva/pinia/tree/test/globalhmr with yarn play. The source code is located at playground/src and src/hmr.ts

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions