-
-
Save primeboard-dev/79d230e4178c4dea2ff598601ed265bf to your computer and use it in GitHub Desktop.
| import { | |
| Pinia, | |
| SetupStoreDefinition, | |
| StoreDefinition, | |
| StoreGeneric, | |
| _ActionsTree, | |
| _GettersTree, | |
| getActivePinia, | |
| } from "pinia"; | |
| type StoreForHMR = SetupStoreDefinition<string, unknown> | StoreDefinition; | |
| export function usePiniaWebpackHotHMR( | |
| hot: webpack.Hot, | |
| store: StoreForHMR | StoreForHMR[] | |
| ) { | |
| hot.accept(); | |
| const stores = Array.isArray(store) ? store : [store]; | |
| stores.forEach((store) => { | |
| hot.dispose((data) => { | |
| (data as any).initialUseStoreId = store.$id; | |
| }); | |
| const piniaAccept = acceptWebpackHMRUpdate(store.$id, hot); | |
| piniaAccept({ ...store }); | |
| }); | |
| } | |
| /** | |
| * Checks if a function is a `StoreDefinition`. | |
| * | |
| * @param fn - object to test | |
| * @returns true if `fn` is a StoreDefinition | |
| */ | |
| export const isUseStore = (fn: any): fn is StoreDefinition => { | |
| return typeof fn === "function" && typeof fn.$id === "string"; | |
| }; | |
| type PiniaPlus = Pinia & { | |
| _s: Map<string, StoreGeneric>; | |
| }; | |
| export function acceptWebpackHMRUpdate( | |
| initialUseStoreId: string, | |
| hot: webpack.Hot | |
| ) { | |
| // strip as much as possible from iife.prod | |
| if (!__DEV__) { | |
| return () => {}; | |
| } | |
| return (newModule: any) => { | |
| // @ts-expect-error | |
| const pinia: PiniaPlus | undefined = hot.data?.pinia || getActivePinia(); | |
| if (!pinia) { | |
| // this store is still not used | |
| return; | |
| } | |
| // preserve the pinia instance across loads | |
| // hot.data.pinia = pinia // FIXME: this doesn't work as data does not let us set functions. | |
| for (const exportName in newModule) { | |
| const useStore = newModule[exportName]; | |
| if (isUseStore(useStore) && pinia._s.has(useStore.$id)) { | |
| // console.log('Accepting update for', useStore.$id) | |
| const id = useStore.$id; | |
| if (id !== initialUseStoreId) { | |
| console.warn( | |
| `The id of the store changed from "${initialUseStoreId}" to "${id}". Reloading.` | |
| ); | |
| // return import.meta.hot.invalidate() | |
| return hot.invalidate(); | |
| } | |
| const existingStore: StoreGeneric = pinia._s.get(id)!; | |
| if (!existingStore) { | |
| console.log(`[Pinia]: skipping hmr because store doesn't exist yet`); | |
| return; | |
| } | |
| useStore(pinia, existingStore); | |
| } | |
| } | |
| }; | |
| } |
@tmcdos great to see this used, and hope it helped! Wanted to check, you mentioned using it in non native Vue - do you mean not in NativeScript, and if so where? Are you adopting this for “normal”/web Vue?
@vpiskunov Thank you very much for your work! I was struggling for months without success to make the HMR working with Webpack.
Yes, I meant I am using your code in normal web Vue v3 projects - Quasar with Webpack, Pinia and WindiCSS. I inherited the project configured with Vite but Vite has problems with the debugging DX (developer experience) - sourcemaps do not provide access to the original *.vue files and I can not put breakpoints inside my original (unminified and untranspiled) code. The breakpoints are only possible inside the transpiled "modules" that are loaded by the browser. So I decided to trade-off the Vite speed for a better debugging experience with Webpack.
I am aware about RsPack but have not found free time to try it on a real project.
If you are interested, I can share several patches for various NPM packages which (the patches) I use in my projects through the https://www.npmjs.com/package/custompatch tool.
It takes too much effort to get these patches merged so I drag and update them with all my projects :)
Thanks a lot, but can you share/explain step 1.
I am quite far from ts( and can't catch it.
Seems without step 1 it's not working due
`ERROR in ./src/utils/piniaHmr.ts:14:8
TS2503: Cannot find namespace 'webpack'.
12 |
13 | export function usePiniaWebpackHotHMR(
14 | hot: webpack.Hot,
| ^^^^^^^
15 | store: StoreForHMR | StoreForHMR[]
16 | ) {
17 | hot.accept();
ERROR in ./src/utils/piniaHmr.ts:21:18
TS7006: Parameter 'data' implicitly has an 'any' type.
19 |
20 | stores.forEach((store) => {
21 | hot.dispose((data) => {
| ^^^^
22 | (data as any).initialUseStoreId = store.$id;
23 | });
24 | const piniaAccept = acceptWebpackHMRUpdate(store.$id, hot);
ERROR in ./src/utils/piniaHmr.ts:45:8
TS2503: Cannot find namespace 'webpack'.
43 | export function acceptWebpackHMRUpdate(
44 | initialUseStoreId: string,
45 | hot: webpack.Hot
| ^^^^^^^
46 | ) {
47 | // strip as much as possible from iife.prod
48 | if (!DEV) {
ERROR in ./src/utils/piniaHmr.ts:52:5
TS2578: Unused '@ts-expect-error' directive.
50 | }
51 | return (newModule: any) => {
52 | // @ts-expect-error
| ^^^^^^^^^^^^^^^^^^^
53 | const pinia: PiniaPlus | undefined = hot.data?.pinia || getActivePinia();
54 | if (!pinia) {
55 | // this store is still not used
Found 4 errors in 489 ms.`
This did not work for me with non-native Vue so I had to make some changes: