vitrify 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/bin/cli.js +3 -3
  2. package/dist/bin/dev.js +3 -3
  3. package/dist/frameworks/vue/fastify-ssr-plugin.js +54 -18
  4. package/dist/frameworks/vue/prerender.js +4 -4
  5. package/dist/frameworks/vue/server.js +2 -1
  6. package/dist/hooks/index.js +1 -0
  7. package/dist/index.js +12 -1
  8. package/dist/plugins/index.js +1 -0
  9. package/dist/plugins/pinia/index.js +61 -0
  10. package/dist/plugins/quasar/index.js +7 -8
  11. package/dist/types/frameworks/vue/fastify-ssr-plugin.d.ts +6 -3
  12. package/dist/types/frameworks/vue/prerender.d.ts +3 -3
  13. package/dist/types/frameworks/vue/server.d.ts +4 -4
  14. package/dist/types/hooks/index.d.ts +2 -0
  15. package/dist/types/index.d.ts +2 -2
  16. package/dist/types/plugins/index.d.ts +1 -0
  17. package/dist/types/plugins/pinia/index.d.ts +5 -0
  18. package/dist/types/plugins/quasar/index.d.ts +2 -2
  19. package/dist/types/vitrify-config.d.ts +73 -11
  20. package/package.json +33 -22
  21. package/src/node/bin/cli.ts +13 -7
  22. package/src/node/bin/dev.ts +7 -4
  23. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +81 -27
  24. package/src/node/frameworks/vue/prerender.ts +6 -6
  25. package/src/node/frameworks/vue/server.ts +8 -2
  26. package/src/node/hooks/index.ts +19 -0
  27. package/src/node/index.ts +16 -4
  28. package/src/node/plugins/index.ts +1 -0
  29. package/src/node/plugins/pinia/index.ts +96 -0
  30. package/src/node/plugins/quasar/index.ts +13 -15
  31. package/src/node/vitrify-config.ts +104 -19
  32. package/src/vite/vue/RootComponent.vue +1 -1
  33. package/src/vite/vue/main.ts +52 -22
  34. package/src/vite/vue/ssr/app.ts +3 -2
  35. package/src/vite/vue/ssr/entry-server.ts +22 -41
  36. package/src/vite/vue/ssr/prerender.ts +2 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitrify",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "license": "MIT",
5
5
  "author": "Stefan van Herwijnen",
6
6
  "description": "Vite as your Full Stack development tool",
@@ -33,6 +33,10 @@
33
33
  "./plugins": {
34
34
  "types": "./dist/types/plugins/index.d.ts",
35
35
  "import": "./dist/plugins/index.js"
36
+ },
37
+ "./hooks": {
38
+ "types": "./dist/types/hooks/index.d.ts",
39
+ "import": "./dist/hooks/index.d.ts"
36
40
  }
37
41
  },
