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
@@ -1,8 +1,8 @@
1
- import type { Plugin } from 'vite'
2
1
  import { fileURLToPath } from 'url'
3
2
  import type {
4
3
  OnBootHook,
5
4
  OnMountedHook,
5
+ OnTemplateRenderedHook,
6
6
  VitrifyConfig
7
7
  } from '../../vitrify-config.js'
8
8
  import type { VitrifyPlugin } from '../index.js'
@@ -31,10 +31,10 @@ export interface QuasarPluginOptions {
31
31
  disableSass?: boolean
32
32
  }
33
33
 
34
- export const injectSsrContext = (
35
- html: string,
36
- ssrContext: Record<string, any>
37
- ) =>
34
+ export const injectSsrContext: OnTemplateRenderedHook = ({
35
+ html,
36
+ ssrContext
37
+ }) =>
38
38
  html
39
39
  .replace(/(<html[^>]*)(>)/i, (found, start, end) => {
40
40
  let matches
@@ -49,21 +49,21 @@ export const injectSsrContext = (
49
49
  start = start.replace(matches[0], '')
50
50
  }
51
51
 
52
- return `${start} ${ssrContext._meta.htmlAttrs || ''} ${end}`
52
+ return `${start} ${ssrContext?._meta.htmlAttrs || ''} ${end}`
53
53
  })
54
54
  .replace(
55
55
  /(<head[^>]*)(>)/i,
56
- (_, start, end) => `${start}${end}${ssrContext._meta.headTags || ''}`
56
+ (_, start, end) => `${start}${end}${ssrContext?._meta.headTags || ''}`
57
57
  )
58
58
  .replace(
59
59
  /(<\/head>)/i,
60
60
  (_, tag) =>
61
- `${ssrContext._meta.resourceStyles || ''}${
62
- ssrContext._meta.endingHeadTags || ''
61
+ `${ssrContext?._meta.resourceStyles || ''}${
62
+ ssrContext?._meta.endingHeadTags || ''
63
63
  }${tag}`
64
64
  )
65
65
  .replace(/(<body[^>]*)(>)/i, (found, start, end) => {
66
- let classes = ssrContext._meta.bodyClasses || ''
66
+ let classes = ssrContext?._meta.bodyClasses || ''
67
67
 
68
68
  const matches = found.match(/\sclass\s*=\s*['"]([^'"]*)['"]/i)
69
69
 
@@ -75,8 +75,8 @@ export const injectSsrContext = (
75
75
  }
76
76
 
77
77
  return `${start} class="${classes.trim()}" ${
78
- ssrContext._meta.bodyAttrs || ''
79
- }${end}${ssrContext._meta.bodyTags || ''}`
78
+ ssrContext?._meta.bodyAttrs || ''
79
+ }${end}${ssrContext?._meta.bodyTags || ''}`
80
80
  })
81
81
 
