Skip to content

Commit 0e9e7e7

Browse files
BobbieGoedeposva
andauthored
feat(nuxt): automatic HMR code (vite only) (#2954)
Co-authored-by: Eduardo San Martin Morote <posva13@gmail.com>
1 parent be9e356 commit 0e9e7e7

File tree

6 files changed

+76
-16
lines changed

6 files changed

+76
-16
lines changed

packages/nuxt/playground/pages/index.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ if (import.meta.server) {
1616

1717
<template>
1818
<div>
19-
<p>Count: {{ counter.$state.count }}</p>
19+
<p>Count: {{ counter.count }} x 2 = {{ counter.double }}</p>
2020
<button @click="counter.increment()">+</button>
21+
<pre>{{ counter.$state }}</pre>
22+
23+
<hr />
2124

2225
<p>Layer store: {{ layerStore.count }}</p>
2326
</div>

packages/nuxt/playground/stores/counter.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ export const useCounter = defineStore('counter', {
1717
},
1818
},
1919
getters: {
20-
getCount: (state) => state.count,
20+
double: (state) => state.count * 2,
2121
},
2222
})
23-
24-
if (import.meta.hot) {
25-
import.meta.hot.accept(acceptHMRUpdate(useCounter, import.meta.hot))
26-
}

packages/nuxt/playground/stores/nested/some-store.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,3 @@ export const useSomeStoreStore = defineStore('some-store', () => {
22
// console.log('I was defined within a nested store directory')
33
return {}
44
})
5-
6-
if (import.meta.hot) {
7-
import.meta.hot.accept(acceptHMRUpdate(useSomeStoreStore, import.meta.hot))
8-
}

packages/nuxt/playground/stores/with-skip-hydrate.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,3 @@ export const useWithSkipHydrateStore = defineStore('with-skip-hydrate', () => {
88
)
99
return { skipped }
1010
})
11-
12-
if (import.meta.hot) {
13-
import.meta.hot.accept(
14-
acceptHMRUpdate(useWithSkipHydrateStore, import.meta.hot)
15-
)
16-
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { VariableDeclarator } from 'estree'
2+
import type { Nuxt } from 'nuxt/schema'
3+
import type { Plugin } from 'vite'
4+
5+
function getStoreDeclaration(nodes?: VariableDeclarator[]) {
6+
return nodes?.find(
7+
(x) =>
8+
x.init?.type === 'CallExpression' &&
9+
x.init.callee.type === 'Identifier' &&
10+
x.init.callee.name === 'defineStore'
11+
)
12+
}
13+
14+
function nameFromDeclaration(node?: VariableDeclarator) {
15+
return node?.id.type === 'Identifier' && node.id.name
16+
}
17+
18+
export function autoRegisterHMRPlugin(rootDir: string) {
19+
return {
20+
name: 'pinia:auto-hmr-registration',
21+
22+
transform(code, id) {
23+
if (id.startsWith('\x00')) return
24+
if (!id.startsWith(rootDir)) return
25+
if (!code.includes('defineStore') || code.includes('acceptHMRUpdate')) {
26+
return
27+
}
28+
29+
const ast = this.parse(code)
30+
31+
// walk top-level nodes
32+
for (const n of ast.body) {
33+
if (
34+
n.type === 'VariableDeclaration' ||
35+
n.type === 'ExportNamedDeclaration'
36+
) {
37+
// find export or variable declaration that uses `defineStore`
38+
const storeDeclaration = getStoreDeclaration(
39+
n.type === 'VariableDeclaration'
40+
? n.declarations
41+
: n.declaration?.type === 'VariableDeclaration'
42+
? n.declaration?.declarations
43+
: undefined
44+
)
45+
46+
// retrieve the variable name
47+
const storeName = nameFromDeclaration(storeDeclaration)
48+
if (storeName) {
49+
// append HMR code
50+
return {
51+
code: [
52+
`import { acceptHMRUpdate } from 'pinia'`,
53+
code,
54+
'if (import.meta.hot) {',
55+
` import.meta.hot.accept(acceptHMRUpdate(${storeName}, import.meta.hot))`,
56+
'}',
57+
].join('\n'),
58+
}
59+
}
60+
}
61+
}
62+
},
63+
} satisfies Plugin
64+
}

packages/nuxt/src/module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import {
88
createResolver,
99
addImportsDir,
1010
getLayerDirectories,
11+
addVitePlugin,
1112
} from '@nuxt/kit'
1213
import type { NuxtModule } from '@nuxt/schema'
1314
import { fileURLToPath } from 'node:url'
15+
import { autoRegisterHMRPlugin } from './auto-hmr-plugin'
1416

1517
export interface ModuleOptions {
1618
/**
@@ -82,6 +84,11 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
8284
}
8385
}
8486
}
87+
88+
// Register automatic hmr code plugin - dev mode only
89+
if (nuxt.options.dev) {
90+
addVitePlugin(autoRegisterHMRPlugin(resolve(nuxt.options.rootDir)))
91+
}
8592
},
8693
})
8794

0 commit comments

Comments
 (0)