38
42
  "engines": {
@@ -50,60 +54,67 @@
50
54
  "dependencies": {
51
55
  "@fastify/middie": "^9.0.3",
52
56
  "@fastify/one-line-logger": "^2.0.2",
53
- "@fastify/static": "^8.1.1",
54
- "@unocss/core": "^66.0.0",
55
- "@unocss/preset-uno": "^66.0.0",
56
- "@unocss/preset-web-fonts": "66.1.0-beta.13",
57
- "@unocss/preset-wind": "^66.0.0",
58
- "@vitejs/plugin-vue": "^5.2.3",
57
+ "@fastify/static": "^8.2.0",
58
+ "@unocss/core": "^66.1.2",
59
+ "@unocss/preset-uno": "^66.1.2",
60
+ "@unocss/preset-web-fonts": "66.1.2",
61
+ "@unocss/preset-wind": "^66.1.2",
62
+ "@vitejs/plugin-vue": "^5.2.4",
59
63
  "ajv": "^8.17.1",
60
64
  "animated-unocss": "^0.0.6",
61
65
  "cac": "^6.7.14",
62
66
  "chalk": "^5.4.1",
63
67
  "cross-env": "^7.0.3",
64
- "esbuild": "^0.25.3",
65
- "fastify": "^5.3.2",
68
+ "devalue": "^5.1.1",
69
+ "esbuild": "^0.25.4",
70
+ "fastify": "^5.3.3",
66
71
  "glob": "^11.0.2",
67
- "happy-dom": "^17.4.6",
72
+ "happy-dom": "^17.4.7",
68
73
  "is-port-reachable": "^4.0.0",
69
74
  "magic-string": "^0.30.17",
70
75
  "merge-deep": "^3.0.3",
71
76
  "readline": "^1.3.0",
72
77
  "rollup-plugin-visualizer": "^5.14.0",
73
- "sass": "1.87.0",
78
+ "sass": "1.89.0",
79
+ "stringify-object": "^5.0.0",
74
80
  "ts-node": "^10.9.2",
75
- "unocss": "^66.0.0",
81
+ "unocss": "^66.1.2",
76
82
  "unplugin-vue-components": "^28.5.0",
77
- "vite": "^6.3.4",
83
+ "vite": "^6.3.5",
78
84
  "vite-plugin-pwa": "^1.0.0",
79
85
  "vitefu": "^1.0.6",
80
- "vitest": "^3.1.2",
86
+ "vitest": "^3.1.4",
81
87
  "workbox-window": "^7.3.0"
82
88
  },
83
89
  "devDependencies": {
84
90
  "@iconify-json/mdi": "^1.2.3",
85
- "@quasar/extras": "^1.16.17",
91
+ "@pinia/colada": "^0.16.1",
92
+ "@quasar/extras": "^1.17.0",
86
93
  "@quasar/quasar-ui-qmarkdown": "^2.0.5",
87
94
  "@quasar/quasar-ui-qmediaplayer": "^2.0.0-beta.0",
88
95
  "@types/connect": "^3.4.38",
89
96
  "@types/glob": "^8.1.0",
90
97
  "@types/merge-deep": "^3.0.3",
91
- "@types/node": "^22.15.3",
98
+ "@types/node": "^22.15.21",
99
+ "@types/stringify-object": "^4.0.5",
92
100
  "@types/ws": "^8.18.1",
93
- "@unocss/preset-icons": "^66.0.0",
94
- "@vue/runtime-core": "^3.5.13",
95
- "beasties": "^0.3.3",
101
+ "@unocss/preset-icons": "^66.1.2",
102
+ "@vue/runtime-core": "^3.5.14",
103
+ "beasties": "^0.3.4",
96
104
  "css": "^3.0.0",
97
105
  "css-to-tailwind-translator": "^1.2.8",
106
+ "pinia": "^3.0.2",
98
107
  "quasar": "^2.18.1",
99
- "rollup": "^4.40.1",
108
+ "rollup": "^4.41.0",
100
109
  "typescript": "^5.8.3",
101
110
  "vue": "^3.5.13",
102
111
  "vue-router": "^4.5.1"
103
112
  },
104
113
  "peerDependencies": {
105
- "@fastify/static": "^8.1.1",
106
- "fastify": "^5.3.2",
114
+ "@fastify/static": "^8.2.0",
115
+ "@pinia/colada": "^0.16.1",
116
+ "fastify": "^5.3.3",
117
+ "pinia": "^3.0.2",
107
118
  "quasar": "^2.18.1",
108
119
  "vue": "^3.5.13",
109
120
  "vue-router": "^4.5.1"
@@ -24,7 +24,6 @@ cli
24
24
  const { build } = await import('./build.js')
25
25
  let appDir: URL
26
26
  let prerender
27
- let onRendered
28
27
  if (options.appDir) {
29
28
  if (options.appDir.slice(-1) !== '/') options.appDir += '/'
30
29
  appDir = new URL(`file://${options.appDir}`)
@@ -90,11 +89,17 @@ cli
90
89
  new URL('ssr/server/prerender.mjs', baseOutDir).pathname
91
90
  ))
92
91
 
93
- const { template, manifest, render, getRoutes, onRendered } =
94
- await loadSSRAssets({
95
- mode: 'ssg',
96
- distDir: baseOutDir
97
- })
92
+ const {
93
+ template,
94
+ manifest,
95
+ render,
96
+ getRoutes,
97
+ onRendered,
98
+ onTemplateRendered
99
+ } = await loadSSRAssets({
100
+ mode: 'ssg',
101
+ distDir: baseOutDir
102
+ })
98
103
  const routes = await getRoutes()
99
104
 
100
105
  prerender({
@@ -103,7 +108,8 @@ cli
103
108
  manifest,
104
109
  render,
105
110
  routes,
106
- onRendered
111
+ onRendered,
112
+ onTemplateRendered
107
113
  })
108
114
  break
109
115
  default:
@@ -5,7 +5,10 @@ import type { Server } from 'net'
5
5
  import fastify from 'fastify'
6
6
  import type { FastifyServerOptions } from 'fastify'
7
7
  import { fastifySsrPlugin } from '../frameworks/vue/fastify-ssr-plugin.js'
8
- import type { OnRenderedHook, VitrifyConfig } from '../vitrify-config.js'
8
+ import type {
9
+ OnTemplateRenderedHook,
10
+ VitrifyConfig
11
+ } from '../vitrify-config.js'
9
12
  import isPortReachable from 'is-port-reachable'
10
13
  import { exitLogs } from '../helpers/logger.js'
11
14
  import { fileURLToPath } from 'url'
@@ -138,7 +141,7 @@ export async function createServer({
138
141
  let setup
139
142
  let app: FastifyInstance | undefined
140
143
  let server: Server
141
- let onRendered: OnRenderedHook[]
144
+ let onTemplateRendered: OnTemplateRenderedHook[]
142
145
  let vitrifyConfig: VitrifyConfig
143
146
 
144
147
  console.log(`Development mode: ${ssr ? ssr : 'csr'}`)
@@ -149,7 +152,7 @@ export async function createServer({
149
152
  : fileURLToPath(new URL(`src/vite/${framework}/ssr/app.ts`, cliDir))
150
153
 
151
154
  const environment = vite.environments.ssr
152
- ;({ setup, onRendered, vitrifyConfig } =
155
+ ;({ setup, onTemplateRendered, vitrifyConfig } =
153
156
  // @ts-expect-error missing types
154
157
  await environment.runner.import(entryUrl))
155
158
  // console.log(module)
@@ -177,7 +180,7 @@ export async function createServer({
177
180
  await app.register(fastifySsrPlugin, {
178
181
  appDir,
179
182
  mode: 'development',
180
- onRendered,
183
+ onTemplateRendered,
181
184
  host
182
185
  })
183
186
  }
@@ -8,8 +8,14 @@ import {
8
8
  appendToHead
9
9
  } from '../../helpers/utils.js'
10
10
  import type { ViteDevServer } from 'vite'
11
- import type { OnRenderedHook } from '../../vitrify-config.js'
11
+ import type {
12
+ OnRenderedHook,
13
+ OnTemplateRenderedHook,
14
+ SSRContext
15
+ } from '../../vitrify-config.js'
12
16
  import { getAppDir } from '../../app-urls.js'
17
+ import { stringify } from 'devalue'
18
+ import stringifyObject from 'stringify-object'
13
19
 
14
20
  type ProvideFn = (
15
21
  req: FastifyRequest,
@@ -23,6 +29,7 @@ export interface FastifySsrOptions {
23
29
  vite?: ViteDevServer
24
30
  // frameworkDir?: URL
25
31
  onRendered?: OnRenderedHook[]
32
+ onTemplateRendered?: OnTemplateRenderedHook[]
26
33
  appDir?: URL
27
34
  publicDir?: URL
28
35
  mode?: string
@@ -92,11 +99,12 @@ const fastifySsrPlugin: FastifyPluginAsync<FastifySsrOptions> = async (
92
99
  }
93
100
 
94
101
  const html = await renderHtml({
95
- request: req,
96
- reply: res,
102
+ req,
103
+ res,
97
104
  url: url ?? '/',
98
105
  provide,
99
106
  onRendered: options.onRendered,
107
+ onTemplateRendered: options.onTemplateRendered,
100
108
  template,
101
109
  manifest,
102
110
  render
@@ -127,16 +135,18 @@ const fastifySsrPlugin: FastifyPluginAsync<FastifySsrOptions> = async (
127
135
  const url = req.raw.url?.replace(options.baseUrl!, '/')
128
136
  const provide = options.provide ? await options.provide(req, res) : {}
129
137
 
130
- const { template, manifest, render, onRendered } = await loadSSRAssets({
131
- distDir: new URL('./dist/', options.appDir)
132
- })
138
+ const { template, manifest, render, onRendered, onTemplateRendered } =
139
+ await loadSSRAssets({
140
+ distDir: new URL('./dist/', options.appDir)
141
+ })
133
142
 
134
143
  const html = await renderHtml({
135
- request: req,
136
- reply: res,
144
+ req,
145
+ res,
137
146
  url: url ?? '/',
138
147
  provide,
139
148
  onRendered,
149
+ onTemplateRendered,
140
150
  template,
141
151
  manifest,
142
152
  render
@@ -168,34 +178,77 @@ const renderTemplate = ({
168
178
 
169
179
  const renderHtml = async (options: {
170
180
  url: string
171
- request: FastifyRequest | { headers: Record<string, unknown>; url: string }
172
- reply: FastifyReply | Record<string, unknown>
181
+ req: FastifyRequest | { headers: Record<string, unknown>; url: string }
182
+ res: FastifyReply | Record<string, unknown>
173
183
  provide: Record<string, unknown>
174
184
  onRendered?: OnRenderedHook[]
185
+ onTemplateRendered?: OnTemplateRenderedHook[]
175
186
  template: string
176
187
  manifest: Record<string, unknown>
177
188
  render: any
178
189
  }) => {
179
- const ssrContext: Record<string, any> = {
180
- req: options.request,
181
- res: options.reply,
182
- provide: options.provide
190
+ const ssrContextOnRendered: (() => unknown)[] = []
191
+ const ssrContext: SSRContext = {
192
+ req: options.req,
193
+ res: options.res,
194
+ provide: options.provide,
195
+ initialState: {},
196
+ _modules: new Set(),
197
+ _meta: {},
198
+ __qMetaList: [],
199
+ onRenderedList: ssrContextOnRendered,
200
+ onRendered: (fn: () => unknown) => {
201
+ ssrContextOnRendered.push(fn)
202
+ }
183
203
  }
184
204
 
185
205
  const onRendered = options.onRendered ?? []
206
+ const onTemplateRendered = options.onTemplateRendered ?? []
186
207
 
187
- const [appHtml, preloadLinks] = await options.render(
188
- options.url,
189
- options.manifest,
190
- ssrContext
191
- )
208
+ const {
209
+ html: appHtml,
210
+ preloadLinks,
211
+ app
212
+ } = await options.render(options.url, options.manifest, ssrContext)
213
+
214
+ if (ssrContextOnRendered?.length) {
215
+ for (const ssrFunction of ssrContextOnRendered) {
216
+ await ssrFunction()
217
+ }
218
+ }
219
+
220
+ if (onRendered?.length) {
221
+ for (const ssrFunction of onRendered) {
222
+ await ssrFunction({ app, ssrContext })
223
+ }
224
+ }
192
225
 
193
- if (!ssrContext.initialState) ssrContext.initialState = {}
226
+ // if (!ssrContext.initialState) ssrContext.initialState = {}
194
227
  ssrContext.initialState.provide = options.provide
195
228
 
229
+ const ssrContextInitialStateStringified: Record<
230
+ keyof SSRContext['initialState'],
231
+ string
232
+ > = {}
233
+ for (const key in ssrContext.initialState) {
234
+ if (key === 'provide') {
235
+ ssrContextInitialStateStringified[key] = JSON.stringify(
236
+ ssrContext.initialState.provide
237
+ )
238
+ } else if (key === 'piniaColada') {
239
+ ssrContextInitialStateStringified[key] = JSON.stringify(
240
+ ssrContext.initialState.piniaColada
241
+ )
242
+ } else {
243
+ ssrContextInitialStateStringified[key] = stringify(
244
+ ssrContext.initialState[key]
245
+ )
246
+ }
247
+ }
248
+
196
249
  const initialStateScript = `
197
250
  <script>
198
- __INITIAL_STATE__ = '${JSON.stringify(ssrContext.initialState)}'
251
+ __INITIAL_STATE__ = ${stringifyObject(ssrContextInitialStateStringified)}
199
252
  </script>`
200
253
 
201
254
  let html = renderTemplate({
@@ -205,9 +258,9 @@ const renderHtml = async (options: {
205
258
  preloadLinks
206
259
  })
207
260
 
208
- if (onRendered?.length) {
209
- for (const ssrFunction of onRendered) {
210
- html = ssrFunction(html, ssrContext)
261
+ if (onTemplateRendered?.length) {
262
+ for (const ssrFunction of onTemplateRendered) {
263
+ html = await ssrFunction({ html, ssrContext })
211
264
  }
212
265
  }
213
266
 
@@ -229,7 +282,7 @@ const loadSSRAssets = async (
229
282
  const baseOutDir = distDir || new URL('dist/', appDir)
230
283
 
231
284
  let templatePath, manifestPath, entryServerPath
232
- const onRenderedPath = fileURLToPath(
285
+ const vitrifyHooksPath = fileURLToPath(
233
286
  new URL('ssr/server/virtual_vitrify-hooks.mjs', baseOutDir)
234
287
  )
235
288
  if (mode === 'ssg') {
@@ -254,14 +307,15 @@ const loadSSRAssets = async (
254
307
  const manifest = JSON.parse(readFileSync(manifestPath).toString())
255
308
  const entryServer = await import(entryServerPath)
256
309
  const { render, getRoutes } = entryServer
257
- const onRendered = (await import(onRenderedPath)).onRendered
310
+ const { onTemplateRendered, onRendered } = await import(vitrifyHooksPath)
258
311
 
259
312
  return {
260
313
  template,
261
314
  manifest,
262
315
  render,
263
316
  getRoutes,
264
- onRendered
317
+ onRendered,
318
+ onTemplateRendered
265
319
  }
266
320
  } catch (e) {
267
321
  console.error(e)
@@ -1,5 +1,5 @@
1
1
  import { existsSync, promises as fs, mkdirSync } from 'fs'
2
- import type { OnRenderedHook } from 'src/node/vitrify-config.js'
2
+ import type { OnTemplateRenderedHook } from 'src/node/vitrify-config.js'
3
3
  import { routesToPaths } from '../../helpers/routes.js'
4
4
  import { renderHtml } from './fastify-ssr-plugin.js'
5
5
  import { type RouteRecordRaw } from 'vue-router'
@@ -10,14 +10,14 @@ export const prerender = async ({
10
10
  manifest,
11
11
  render,
12
12
  routes,
13
- onRendered
13
+ onTemplateRendered
14
14
  }: {
15
15
  outDir: string
16
16
  template: string
17
17
  manifest: Record<string, unknown>
18
18
  render: unknown
19
19
  routes: RouteRecordRaw[]
20
- onRendered: OnRenderedHook[]
20
+ onTemplateRendered: OnTemplateRenderedHook[]
21
21
  }) => {
22
22
  const promises = []
23
23
  const paths = routesToPaths(routes).filter(
@@ -49,10 +49,10 @@ export const prerender = async ({
49
49
  manifest,
50
50
  provide: {},
51
51
  render,
52
- request: { headers: {}, url },
53
- reply: {},
52
+ req: { headers: {}, url },
53
+ res: {},
54
54
  template,
55
- onRendered
55
+ onTemplateRendered
56
56
  })
57
57
  html = await beasties.process(html)
58
58
 
@@ -1,6 +1,9 @@
1
- import type { FastifyInstance } from 'fastify'
2
1
  import fastify from 'fastify'
3
- import type { OnRenderedHook, OnSetupHook } from '../../vitrify-config.js'
2
+ import type {
3
+ OnTemplateRenderedHook,
4
+ OnSetupHook,
5
+ OnRenderedHook
6
+ } from '../../vitrify-config.js'
4
7
  import type { FastifyCsrPlugin } from './fastify-csr-plugin.js'
5
8
  import type { FastifySsrPlugin } from './fastify-ssr-plugin.js'
6
9
 
@@ -10,6 +13,7 @@ export const createApp = ({
10
13
  baseUrl,
11
14
  fastifyPlugin,
12
15
  onRendered,
16
+ onTemplateRendered,
13
17
  vitrifyDir,
14
18
  mode
15
19
  }: {
@@ -18,6 +22,7 @@ export const createApp = ({
18
22
  baseUrl?: string
19
23
  fastifyPlugin: FastifySsrPlugin | FastifyCsrPlugin
20
24
  onRendered?: OnRenderedHook[]
25
+ onTemplateRendered?: OnTemplateRenderedHook[]
21
26
  vitrifyDir?: URL
22
27
  mode: string
23
28
  }) => {
@@ -35,6 +40,7 @@ export const createApp = ({
35
40
  appDir,
36
41
  vitrifyDir,
37
42
  onRendered,
43
+ onTemplateRendered,
38
44
  mode
39
45
  })
40
46
 
@@ -0,0 +1,19 @@
1
+ import type {
2
+ OnBootHook,
3
+ onAppCreatedHook,
4
+ OnMountedHook,
5
+ OnRenderedHook,
6
+ OnTemplateRenderedHook,
7
+ OnSetupFile,
8
+ OnSetupHook
9
+ } from '../vitrify-config.js'
10
+
11
+ export {
12
+ OnBootHook,
13
+ onAppCreatedHook,
14
+ OnMountedHook,
15
+ OnRenderedHook,
16
+ OnTemplateRenderedHook,
17
+ OnSetupFile,
18
+ OnSetupHook
19
+ }
package/src/node/index.ts CHANGED
@@ -17,7 +17,6 @@ import { visualizer } from 'rollup-plugin-visualizer'
17
17
  import { fileURLToPath } from 'url'
18
18
  import type {
19
19
  StaticImports,
20
- BootFunction,
21
20
  OnMountedHook,
22
21
  VitrifyConfig,
23
22
  VitrifyConfigAsync,
@@ -27,7 +26,9 @@ import type {
27
26
  VitrifySSRModes,
28
27
  OnRenderedHook,
29
28
  OnBootHook,
30
- OnSetupFile
29
+ OnSetupFile,
30
+ onAppCreatedHook,
31
+ OnTemplateRenderedHook
31
32
  } from './vitrify-config.js'
32
33
  import type { VitrifyContext } from './bin/run.js'
33
34
  import type { VitrifyPlugin } from './plugins/index.js'
@@ -63,7 +64,7 @@ const manualChunkNames = [
63
64
  ]
64
65
 
65
66
  const moduleChunks = {
66
- vue: ['vue', '@vue', 'vue-router'],
67
+ vue: ['vue', '@vue', 'vue-router', 'pinia', '@pinia/colada', '@vue/devtools'],
67
68
  quasar: ['quasar'],
68
69
  atQuasar: ['@quasar']
69
70
  }
@@ -279,7 +280,9 @@ export const baseConfig = async ({
279
280
 
280
281
  let onBootHooks: OnBootHook[]
281
282
  let onRenderedHooks: OnRenderedHook[]
283
+ let onTemplateRenderedHooks: OnTemplateRenderedHook[]
282
284
  let onMountedHooks: OnMountedHook[]
285
+ let onAppCreatedHooks: onAppCreatedHook[]
283
286
  let onSetupFiles: OnSetupFile[]
284
287
  let globalCss: string[] = []
285
288
  let staticImports: StaticImports
@@ -357,7 +360,10 @@ export const baseConfig = async ({
357
360
  config: (config: VitrifyConfig, env) => {
358
361
  onBootHooks = config.vitrify?.hooks?.onBoot || []
359
362
  onRenderedHooks = config.vitrify?.hooks?.onRendered || []
363
+ onTemplateRenderedHooks =
364
+ config.vitrify?.hooks?.onTemplateRendered || []
360
365
  onMountedHooks = config.vitrify?.hooks?.onMounted || []
366
+ onAppCreatedHooks = config.vitrify?.hooks?.onAppCreated || []
361
367
  onSetupFiles = config?.vitrify?.hooks?.onSetup || []
362
368
  globalCss = config.vitrify?.globalCss || []
363
369
  staticImports = config.vitrify?.staticImports || {}
@@ -395,6 +401,12 @@ export const baseConfig = async ({
395
401
  export const onRendered = [${onRenderedHooks
396
402
  .map((fn) => `${String(fn)}`)
397
403
  .join(', ')}]
404
+ export const onTemplateRendered = [${onTemplateRenderedHooks
405
+ .map((fn) => `${String(fn)}`)
406
+ .join(', ')}]
407
+ export const onAppCreated = [${onAppCreatedHooks
408
+ .map((fn) => `${String(fn)}`)
409
+ .join(', ')}]
398
410
  export const onSetup = []
399
411
  ${onSetupFiles
400
412
  .map((url, index) => {
@@ -726,5 +738,5 @@ export type {
726
738
  VitrifyConfigAsync,
727
739
  VitrifyPlugin,
728
740
  VitrifyContext,
729
- BootFunction
741
+ OnBootHook
730
742
  }
@@ -26,3 +26,4 @@ export type VitrifyPlugin<Options> = ({
26
26
  }) => Promise<VitrifyPluginReturnType> | VitrifyPluginReturnType
27
27
 
28
28
  export * from './quasar/index.js'
29
+ export * from './pinia/index.js'
@@ -0,0 +1,96 @@
1
+ import type { onAppCreatedHook, OnRenderedHook } from '../../vitrify-config.js'
2
+ import type { VitrifyPlugin } from '../index.js'
3
+
4
+ export type PiniaPluginOptions = {
5
+ // Initialize Pinia Colada
6
+ colada?: boolean
7
+ }
8
+
9
+ const piniaonAppCreated: onAppCreatedHook = async ({
10
+ app,
11
+ ctx,
12
+ initialState,
13
+ ssrContext
14
+ }) => {
15
+ const { createPinia } = await import('pinia')
16
+ const pinia = createPinia()
17
+ ctx.pinia = pinia
18
+ app.use(pinia)
19
+
20
+ // SSR Client
21
+ if (initialState?.pinia) pinia.state.value = initialState.pinia
22
+ // SSR Server
23
+ if (ssrContext) ssrContext.pinia = pinia
24
+ }
25
+
26
+ const piniaOnRenderedHook: OnRenderedHook = ({ app, ssrContext }) => {
27
+ // SSR Server
28
+ if (ssrContext?.initialState && ssrContext.pinia) {
29
+ ssrContext.initialState.pinia = ssrContext.pinia.state.value
30
+ }
31
+ }
32
+
33
+ const piniaColadaonAppCreated: onAppCreatedHook = async ({
34
+ app,
35
+ ctx,
36
+ initialState
37
+ }) => {
38
+ if (ctx?.pinia) {
39
+ const { PiniaColada, useQueryCache, hydrateQueryCache } = await import(
40
+ '@pinia/colada'
41
+ )
42
+
43
+ app.use(PiniaColada)
44
+
45
+ // SSR Client
46
+ if (initialState?.piniaColada) {
47
+ hydrateQueryCache(useQueryCache(ctx.pinia), initialState.piniaColada)
48
+ }
49
+ }
50
+ }
51
+
52
+ const piniaColadaOnRenderedHook: OnRenderedHook = async ({
53
+ app,
54
+ ssrContext
55
+ }) => {
56
+ // SSR Server
57
+ if (ssrContext?.initialState && ssrContext.pinia) {
58
+ const { useQueryCache, serializeQueryCache } = await import('@pinia/colada')
59
+
60
+ // Delete to prevent Non-POJO error
61
+ if (ssrContext.initialState.pinia?._pc_query) {
62
+ delete ssrContext.initialState.pinia._pc_query
63
+ }
64
+ ssrContext.initialState.piniaColada = serializeQueryCache(
65
+ useQueryCache(ssrContext.pinia)
66
+ )
67
+ }
68
+ }
69
+
70
+ export const PiniaPlugin: VitrifyPlugin<PiniaPluginOptions> = async ({
71
+ ssr = false,
72
+ pwa = false,
73
+ options = {}
74
+ }) => {
75
+ const onAppCreated = [piniaonAppCreated]
76
+ const onRendered = [piniaOnRenderedHook]
77
+ if (options.colada) {
78
+ onAppCreated.push(piniaColadaonAppCreated)
79
+ onRendered.push(piniaColadaOnRenderedHook)
80
+ }
81
+
82
+ return {
83
+ plugins: [],
84
+ config: {
85
+ vitrify: {
86
+ ssr: {
87
+ serverModules: ['@pinia/colada']
88
+ },
89
+ hooks: {
90
+ onAppCreated,
91
+ onRendered
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }