vitrify 0.3.0 → 0.5.1

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 (44) hide show
  1. package/README.md +2 -2
  2. package/dist/app-urls.js +1 -1
  3. package/dist/bin/build.js +9 -8
  4. package/dist/bin/cli.js +28 -6
  5. package/dist/bin/dev.js +73 -29
  6. package/dist/frameworks/vue/fastify-csr-plugin.js +38 -0
  7. package/dist/frameworks/vue/fastify-ssr-plugin.js +83 -18
  8. package/dist/frameworks/vue/server.js +10 -5
  9. package/dist/helpers/collect-css-ssr.js +61 -0
  10. package/dist/index.js +298 -77
  11. package/dist/plugins/quasar.js +30 -9
  12. package/dist/types/bin/build.d.ts +2 -2
  13. package/dist/types/bin/dev.d.ts +43 -4
  14. package/dist/types/frameworks/vue/fastify-csr-plugin.d.ts +17 -0
  15. package/dist/types/frameworks/vue/fastify-ssr-plugin.d.ts +6 -3
  16. package/dist/types/frameworks/vue/server.d.ts +10 -5
  17. package/dist/types/helpers/collect-css-ssr.d.ts +14 -0
  18. package/dist/types/helpers/routes.d.ts +1 -1
  19. package/dist/types/index.d.ts +4 -2
  20. package/dist/types/plugins/index.d.ts +1 -1
  21. package/dist/types/vitrify-config.d.ts +16 -5
  22. package/package.json +33 -32
  23. package/src/node/app-urls.ts +1 -1
  24. package/src/node/bin/build.ts +11 -10
  25. package/src/node/bin/cli.ts +35 -7
  26. package/src/node/bin/dev.ts +109 -38
  27. package/src/node/frameworks/vue/fastify-csr-plugin.ts +72 -0
  28. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +99 -20
  29. package/src/node/frameworks/vue/server.ts +24 -9
  30. package/src/node/helpers/collect-css-ssr.ts +85 -0
  31. package/src/node/index.ts +338 -90
  32. package/src/node/plugins/index.ts +1 -1
  33. package/src/node/plugins/quasar.ts +40 -9
  34. package/src/node/vitrify-config.ts +20 -5
  35. package/src/vite/fastify/entry.ts +11 -0
  36. package/src/vite/fastify/server.ts +12 -0
  37. package/src/vite/vue/csr/app.ts +25 -0
  38. package/src/vite/vue/csr/fastify-csr-plugin.ts +3 -0
  39. package/src/vite/vue/csr/server.ts +8 -0
  40. package/src/vite/vue/index.html +1 -0
  41. package/src/vite/vue/main.ts +0 -1
  42. package/src/vite/vue/ssr/app.ts +25 -0
  43. package/src/vite/vue/ssr/entry-server.ts +13 -1
  44. package/src/vite/vue/ssr/server.ts +23 -14
@@ -3,10 +3,11 @@ import type {
3
3
  FastifyRequest,
4
4
  FastifyReply
5
5
  } from 'fastify'
6
- import fastifyStatic from 'fastify-static'
6
+ import fastifyStatic from '@fastify/static'
7
7
  import { readFileSync } from 'fs'
8
- import type { ViteDevServer } from 'vite'
9
8
  import type { OnRenderedHook } from '../../vitrify-config.js'
9
+ import { componentsModules, collectCss } from '../../helpers/collect-css-ssr.js'
10
+ import type { ViteDevServer } from 'vite'
10
11
 
11
12
  export interface FastifySsrOptions {
12
13
  baseUrl?: string
@@ -14,11 +15,14 @@ export interface FastifySsrOptions {
14
15
  req: FastifyRequest,
15
16
  res: FastifyReply
16
17
  ) => Promise<Record<string, unknown>>
18
+ vitrifyDir?: URL
17
19
  vite?: ViteDevServer
18
- cliDir?: URL
20
+ // frameworkDir?: URL
19
21
  appDir?: URL
22
+ publicDir?: URL
20
23
  productName?: string
21
- onRenderedHooks?: OnRenderedHook[]
24
+ onRendered?: OnRenderedHook[]
25
+ mode?: string
22
26
  }
