vitrify 0.21.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 (39) hide show
  1. package/dist/bin/cli.js +3 -3
  2. package/dist/bin/dev.js +26 -39
  3. package/dist/frameworks/vue/fastify-ssr-plugin.js +58 -19
  4. package/dist/frameworks/vue/prerender.js +4 -4
  5. package/dist/frameworks/vue/server.js +5 -1
  6. package/dist/hooks/index.js +1 -0
  7. package/dist/index.js +80 -94
  8. package/dist/plugins/index.js +2 -1
  9. package/dist/plugins/pinia/index.js +61 -0
  10. package/dist/plugins/quasar/index.js +226 -0
  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 +13 -2
  17. package/dist/types/plugins/pinia/index.d.ts +5 -0
  18. package/dist/types/plugins/{quasar.d.ts → quasar/index.d.ts} +5 -5
  19. package/dist/types/vitrify-config.d.ts +87 -12
  20. package/package.json +37 -25
  21. package/src/node/bin/cli.ts +13 -7
  22. package/src/node/bin/dev.ts +30 -41
  23. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +85 -28
  24. package/src/node/frameworks/vue/prerender.ts +6 -6
  25. package/src/node/frameworks/vue/server.ts +11 -2
  26. package/src/node/hooks/index.ts +19 -0
  27. package/src/node/index.ts +114 -130
  28. package/src/node/plugins/index.ts +20 -3
  29. package/src/node/plugins/pinia/index.ts +96 -0
  30. package/src/node/plugins/quasar/index.ts +318 -0
  31. package/src/node/vitrify-config.ts +120 -21
  32. package/src/vite/fastify/server.ts +3 -0
  33. package/src/vite/vue/RootComponent.vue +1 -1
  34. package/src/vite/vue/main.ts +52 -22
  35. package/src/vite/vue/ssr/app.ts +3 -2
  36. package/src/vite/vue/ssr/entry-server.ts +22 -41
  37. package/src/vite/vue/ssr/prerender.ts +2 -2
  38. package/dist/plugins/quasar.js +0 -217
  39. package/src/node/plugins/quasar.ts +0 -307
@@ -0,0 +1,318 @@
1
+ import { fileURLToPath } from 'url'
2
+ import type {
3
+ OnBootHook,
4
+ OnMountedHook,
5
+ OnTemplateRenderedHook,
6
+ VitrifyConfig
7
+ } from '../../vitrify-config.js'
8
+ import type { VitrifyPlugin } from '../index.js'
9
+ import { findDepPkgJsonPath } from 'vitefu'
10
+ import {
11
+ type QuasarFonts,
12
+ type QuasarComponents,
13
+ type QuasarDirectives,
14
+ type QuasarIconSets,
15
+ type QuasarPlugins,
16
+ type GlobalQuasarIconMapFn,
17
+ type QuasarIconSet
18
+ } from 'quasar'
19
+ import { QuasarResolver } from 'unplugin-vue-components/resolvers'
20
+
21
+ export interface QuasarPluginOptions {
22
+ framework: {
23
+ components?: (keyof QuasarComponents)[]
24
+ directives?: (keyof QuasarDirectives)[]
25
+ plugins?: (keyof QuasarPlugins)[]
26
+ lang?: string
27
+ iconSet?: QuasarIconSets | QuasarIconSet
28
+ iconMapFn?: GlobalQuasarIconMapFn
29
+ }
30
+ extras?: (QuasarIconSets | QuasarFonts)[]
31
+ disableSass?: boolean
32
+ }
33
+
34
+ export const injectSsrContext: OnTemplateRenderedHook = ({
35
+ html,
36
+ ssrContext
37
+ }) =>
38
+ html
39
+ .replace(/(<html[^>]*)(>)/i, (found, start, end) => {
40
+ let matches
41
+
42
+ matches = found.match(/\sdir\s*=\s*['"]([^'"]*)['"]/i)
43
+ if (matches) {
44
+ start = start.replace(matches[0], '')
45
+ }
46
+
47
+ matches = found.match(/\slang\s*=\s*['"]([^'"]*)['"]/i)
48
+ if (matches) {
49
+ start = start.replace(matches[0], '')
50
+ }
51
+
52
+ return `${start} ${ssrContext?._meta.htmlAttrs || ''} ${end}`
53
+ })
54
+ .replace(
55
+ /(<head[^>]*)(>)/i,
56
+ (_, start, end) => `${start}${end}${ssrContext?._meta.headTags || ''}`
57
+ )
58
+ .replace(
59
+ /(<\/head>)/i,
60
+ (_, tag) =>
61
+ `${ssrContext?._meta.resourceStyles || ''}${
62
+ ssrContext?._meta.endingHeadTags || ''
63
+ }${tag}`
64
+ )
65
+ .replace(/(<body[^>]*)(>)/i, (found, start, end) => {
66
+ let classes = ssrContext?._meta.bodyClasses || ''
67
+
68
+ const matches = found.match(/\sclass\s*=\s*['"]([^'"]*)['"]/i)
69
+
70
+ if (matches) {
71
+ if (matches[1].length > 0) {
72
+ classes += ` ${matches[1]}`
73
+ }
74
+ start = start.replace(matches[0], '')
75
+ }
76
+
77
+ return `${start} class="${classes.trim()}" ${
78
+ ssrContext?._meta.bodyAttrs || ''
79
+ }${end}${ssrContext?._meta.bodyTags || ''}`
80
+ })
81
+
82
+ export const QuasarPlugin: VitrifyPlugin<QuasarPluginOptions> = async ({
83
+ ssr = false,
84
+ pwa = false,
85
+ options
86
+ }) => {
87
+ let plugins: string[] = []
88
+ const quasarConf: QuasarPluginOptions = options
89
+ return {
90
+ plugins: [
91
+ {
92
+ name: 'vite-plugin-quasar-transform',
93
+ enforce: 'pre',
94
+ transform: (code, id, options) => {
95
+ code = code
96
+ .replaceAll('__QUASAR_SSR__', ssr ? 'true' : 'false')
97
+ .replaceAll(
98
+ '__QUASAR_SSR_SERVER__',
99
+ ssr ? '(import.meta.env.SSR === true)' : 'false'
100
+ )
101
+ .replaceAll(
102
+ '__QUASAR_SSR_CLIENT__',
103
+ ssr ? '(import.meta.env.SSR === false)' : 'false'
104
+ )
105
+ .replaceAll(
106
+ '__QUASAR_SSR_PWA__',
107
+ ssr && pwa ? '(import.meta.env.SSR === false)' : 'false'
108
+ )
109
+
110
+ return code
111
+ }
112
+ },
113
+ {
114
+ name: 'vite-plugin-quasar-setup',
115
+ enforce: 'pre',
116
+ config: async (config: VitrifyConfig, env): Promise<VitrifyConfig> => {
117
+ const { vitrify: { urls } = {} } = config
118
+
119
+ // if (quasar) quasarConf = quasar
120
+ if (!quasarConf.framework.lang && config.vitrify?.lang)
121
+ quasarConf.framework.lang = config.vitrify.lang
122
+
123
+ const globalCss = quasarConf?.extras?.map(
124
+ (extra) => `@quasar/extras/${extra}/${extra}.css`
125
+ )
126
+
127
+ const localPackages = ['@quasar/extras', 'quasar']
128
+ // const localPackages: string[] = []
129
+ await (async () => {
130
+ for (const val of localPackages) {
131
+ const pkgDir = await findDepPkgJsonPath(
132
+ val,
133
+ fileURLToPath(config.vitrify!.urls!.app!)
134
+ )
135
+ if (pkgDir) urls!.packages![val] = new URL(`file://${pkgDir}`)
136
+ }
137
+ })()
138
+
139
+ const onMountedHooks: OnMountedHook[] = [
140
+ async (instance) => {
141
+ const {
142
+ proxy: { $q }
143
+ } = instance
144
+ if ($q.onSSRHydrated !== void 0) $q.onSSRHydrated()
145
+ }
146
+ ]
147
+
148
+ const onBootHooks: OnBootHook[] = [
149
+ async ({ app, ssrContext, staticImports }) => {
150
+ // @ts-expect-error undefined
151
+ const quasarPlugins = await import('virtual:quasar-plugins')
152
+ // @ts-expect-error undefined
153
+ const directives = await import('virtual:quasar-directives')
154
+ // @ts-expect-error undefined
155
+ const { default: lang } = await import('virtual:quasar-lang')
156
+ const { default: iconSet } = await import(
157
+ // @ts-expect-error undefined
158
+ 'virtual:quasar-iconSet'
159
+ )
160
+ const { default: iconMapFn } = await import(
161
+ // @ts-expect-error undefined
162
+ 'virtual:quasar-iconMapFn'
163
+ )
164
+
165
+ app.use(
166
+ staticImports?.Quasar,
167
+ {
168
+ plugins: quasarPlugins,
169
+ directives,
170
+ lang,
171
+ iconSet,
172
+ config: {
173
+ iconMapFn
174
+ }
175
+ },
176
+ ssrContext
177
+ )
178
+ }
179
+ ]
180
+
181
+ /**
182
+ * Importing package.json is problematic
183
+ */
184
+ const version = '?'
185
+
186
+ /**
187
+ * All components should have been auto-imported
188
+ */
189
+ if (quasarConf?.framework?.plugins) {
190
+ if (!quasarConf.framework) quasarConf.framework = {}
191
+ quasarConf.framework.plugins = [
192
+ ...new Set(quasarConf.framework.plugins)
193
+ ]
194
+ plugins = quasarConf?.framework.plugins
195
+ }
196
+
197
+ return {
198
+ vitrify: {
199
+ urls,
200
+ globalCss,
201
+ staticImports: {
202
+ quasar: ['Quasar']
203
+ },
204
+ hooks: {
205
+ onBoot: onBootHooks,
206
+ onMounted: onMountedHooks,
207
+ onTemplateRendered: [injectSsrContext]
208
+ },
209
+ sass: quasarConf.disableSass
210
+ ? undefined
211
+ : {
212
+ global: ['quasar/src/css/index.sass']
213
+ }
214
+ },
215
+ resolve: {
216
+ alias: [
217
+ {
218
+ find: 'quasar/src/',
219
+ replacement: fileURLToPath(
220
+ new URL('./src/', config.vitrify!.urls!.packages!.quasar)
221
+ )
222
+ }
223
+ ]
224
+ },
225
+ optimizeDeps: {
226
+ exclude: ['quasar']
227
+ },
228
+ define: {
229
+ __DEV__: process.env.NODE_ENV !== 'production' || true,
230
+ __QUASAR_VERSION__: `'${version}'`
231
+ },
232
+ ssr: {
233
+ noExternal: ['quasar']
234
+ }
235
+ }
236
+ }
237
+ },
238
+ {
239
+ name: 'quasar-virtual-modules',
240
+ enforce: 'pre',
241
+ config: async (config, env) => ({
242
+ resolve: {
243
+ alias: [
244
+ {
245
+ find: new RegExp('^quasar$'),
246
+ replacement: 'virtual:quasar'
247
+ }
248
+ // { find: new RegExp('^quasar$'), replacement: 'virtual:quasar' }
249
+ ]
250
+ }
251
+ }),
252
+ resolveId(id) {
253
+ switch (id) {
254
+ case 'virtual:quasar-plugins':
255
+ return 'virtual:quasar-plugins'
256
+ case 'virtual:quasar-directives':
257
+ return 'virtual:quasar-directives'
258
+ case 'virtual:quasar-lang':
259
+ return 'virtual:quasar-lang'
260
+ case 'virtual:quasar-iconSet':
261
+ return 'virtual:quasar-iconSet'
262
+ case 'virtual:quasar-iconMapFn':
263
+ return 'virtual:quasar-iconMapFn'
264
+ case 'virtual:quasar':
265
+ return { id: 'virtual:quasar', moduleSideEffects: false }
266
+ default:
267
+ return
268
+ }
269
+ },
270
+ load(id) {
271
+ if (id === 'virtual:quasar-plugins') {
272
+ return `export { ${plugins.join(',')} } from 'quasar'`
273
+ } else if (id === 'virtual:quasar-directives') {
274
+ return `export * from 'quasar/src/directives.js'`
275
+ } else if (id === 'virtual:quasar-lang') {
276
+ return `import lang from 'quasar/lang/${
277
+ quasarConf?.framework?.lang || 'en-US'
278
+ }';
279
+ export default lang`
280
+ } else if (id === 'virtual:quasar-iconSet') {
281
+ return `${
282
+ typeof quasarConf.framework.iconSet === 'string'
283
+ ? `import iconSet from 'quasar/icon-set/${
284
+ quasarConf?.framework.iconSet || 'material-icons'
285
+ }';
286
+ export default iconSet`
287
+ : `export default ${
288
+ quasarConf.framework.iconSet
289
+ ? JSON.stringify(quasarConf.framework.iconSet)
290
+ : null
291
+ }`
292
+ }`
293
+ } else if (id === 'virtual:quasar-iconMapFn') {
294
+ return `export default ${
295
+ quasarConf?.framework.iconMapFn?.toString() ?? null
296
+ }`
297
+ } else if (id === 'virtual:quasar') {
298
+ return `export * from 'quasar/src/plugins.js';
299
+ export * from 'quasar/src/components.js';
300
+ export * from 'quasar/src/composables.js';
301
+ export * from 'quasar/src/directives.js';
302
+ export * from 'quasar/src/utils.js';
303
+ export * from 'quasar/src/composables.js';
304
+ export { default as Quasar } from 'quasar/src/install-quasar.js'`
305
+ }
306
+ return null
307
+ }
308
+ }
309
+ ],
310
+ config: {
311
+ vitrify: {
312
+ unpluginVueComponents: {
313
+ resolvers: [QuasarResolver()]
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
@@ -1,51 +1,133 @@
1
1
  import type { Alias, UserConfig as ViteUserConfig, ViteDevServer } from 'vite'
2
- import type { QuasarConf } from './plugins/quasar.js'
3
2
  import type { ComponentInternalInstance } from '@vue/runtime-core'
4
- import type { FastifyInstance, FastifyServerOptions } from 'fastify'
3
+ import type {
4
+ FastifyInstance,
5
+ FastifyReply,
6
+ FastifyRequest,
7
+ FastifyServerOptions
8
+ } from 'fastify'
5
9
  import type { VitePWAOptions } from 'vite-plugin-pwa'
6
- import { ComponentResolver } from 'unplugin-vue-components'
10
+ import type { Options as unpluginVueComponentsOptions } from 'unplugin-vue-components'
7
11
  import type { UserConfig as UnoCSSUserConfig } from '@unocss/core'
12
+ import type { VitrifyPlugin } from './plugins/index.js'
13
+ import type { Router } from 'vue-router'
14
+ import type { App } from '@vue/runtime-core'
15
+ import type { Pinia } from 'pinia'
16
+ import type { _UseQueryEntryNodeValueSerialized } from '@pinia/colada/index.js'
8
17
 
9
- export type BootFunction = ({
18
+ export type SSRContext = {
19
+ // Quasar requires req and res on SSRContext instead of request and reply
20
+ req:
21
+ | FastifyRequest
22
+ | {
23
+ headers: Record<string, unknown>
24
+ url: string
25
+ }
26
+ res: FastifyReply | Record<string, unknown>
27
+ provide: Record<string, unknown>
28
+ initialState: {
29
+ provide?: Record<string, unknown>
30
+ pinia?: Record<string, unknown>
31
+ piniaColada?: Record<string, _UseQueryEntryNodeValueSerialized>
32
+ [key: string]: unknown
33
+ }
34
+ pinia?: Pinia
35
+ // Quasar internals
36
+ _modules: Set<unknown>
37
+ _meta: Record<string, any>
38
+ __qMetaList: unknown[]
39
+ /**
40
+ * Required for Quasar
41
+ */
42
+ onRenderedList: (() => unknown)[]
43
+ onRendered: (fn: () => unknown) => void
44
+ /**
45
+ * Vue internals
46
+ */
47
+ modules?: Map<unknown, unknown>
48
+ transports?: Record<string, unknown>
49
+ [key: string]: unknown
50
+ }
51
+
52
+ export type onAppCreatedHook = ({
10
53
  app,
11
- ssrContext,
12
- staticImports
54
+ router,
55
+ ctx,
56
+ initialState,
57
+ ssrContext
13
58
  }: {
14
- app: any
15
- ssrContext: Record<string, unknown>
16
- staticImports: Record<string, any>
59
+ app: App
60
+ router: Router
61
+ ctx: {
62
+ pinia?: Pinia
63
+ [key: string]: unknown
64
+ }
65
+ initialState: {
66
+ provide?: Record<string, unknown>
67
+ pinia?: Record<string, unknown>
68
+ piniaColada?: Record<string, _UseQueryEntryNodeValueSerialized>
69
+ [key: string]: unknown
70
+ }
71
+ ssrContext?: SSRContext
17
72
  }) => Promise<void> | void
73
+
18
74
  export type OnBootHook = ({
19
75
  app,
20
76
  ssrContext,
21
77
  staticImports
22
78
  }: {
23
- app: any
24
- ssrContext: Record<string, unknown>
79
+ app: App
80
+ ssrContext: SSRContext
25
81
  staticImports?: Record<string, any>
26
82
  }) => Promise<void> | void
83
+
27
84
  export type OnMountedHook = (
28
85
  instance: ComponentInternalInstance
29
86
  ) => Promise<void> | void
30
87
  export type StaticImports = Record<string, string[]>
31
- export type SsrFunction = (
32
- html: string,
33
- ssrContext: Record<string, any>
34
- ) => string
35
- export type OnRenderedHook = (
36
- html: string,
37
- ssrContext: Record<string, any>
38
- ) => string
88
+
89
+ export type OnSetupFile = URL
39
90
  export type OnSetupHook = (
40
91
  fastify: FastifyInstance,
41
92
  options?: {
42
93
  vite?: ViteDevServer
43
94
  }
44
95
  ) => any
45
- export type OnSetupFile = URL
96
+
97
+ export type Render = (
98
+ url: string,
99
+ manifest: Record<string, unknown>,
100
+ ssrContext: SSRContext,
101
+ renderToString: (app: App, ctx?: Record<string, any>) => Promise<string>
102
+ ) => Promise<{
103
+ html: string
104
+ preloadLinks: string
105
+ app: App
106
+ }>
107
+
108
+ export type OnRenderedHook = ({
109
+ app,
110
+ ssrContext
111
+ }: {
112
+ app: App
113
+ ssrContext?: SSRContext
114
+ }) => Promise<void> | void
115
+
116
+ export type OnTemplateRenderedHook = ({
117
+ html,
118
+ ssrContext
119
+ }: {
120
+ html: string
121
+ ssrContext?: SSRContext
122
+ }) => Promise<string> | string
123
+
46
124
  export interface VitrifyConfig extends ViteUserConfig {
47
125
  vitrify?: {
48
126
  lang?: string
127
+ /**
128
+ * Vitrify plugins
129
+ */
130
+ plugins?: VitrifyPluginConfig[]
49
131
  /**
50
132
  * Global CSS imports
51
133
  */
@@ -71,6 +153,14 @@ export interface VitrifyConfig extends ViteUserConfig {
71
153
  * Functions which run after rendering the app (SSR)
72
154
  */
73
155
  onRendered?: OnRenderedHook[]
156
+ /**
157
+ * Functions which run after rendering the template (SSR)
158
+ */
159
+ onTemplateRendered?: OnTemplateRenderedHook[]
160
+ /**
161
+ * Functions which run directly after initializing the application
162
+ */
163
+ onAppCreated?: onAppCreatedHook[]
74
164
  }
75
165
  /**
76
166
  * Global SASS variables
@@ -118,8 +208,12 @@ export interface VitrifyConfig extends ViteUserConfig {
118
208
  * UnoCSS Configuration
119
209
  */
120
210
  unocss?: UnoCSSUserConfig
211
+ /**
212
+ * unplugin-vue-components configuration
213
+ */
214
+ unpluginVueComponents?: unpluginVueComponentsOptions
121
215
  }
122
- quasar?: QuasarConf
216
+ // quasar?: QuasarConf
123
217
  }
124
218
 
125
219
  export type VitrifyCommands = 'build' | 'dev' | 'test'
@@ -135,4 +229,9 @@ export type VitrifyConfigAsync = ({
135
229
  command: VitrifyCommands
136
230
  }) => Promise<VitrifyConfig>
137
231
 
232
+ type VitrifyPluginConfig = {
233
+ plugin: VitrifyPlugin<any>
234
+ options: any
235
+ }
236
+
138
237
  export const defineConfig = (config: VitrifyConfig) => config
@@ -3,6 +3,9 @@ import { setup, vitrifyConfig } from './entry'
3
3
 
4
4
  const fastify = Fastify({
5
5
  logger: {
6
+ transport: {
7
+ target: '@fastify/one-line-logger'
8
+ },
6
9
  level: process.env.DEBUG ? 'debug' : 'info'
7
10
  },
8
11
  ...vitrifyConfig.vitrify?.ssr.fastify
@@ -8,7 +8,7 @@ import {
8
8
  onMounted as onMountedVue,
9
9
  getCurrentInstance
10
10
  } from 'vue'
11
- import { onBoot, onMounted } from 'virtual:vitrify-hooks'
11
+ import { onMounted } from 'virtual:vitrify-hooks'
12
12
  import * as staticImports from 'virtual:static-imports'
13
13
  import App from 'src/App.vue'
14
14
  // import 'vitrify.sass'
@@ -1,14 +1,18 @@
1
1
  import createRouter from 'src/router'
2
- import { createSSRApp, createApp as createVueApp, ref } from 'vue'
3
- import { onBoot } from 'virtual:vitrify-hooks'
2
+ import { App, createSSRApp, createApp as createVueApp, ref } from 'vue'
3
+ import { onBoot, onAppCreated } from 'virtual:vitrify-hooks'
4
4
  import routes from 'src/router/routes'
5
5
  import * as staticImports from 'virtual:static-imports'
6
6
  import 'virtual:uno.css'
7
-
8
7
  import RootComponent from './RootComponent.vue'
9
- interface ssrContext {
10
- provide?: Record<string, unknown>
11
- [key: string]: unknown
8
+ import { parse } from 'devalue'
9
+ import type { SSRContext } from '../../node/vitrify-config'
10
+ import type { Pinia } from 'pinia'
11
+
12
+ declare global {
13
+ interface Window {
14
+ __INITIAL_STATE__: any
15
+ }
12
16
  }
13
17
 
14
18
  function capitalizeFirstLetter(string: string) {
@@ -17,18 +21,58 @@ function capitalizeFirstLetter(string: string) {
17
21
 
18
22
  export async function createApp(
19
23
  ssr?: 'client' | 'server',
20
- ssrContext?: ssrContext
24
+ ssrContext?: SSRContext
21
25
  ) {
22
- let app
26
+ let initialState: Record<string, any> | null = null
27
+
28
+ if (!import.meta.env.SSR && window?.__INITIAL_STATE__) {
29
+ initialState = window.__INITIAL_STATE__
30
+
31
+ for (const key in initialState) {
32
+ if (key === 'provide' || key === 'piniaColada') {
33
+ initialState[key] = JSON.parse(initialState[key])
34
+ } else {
35
+ initialState[key] = parse(initialState[key], {
36
+ PiniaColada_TreeMapNode: (data) => data
37
+ })
38
+ }
39
+ }
40
+ }
41
+
42
+ // Delete for security reasons
43
+ if (!import.meta.env.SSR && window.__INITIAL_STATE__)
44
+ delete window.__INITIAL_STATE__
45
+
46
+ let provide: Record<string, any> = {}
47
+ if (import.meta.env.SSR) {
48
+ if (ssrContext?.provide) {
49
+ provide = ssrContext?.provide
50
+ }
51
+ } else {
52
+ if (initialState) {
53
+ provide = initialState.provide
54
+ }
55
+ }
56
+
57
+ let app: App
58
+ const ctx: {
59
+ pinia?: Pinia
60
+ [key: string]: unknown
61
+ } = {}
23
62
 
24
63
  if (ssr) {
25
64
  app = createSSRApp(RootComponent)
26
65
  } else {
27
66
  app = createVueApp(RootComponent)
28
67
  }
68
+
29
69
  const router = createRouter()
30
70
  app.use(router)
31
71
 
72
+ for (const fn of onAppCreated) {
73
+ await fn({ app, router, ctx, initialState, ssrContext })
74
+ }
75
+
32
76
  // Workaround to fix hydration errors when serving html files directly
33
77
  router.beforeEach((to, from, next) => {
34
78
  if (to.path.endsWith('.html')) {
@@ -38,20 +82,6 @@ export async function createApp(
38
82
  next()
39
83
  })
40
84
 
41
- let initialState: Record<string, any>
42
- let provide: Record<string, any> = {}
43
- if (import.meta.env.SSR) {
44
- if (ssrContext?.provide) {
45
- provide = ssrContext?.provide
46
- }
47
- } else {
48
- // @ts-expect-error undefined
49
- if (window.__INITIAL_STATE__) {
50
- // @ts-expect-error undefined
51
- initialState = JSON.parse(window.__INITIAL_STATE__)
52
- provide = initialState.provide
53
- }
54
- }
55
85
  for (const key in provide) {
56
86
  if (provide[key]?.value) {
57
87
  const refValue = ref(provide[key].value)
@@ -1,6 +1,6 @@
1
1
  import { createApp } from '../../../node/frameworks/vue/server.js'
2
2
  import { getAppDir } from '../../../node/app-urls.js'
3
- import { onSetup, onRendered } from 'virtual:vitrify-hooks'
3
+ import { onSetup, onRendered, onTemplateRendered } from 'virtual:vitrify-hooks'
4
4
  import { fastifySsrPlugin } from './fastify-ssr-plugin.js'
5
5
 
6
6
  const getString = (str?: string) => str
@@ -14,9 +14,10 @@ export const setupApp = async () => {
14
14
  baseUrl,
15
15
  fastifyPlugin: fastifySsrPlugin,
16
16
  onRendered,
17
+ onTemplateRendered,
17
18
  mode: import.meta.env.MODE
18
19
  })
19
20
  }
20
21
 
21
22
  export { default as vitrifyConfig } from 'virtual:vitrify-config'
22
- export { onRendered }
23
+ export { onRendered, onTemplateRendered }