82
82
  export const QuasarPlugin: VitrifyPlugin<QuasarPluginOptions> = async ({
@@ -204,7 +204,7 @@ export const QuasarPlugin: VitrifyPlugin<QuasarPluginOptions> = async ({
204
204
  hooks: {
205
205
  onBoot: onBootHooks,
206
206
  onMounted: onMountedHooks,
207
- onRendered: [injectSsrContext]
207
+ onTemplateRendered: [injectSsrContext]
208
208
  },
209
209
  sass: quasarConf.disableSass
210
210
  ? undefined
@@ -316,5 +316,3 @@ export const QuasarPlugin: VitrifyPlugin<QuasarPluginOptions> = async ({
316
316
  }
317
317
  }
318
318
  }
319
-
320
- export default QuasarPlugin
@@ -1,48 +1,125 @@
1
1
  import type { Alias, UserConfig as ViteUserConfig, ViteDevServer } from 'vite'
2
2
  import type { ComponentInternalInstance } from '@vue/runtime-core'
3
- import type { FastifyInstance, FastifyServerOptions } from 'fastify'
3
+ import type {
4
+ FastifyInstance,
5
+ FastifyReply,
6
+ FastifyRequest,
7
+ FastifyServerOptions
8
+ } from 'fastify'
4
9
  import type { VitePWAOptions } from 'vite-plugin-pwa'
5
10
  import type { Options as unpluginVueComponentsOptions } from 'unplugin-vue-components'
6
11
  import type { UserConfig as UnoCSSUserConfig } from '@unocss/core'
7
- import { VitrifyPlugin } from './plugins/index.js'
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
46
123
 
47
124
  export interface VitrifyConfig extends ViteUserConfig {
48
125
  vitrify?: {
@@ -76,6 +153,14 @@ export interface VitrifyConfig extends ViteUserConfig {
76
153
  * Functions which run after rendering the app (SSR)
77
154
  */
78
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[]
79
164
  }
80
165
  /**
81
166
  * Global SASS variables
@@ -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 }
@@ -1,28 +1,10 @@
1
- import { type FastifyReply, type FastifyRequest } from 'fastify'
2
1
  import { createApp } from '../main.js'
3
- import { renderToString as renderToStringVue } from 'vue/server-renderer'
4
-
5
- const initializeApp = async (
6
- url: string,
7
- ssrContext: Record<string, unknown>
8
- ) => {
9
- const onRenderedList: (() => unknown)[] = []
10
- Object.assign(ssrContext, {
11
- _modules: new Set(),
12
- _meta: {},
13
- onRendered: (fn: () => unknown) => {
14
- onRenderedList.push(fn)
15
- }
16
- })
2
+ import type { Render, SSRContext } from '../../../node/vitrify-config.js'
17
3
 
4
+ const initializeApp = async (url: string, ssrContext: SSRContext) => {
18
5
  const { app, router, routes } = await createApp('server', ssrContext)
19
6
 
20
7
  router.push({ path: url })
21
- ssrContext.initialState = {}
22
-
23
- onRenderedList.forEach((fn) => {
24
- fn()
25
- })
26
8
 
27
9
  await router.isReady()
28
10
 
@@ -33,36 +15,35 @@ export const getRoutes = async () =>
33
15
  (
34
16
  await initializeApp('/', {
35
17
  req: { headers: {}, url: '/' },
36
- res: {}
18
+ res: {},
19
+ provide: {},
20
+ initialState: {},
21
+ onTemplateRenderedInternal: [],
22
+ _modules: new Set(),
23
+ _meta: {},
24
+ __qMetaList: [],
25
+ onRenderedList: [],
26
+ onRendered: (fn: () => unknown) => {
27
+ return
28
+ }
37
29
  })
38
30
  ).routes
39
31
 
40
- export async function render(
41
- url: string,
42
- manifest: Record<string, unknown>,
43
- ssrContext: {
44
- request: FastifyRequest | { headers: Record<string, unknown>; url: string }
45
- reply: FastifyReply | Record<string, unknown>
46
- provide: Record<string, unknown>
47
- },
48
- renderToString: typeof renderToStringVue
49
- ) {
32
+ export const render: Render = async (
33
+ url,
34
+ manifest,
35
+ ssrContext,
36
+ renderToString
37
+ ) => {
50
38
  if (!renderToString)
51
39
  renderToString = (await import('vue/server-renderer')).renderToString
52
40
  const { app, router } = await initializeApp(url, ssrContext)
53
41
 
54
- const ctx: {
55
- modules?: Map<unknown, unknown>
56
- transports?: Record<string, unknown>
57
- __qMetaList: unknown[]
58
- } = {
59
- __qMetaList: []
60
- }
61
- const html = await renderToString(app, ctx)
42
+ const html = await renderToString(app, ssrContext)
62
43
 
63
- const preloadLinks = renderPreloadLinks(ctx.modules!, manifest)
44
+ const preloadLinks = renderPreloadLinks(ssrContext.modules!, manifest)
64
45
 
65
- return [html, preloadLinks]
46
+ return { html, preloadLinks, app }
66
47
  }
67
48
 
68
49
  function renderPreloadLinks(
@@ -1,4 +1,4 @@
1
1
  import { prerender } from '../../../node/frameworks/vue/prerender.js'
2
- import { onRendered } from 'virtual:vitrify-hooks'
2
+ import { onTemplateRendered } from 'virtual:vitrify-hooks'
3
3
 
4
- export { prerender, onRendered }
4
+ export { prerender, onTemplateRendered }