23
27
 
24
28
  const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
@@ -26,25 +30,89 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
26
30
  options,
27
31
  done
28
32
  ) => {
29
- if (import.meta.env.MODE === 'development') {
30
- if (!options.vite) throw new Error('Option vite cannot be undefined')
31
- const middie = (await import('middie')).default
32
- await fastify.register(middie)
33
- fastify.use(options.vite.middlewares)
33
+ options.vitrifyDir =
34
+ options.vitrifyDir || (await import('vitrify')).vitrifyDir
35
+ const frameworkDir = new URL('src/vite/vue/', options.vitrifyDir)
36
+ options.baseUrl = options.baseUrl || '/'
37
+ options.mode = options.mode || process.env.MODE || import.meta.env.MODE
38
+ options.appDir = options.appDir || new URL('../../..', import.meta.url)
39
+
40
+ if (
41
+ options.baseUrl.charAt(options.baseUrl.length - 1) !== '/' ||
42
+ options.baseUrl.charAt(0) !== '/'
43
+ )
44
+ throw new Error('baseUrl should start and end with a /')
45
+ if (options.mode === 'development') {
46
+ // if (!options.vitrifyDir)
47
+ // throw new Error('Option vitrifyDir cannot be undefined')
48
+ // if (!options.vite) throw new Error('Option vite cannot be undefined')
49
+ // const { resolve } = await import('import-meta-resolve')
50
+ // const cliDir = new URL('../', await resolve('vitrify', import.meta.url))
51
+ options.appDir = options.appDir || new URL('../../..', import.meta.url)
52
+
53
+ const { createVitrifyDevServer } = await import('vitrify/dev')
54
+ const vite = await createVitrifyDevServer({
55
+ appDir: options.appDir,
56
+ ssr: 'ssr',
57
+ framework: 'vue',
58
+ base: options.baseUrl
59
+ })
60
+ // const { createServer, searchForWorkspaceRoot } = await import('vite')
61
+ // const { baseConfig } = await import('vitrify')
62
+ // const cliDir = options.vitrifyDir
63
+ // const config = await baseConfig({
64
+ // ssr: 'server',
65
+ // command: 'dev',
66
+ // mode: 'development',
67
+ // appDir: options.appDir,
68
+ // publicDir: options.publicDir || new URL('public', options.appDir)
69
+ // })
70
+
71
+ // config.server = {
72
+ // middlewareMode: true,
73
+ // fs: {
74
+ // allow: [
75
+ // searchForWorkspaceRoot(process.cwd()),
76
+ // searchForWorkspaceRoot(options.appDir.pathname),
77
+ // searchForWorkspaceRoot(cliDir.pathname)
78
+ // // appDir.pathname,
79
+ // ]
80
+ // },
81
+ // watch: {
82
+ // // During tests we edit the files too fast and sometimes chokidar
83
+ // // misses change events, so enforce polling for consistency
84
+ // usePolling: true,
85
+ // interval: 100
86
+ // }
87
+ // }
88
+ // const vite = await createServer({
89
+ // configFile: false,
90
+ // ...config
91
+ // })
34
92
 
35
- fastify.get('*', async (req, res) => {
93
+ console.log('Dev mode')
94
+ if (!('use' in fastify)) {
95
+ const middie = (await import('@fastify/middie')).default
96
+ await fastify.register(middie)
97
+ }
98
+ fastify.use(vite.middlewares)
99
+
100
+ fastify.get(`${options.baseUrl}*`, async (req, res) => {
36
101
  try {
37
- const url = req.raw.url
102
+ const url = req.raw.url?.replace(options.baseUrl!, '/')
38
103
  const ssrContext = {
39
104
  req,
40
105
  res
41
106
  }
42
- const template = readFileSync(
43
- new URL('index.html', options.cliDir)
107
+
108
+ let template = readFileSync(
109
+ new URL('index.html', frameworkDir)
44
110
  ).toString()
45
111
 
46
- const entryUrl = new URL('ssr/entry-server.ts', options.cliDir).pathname
47
- const render = (await options.vite!.ssrLoadModule(entryUrl)).render
112
+ template = await vite.transformIndexHtml(url!, template)
113
+
114
+ const entryUrl = new URL('ssr/entry-server.ts', frameworkDir).pathname
115
+ const render = (await vite!.ssrLoadModule(entryUrl)).render
48
116
  let manifest
49
117
  // TODO: https://github.com/vitejs/vite/issues/2282
50
118
  try {
@@ -53,11 +121,21 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
53
121
  manifest = {}
54
122
  }
55
123
 
124
+ const cssModules = [entryUrl]
125
+ // // @ts-ignore
126
+ // if (options.vite?.config.vitrify!.globalCss)
127
+ // cssModules.push(...options.vite?.config.vitrify.globalCss)
128
+ const matchedModules = componentsModules(cssModules, vite!)
129
+ const css = collectCss({
130
+ mods: matchedModules
131
+ })
132
+
56
133
  const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
57
134
  const html = template
58
135
  .replace(`<!--preload-links-->`, preloadLinks)
59
136
  .replace(`<!--app-html-->`, appHtml)
60
137
  .replace('<!--product-name-->', options.productName || 'Product name')
138
+ .replace('<!--dev-ssr-css-->', css)
61
139
 
62
140
  res.code(200)
63
141
  res.type('text/html')
@@ -65,13 +143,13 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
65
143
  // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
66
144
  } catch (e: any) {
67
145
  console.error(e.stack)
68
- options.vite && options.vite.ssrFixStacktrace(e)
146
+ vite && vite.ssrFixStacktrace(e)
69
147
  res.code(500)
70
148
  res.send(e.stack)
71
149
  }
72
150
  })
73
151
  } else {
74
- options.baseUrl = options.baseUrl || '/'
152
+ options.appDir = options.appDir || new URL('../../..', import.meta.url)
75
153
  fastify.register(fastifyStatic, {
76
154
  root: new URL('./dist/ssr/client', options.appDir).pathname,
77
155
  wildcard: false,
@@ -80,7 +158,7 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
80
158
  })
81
159
 
82
160
  fastify.get(`${options.baseUrl}*`, async (req, res) => {
83
- const url = req.raw.url
161
+ const url = req.raw.url?.replace(options.baseUrl!, '/')
84
162
  const provide = options.provide ? await options.provide(req, res) : {}
85
163
  const ssrContext: Record<string, any> = {
86
164
  req,
@@ -111,8 +189,8 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
111
189
  .replace(`<!--preload-links-->`, preloadLinks)
112
190
  .replace(`<!--app-html-->`, appHtml)
113
191
 
114
- if (options.onRenderedHooks?.length) {
115
- for (const ssrFunction of options.onRenderedHooks) {
192
+ if (options.onRendered?.length) {
193
+ for (const ssrFunction of options.onRendered) {
116
194
  html = ssrFunction(html, ssrContext)
117
195
  }
118
196
  }
@@ -127,3 +205,4 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
127
205
  }
128
206
 
129
207
  export { fastifySsrPlugin }
208
+ export type FastifySsrPlugin = typeof fastifySsrPlugin
@@ -1,30 +1,45 @@
1
1
  import type { FastifyInstance } from 'fastify'
2
2
  import fastify from 'fastify'
3
- import type { OnRenderedHook } from '../../vitrify-config.js'
4
- import { fastifySsrPlugin } from './fastify-ssr-plugin.js'
3
+ import type { ViteDevServer } from 'vite'
4
+ import { getCliDir, getCliViteDir } from '../../app-urls.js'
5
+ import type { OnRenderedHook, OnSetupFile } from '../../vitrify-config.js'
6
+ import type { FastifyCsrPlugin } from './fastify-csr-plugin.js'
7
+ import type { FastifySsrPlugin } from './fastify-ssr-plugin.js'
5
8
 
6
9
  export const createApp = ({
7
- setup,
10
+ onSetup,
8
11
  appDir,
9
12
  baseUrl,
10
- onRenderedHooks
13
+ onRendered,
14
+ fastifyPlugin,
15
+ vitrifyDir,
16
+ mode
11
17
  }: {
12
- setup: (fastify: FastifyInstance) => any
18
+ onSetup: OnSetupFile[]
13
19
  appDir: URL
14
20
  baseUrl?: string
15
- onRenderedHooks?: OnRenderedHook[]
21
+ onRendered?: OnRenderedHook[]
22
+ fastifyPlugin: FastifySsrPlugin | FastifyCsrPlugin
23
+ vitrifyDir?: URL
24
+ mode: string
16
25
  }) => {
17
26
  const app = fastify({
18
27
  logger: true
19
28
  })
20
29
 
21
- app.register(fastifySsrPlugin, {
30
+ app.register(fastifyPlugin, {
22
31
  baseUrl,
23
32
  appDir,
24
- onRenderedHooks
33
+ onRendered,
34
+ vitrifyDir,
35
+ mode
25
36
  })
26
37
 
27
- setup(app)
38
+ // if (onSetup?.length) {
39
+ // for (const setup of onSetup) {
40
+ // setup(app)
41
+ // }
42
+ // }
28
43
 
29
44
  return app
30
45
  }
@@ -0,0 +1,85 @@
1
+ // collect-css-ssr.ts
2
+ import type { ViteDevServer, ModuleNode, UpdatePayload } from 'vite'
3
+
4
+ /**
5
+ * Collect SSR CSS for Vite
6
+ */
7
+ export const componentsModules = (
8
+ components: string[],
9
+ vite: ViteDevServer
10
+ ) => {
11
+ const matchedModules = new Set<ModuleNode>()
12
+ components.forEach((component) => {
13
+ const modules = vite.moduleGraph.getModulesByFile(component)
14
+ modules?.forEach((mod) => matchedModules.add(mod))
15
+ })
16
+ return matchedModules
17
+ }
18
+
19
+ export const collectCss = ({
20
+ mods,
21
+ styles = new Map<string, string>(),
22
+ checkedComponents = new Set()
23
+ }: {
24
+ mods: Set<ModuleNode>
25
+ styles?: Map<string, string>
26
+ checkedComponents?: Set<unknown>
27
+ }) => {
28
+ for (const mod of mods) {
29
+ if (
30
+ (mod.file?.endsWith('.scss') ||
31
+ mod.file?.endsWith('.css') ||
32
+ mod.id?.includes('vue&type=style')) &&
33
+ mod.ssrModule
34
+ ) {
35
+ styles.set(mod.url, mod.ssrModule.default)
36
+ }
37
+ if (mod.importedModules.size > 0 && !checkedComponents.has(mod.id)) {
38
+ checkedComponents.add(mod.id)
39
+ collectCss({
40
+ mods: mod.importedModules,
41
+ styles,
42
+ checkedComponents
43
+ })
44
+ }
45
+ }
46
+ let result = ''
47
+ styles.forEach((content, id) => {
48
+ const styleTag = `<style type="text/css" vite-module-id="${hashCode(
49
+ id
50
+ )}">${content}</style>`
51
+ result = result.concat(styleTag)
52
+ })
53
+ return result
54
+ }
55
+
56
+ /**
57
+ * Client listener to detect updated modules through HMR, and remove the initial styled attached to the head
58
+ */
59
+ export const removeCssHotReloaded = () => {
60
+ if (import.meta.hot) {
61
+ import.meta.hot.on('vite:beforeUpdate', (module: UpdatePayload) => {
62
+ module.updates.forEach((update) => {
63
+ const moduleStyle = document.querySelector(
64
+ `[vite-module-id="${hashCode(update.acceptedPath)}"]`
65
+ )
66
+ if (moduleStyle) {
67
+ moduleStyle.remove()
68
+ }
69
+ })
70
+ })
71
+ }
72
+ }
73
+
74
+ const hashCode = (moduleId: string) => {
75
+ let hash = 0,
76
+ i,
77
+ chr
78
+ if (moduleId.length === 0) return hash
79
+ for (i = 0; i < moduleId.length; i++) {
80
+ chr = moduleId.charCodeAt(i)
81
+ hash = (hash << 5) - hash + chr
82
+ hash |= 0 // Convert to 32bit integer
83
+ }
84
+ return hash
85
+ }