vitrify 0.3.0 → 0.4.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/app-urls.js +1 -1
  2. package/dist/bin/cli.js +26 -4
  3. package/dist/bin/dev.js +59 -27
  4. package/dist/frameworks/vue/fastify-ssr-plugin.js +67 -16
  5. package/dist/frameworks/vue/server.js +9 -4
  6. package/dist/helpers/collect-css-ssr.js +57 -0
  7. package/dist/index.js +255 -69
  8. package/dist/plugins/quasar.js +9 -4
  9. package/dist/types/bin/build.d.ts +2 -2
  10. package/dist/types/bin/dev.d.ts +39 -3
  11. package/dist/types/frameworks/vue/fastify-ssr-plugin.d.ts +6 -3
  12. package/dist/types/frameworks/vue/server.d.ts +9 -5
  13. package/dist/types/helpers/collect-css-ssr.d.ts +10 -0
  14. package/dist/types/helpers/routes.d.ts +1 -1
  15. package/dist/types/index.d.ts +1 -1
  16. package/dist/types/plugins/index.d.ts +1 -1
  17. package/dist/types/vitrify-config.d.ts +3 -4
  18. package/package.json +32 -32
  19. package/src/node/app-urls.ts +1 -1
  20. package/src/node/bin/build.ts +2 -2
  21. package/src/node/bin/cli.ts +33 -5
  22. package/src/node/bin/dev.ts +92 -34
  23. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +80 -18
  24. package/src/node/frameworks/vue/server.ts +22 -8
  25. package/src/node/helpers/collect-css-ssr.ts +77 -0
  26. package/src/node/index.ts +285 -81
  27. package/src/node/plugins/index.ts +1 -1
  28. package/src/node/plugins/quasar.ts +9 -4
  29. package/src/node/vitrify-config.ts +7 -4
  30. package/src/vite/fastify/entry.ts +11 -0
  31. package/src/vite/fastify/server.ts +10 -0
  32. package/src/vite/vue/index.html +1 -0
  33. package/src/vite/vue/main.ts +0 -1
  34. package/src/vite/vue/ssr/app.ts +25 -0
  35. package/src/vite/vue/ssr/entry-server.ts +13 -1
  36. package/src/vite/vue/ssr/server.ts +23 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vitrify",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "author": "Stefan van Herwijnen",
6
6
  "description": "Pre-configured Vite CLI for your framework",
@@ -49,53 +49,53 @@
49
49
  "homepage": "https://github.com/simsustech/vitrify/tree/main/#readme",
50
50
  "scripts": {
51
51
  "build": "tsc",
52
- "test": "echo \"Error: no test specified\" && exit 0"
52
+ "test": "vitest test/"
53
53
  },
54
54
  "dependencies": {
55
- "@quasar/extras": "^1.13.5",
56
- "@vitejs/plugin-vue": "^2.3.1",
57
- "@vue/compiler-sfc": "^3.2.33",
58
- "@vue/server-renderer": "^3.2.33",
59
- "builtin-modules": "^3.2.0",
55
+ "@fastify/middie": "^8.0.0",
56
+ "@fastify/static": "^6.4.0",
57
+ "@quasar/extras": "^1.14.0",
58
+ "@vitejs/plugin-vue": "^3.0.0-alpha.1",
59
+ "builtin-modules": "^3.3.0",
60
60
  "cac": "^6.7.12",
61
61
  "chalk": "^5.0.1",
62
62
  "cross-env": "^7.0.3",
63
- "fastify": "^3.28.0",
64
- "fastify-static": "^4.6.1",
65
- "glob": "^8.0.1",
66
- "happy-dom": "^2.55.0",
67
- "import-meta-resolve": "^1.1.1",
63
+ "esbuild": "^0.14.43",
64
+ "fastify": "^4.0.0",
65
+ "glob": "^8.0.3",
66
+ "happy-dom": "^5.2.0",
68
67
  "local-pkg": "^0.4.1",
69
- "magic-string": "^0.26.1",
68
+ "magic-string": "^0.26.2",
70
69
  "merge-deep": "^3.0.3",
71
- "middie": "^6.0.0",
72
70
  "readline": "^1.3.0",
73
- "sass": "1.50.0",
74
- "unplugin-vue-components": "^0.19.3",
75
- "vite": "^2.9.5",
76
- "vitest": "^0.9.3"
71
+ "sass": "1.52.3",
72
+ "ts-node": "^10.8.1",
73
+ "unplugin-vue-components": "^0.19.6",
74
+ "vite": "^3.0.0-alpha.9",
75
+ "vitest": "^0.14.1"
77
76
  },
78
77
  "devDependencies": {
78
+ "@types/connect": "^3.4.35",
79
79
  "@types/glob": "^7.2.0",
80
80
  "@types/merge-deep": "^3.0.0",
81
- "@types/node": "^17.0.24",
81
+ "@types/node": "^17.0.41",
82
82
  "@types/ws": "^8.5.3",
83
- "@vue/runtime-core": "^3.2.33",
84
- "quasar": "^2.6.6",
85
- "rollup": "^2.70.1",
86
- "typescript": "^4.6.3",
87
- "vite": "^2.9.5",
88
- "vue": "^3.2.33",
89
- "vue-router": "^4.0.14"
83
+ "@vue/runtime-core": "^3.2.37",
84
+ "import-meta-resolve": "^2.0.2",
85
+ "quasar": "^2.7.1",
86
+ "rollup": "^2.75.6",
87
+ "typescript": "^4.7.3",
88
+ "vite": "^3.0.0-alpha.9",
89
+ "vue": "^3.2.37",
90
+ "vue-router": "^4.0.15"
90
91
  },
91
92
  "peerDependencies": {
92
- "fastify": "^3.28.0",
93
+ "@fastify/static": "^6.4.0",
94
+ "fastify": "^4.0.0",
93
95
  "fastify-plugin": "^3.0.1",
94
- "fastify-sensible": "^3.1.2",
95
- "fastify-static": "^4.6.1",
96
- "quasar": "^2.6.6",
97
- "vue": "^3.2.33",
98
- "vue-router": "^4.0.14"
96
+ "quasar": "^2.7.1",
97
+ "vue": "^3.2.37",
98
+ "vue-router": "^4.0.15"
99
99
  },
100
100
  "publishConfig": {
101
101
  "access": "public",
@@ -17,7 +17,7 @@ export const getCwd = () => new URL(`file://${process.cwd()}/`)
17
17
 
18
18
  export const parsePath = (path: string, basePath: URL) => {
19
19
  if (path) {
20
- if (path.slice(-1) !== '/') path += '/'
20
+ if (!path.includes('.') && path.slice(-1) !== '/') path += '/'
21
21
  if (path.startsWith('.')) {
22
22
  return new URL(path, basePath)
23
23
  } else if (path) {
@@ -3,9 +3,9 @@ import { baseConfig } from '../index.js'
3
3
  import { build as viteBuild } from 'vite'
4
4
 
5
5
  export async function build(opts: {
6
- ssr?: 'client' | 'server' | 'ssg'
6
+ ssr?: 'client' | 'server' | 'ssg' | 'fastify'
7
7
  base?: string
8
- outDir?: string
8
+ outDir: string
9
9
  appDir?: URL
10
10
  publicDir?: URL
11
11
  }) {
@@ -2,7 +2,13 @@
2
2
  import cac from 'cac'
3
3
  import { getAppDir, parsePath } from '../app-urls.js'
4
4
  import { printHttpServerUrls } from '../helpers/logger.js'
5
- import type { ViteDevServer } from 'vite'
5
+ import type {
6
+ ConfigEnv,
7
+ ResolvedConfig,
8
+ UserConfig,
9
+ UserConfigExport,
10
+ ViteDevServer
11
+ } from 'vite'
6
12
  import type { Server } from 'net'
7
13
 
8
14
  const cli = cac('vitrify')
@@ -45,6 +51,13 @@ cli
45
51
  outDir: new URL('spa/', baseOutDir).pathname
46
52
  })
47
53
  break
54
+ case 'fastify':
55
+ await build({
56
+ ssr: 'fastify',
57
+ ...args,
58
+ outDir: new URL('server/', baseOutDir).pathname
59
+ })
60
+ break
48
61
  case 'ssr':
49
62
  await build({
50
63
  ssr: 'client',
@@ -96,26 +109,41 @@ cli
96
109
  { default: '127.0.0.1' }
97
110
  )
98
111
  .option('--appDir [appDir]', 'Application directory')
112
+ .option('--app [app]', 'Fastify app instance path')
99
113
  .option('--publicDir [publicDir]', 'Public directory')
100
114
  .action(async (options) => {
101
115
  let server: Server
102
- let vite: ViteDevServer
116
+ let config: ResolvedConfig
103
117
  if (options.host === true) {
104
118
  options.host = '0.0.0.0'
105
119
  }
106
120
  const { createServer } = await import('./dev.js')
107
121
  const cwd = (await import('../app-urls.js')).getCwd()
122
+ let app
123
+ const appPath = parsePath(options.app, cwd)?.pathname
124
+ if (appPath) {
125
+ app = await import(appPath)
126
+ }
127
+
108
128
  switch (options.mode) {
109
129
  case 'ssr':
110
- ;({ server, vite } = await createServer({
130
+ ;({ server, config } = await createServer({
111
131
  mode: 'ssr',
112
132
  host: options.host,
113
133
  appDir: parsePath(options.appDir, cwd),
114
134
  publicDir: parsePath(options.publicDir, cwd)
115
135
  }))
116
136
  break
137
+ case 'fastify':
138
+ ;({ server, config } = await createServer({
139
+ mode: 'fastify',
140
+ host: options.host,
141
+ appDir: parsePath(options.appDir, cwd),
142
+ publicDir: parsePath(options.publicDir, cwd)
143
+ }))
144
+ break
117
145
  default:
118
- ;({ server, vite } = await createServer({
146
+ ;({ server, config } = await createServer({
119
147
  host: options.host,
120
148
  appDir: parsePath(options.appDir, cwd),
121
149
  publicDir: parsePath(options.publicDir, cwd)
@@ -123,7 +151,7 @@ cli
123
151
  break
124
152
  }
125
153
  console.log('Dev server running at:')
126
- printHttpServerUrls(server, vite.config)
154
+ printHttpServerUrls(server, config)
127
155
  })
128
156
 
129
157
  cli.command('test').action(async (options) => {
@@ -1,12 +1,13 @@
1
- import type { ViteDevServer, LogLevel } from 'vite'
1
+ import type { LogLevel, InlineConfig } from 'vite'
2
+ import { ViteDevServer, mergeConfig } from 'vite'
2
3
  import { searchForWorkspaceRoot } from 'vite'
3
4
  import { baseConfig } from '../index.js'
4
5
  import type { Server } from 'net'
5
6
  import type { FastifyInstance } from 'fastify/types/instance'
6
7
  import fastify from 'fastify'
7
- import { readFileSync } from 'fs'
8
+ import { fastifySsrPlugin } from '../frameworks/vue/fastify-ssr-plugin.js'
8
9
 
9
- export async function createServer({
10
+ export async function createVitrifyDevServer({
10
11
  port = 3000,
11
12
  logLevel = 'info',
12
13
  mode = 'csr',
@@ -17,38 +18,44 @@ export async function createServer({
17
18
  }: {
18
19
  port?: number
19
20
  logLevel?: LogLevel
20
- mode?: 'csr' | 'ssr'
21
+ mode?: 'csr' | 'ssr' | 'fastify'
21
22
  framework?: 'vue'
22
23
  host?: string
23
24
  appDir?: URL
24
25
  publicDir?: URL
25
26
  }) {
26
- const { getAppDir, getCliDir, getCwd } = await import('../app-urls.js')
27
- const cwd = getCwd()
28
- const cliDir = getCliDir()
29
- if (!appDir) appDir = getAppDir()
30
- const { fastifySsrPlugin } = await import(
31
- `../frameworks/${framework}/fastify-ssr-plugin.js`
27
+ const { getAppDir, getCliDir, getCliViteDir, getCwd } = await import(
28
+ '../app-urls.js'
32
29
  )
33
30
 
34
- /**
35
- * @type {import('vite').ViteDevServer}
36
- */
37
- const config = await baseConfig({
38
- ssr: mode === 'ssr' ? 'server' : undefined,
31
+ const cliDir = getCliDir()
32
+
33
+ if (!appDir) appDir = getAppDir()
34
+ let config: InlineConfig = {}
35
+ let ssrMode: 'server' | 'fastify' | undefined
36
+ if (mode === 'ssr') ssrMode = 'server'
37
+ if (mode === 'fastify') ssrMode = 'fastify'
38
+ config = await baseConfig({
39
+ framework,
40
+ ssr: ssrMode,
39
41
  command: 'dev',
40
42
  mode: 'development',
41
43
  appDir,
42
44
  publicDir
43
45
  })
46
+
44
47
  config.logLevel = logLevel
45
48
  config.server = {
49
+ https: config.server?.https,
46
50
  port,
47
- middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
51
+ // middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
52
+ middlewareMode: mode !== 'csr' ? 'ssr' : false,
48
53
  fs: {
49
54
  allow: [
50
55
  searchForWorkspaceRoot(process.cwd()),
51
- searchForWorkspaceRoot(appDir.pathname),
56
+ ...(Array.isArray(appDir)
57
+ ? appDir.map((dir) => searchForWorkspaceRoot(dir.pathname))
58
+ : [searchForWorkspaceRoot(appDir.pathname)]),
52
59
  searchForWorkspaceRoot(cliDir.pathname)
53
60
  // appDir.pathname,
54
61
  ]
@@ -61,34 +68,85 @@ export async function createServer({
61
68
  },
62
69
  host
63
70
  }
64
- const vite = await (
71
+ const vitrifyDevServer = await (
65
72
  await import('vite')
66
73
  ).createServer({
67
74
  configFile: false,
68
75
  ...config
69
76
  })
70
- const { productName = 'Product name' } = JSON.parse(
71
- readFileSync(new URL('package.json', appDir).pathname, {
72
- encoding: 'utf-8'
73
- })
77
+
78
+ return vitrifyDevServer
79
+ }
80
+
81
+ export async function createServer({
82
+ port = 3000,
83
+ logLevel = 'info',
84
+ mode = 'csr',
85
+ framework = 'vue',
86
+ host,
87
+ appDir,
88
+ publicDir
89
+ }: {
90
+ port?: number
91
+ logLevel?: LogLevel
92
+ mode?: 'csr' | 'ssr' | 'fastify'
93
+ framework?: 'vue'
94
+ host?: string
95
+ appDir?: URL
96
+ publicDir?: URL
97
+ }) {
98
+ const { getAppDir, getCliDir, getCliViteDir, getCwd } = await import(
99
+ '../app-urls.js'
74
100
  )
75
101
 
76
- let app: ViteDevServer | FastifyInstance
102
+ const cliDir = getCliDir()
103
+
104
+ const vite = await createVitrifyDevServer({
105
+ port,
106
+ logLevel,
107
+ mode,
108
+ framework,
109
+ host,
110
+ appDir,
111
+ publicDir
112
+ })
113
+ let entryUrl: string
114
+
115
+ let setup
77
116
  let server: Server
78
- if (mode === 'ssr') {
79
- console.log('SSR mode')
80
- app = fastify()
81
- await app.register(fastifySsrPlugin, {
82
- appDir,
83
- cliDir,
84
- vite,
85
- productName
86
- })
87
117
 
88
- await app.listen(port || 3000, host)
118
+ console.log(`Development mode: ${mode}`)
119
+ if (['ssr', 'fastify'].includes(mode)) {
120
+ const entryUrl =
121
+ mode === 'fastify'
122
+ ? new URL('src/vite/fastify/entry.ts', cliDir).pathname
123
+ : new URL(`src/vite/${framework}/ssr/entry-server.ts`, cliDir).pathname
124
+
125
+ ;({ setup } = await vite.ssrLoadModule(entryUrl))
126
+
127
+ const app = fastify({
128
+ https:
129
+ typeof vite.config.server.https === 'object'
130
+ ? vite.config.server.https
131
+ : {}
132
+ })
133
+ if (setup) {
134
+ await setup({
135
+ fastify: app
136
+ })
137
+ }
138
+ // await app.register(fastifySsrPlugin, {
139
+ // appDir,
140
+ // vitrifyDir: new URL('../..', import.meta.url),
141
+ // mode: 'development'
142
+ // })
143
+ await app.listen({
144
+ port: Number(port || 3000),
145
+ host
146
+ })
89
147
  server = app.server
90
148
  } else {
91
149
  server = (await vite.listen()).httpServer as Server
92
150
  }
93
- return { server, vite }
151
+ return { server, config: vite.config }
94
152
  }
@@ -3,22 +3,25 @@ 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'
10
-
9
+ import { componentsModules, collectCss } from '../../helpers/collect-css-ssr.js'
10
+ import type { ViteDevServer } from 'vite'
11
11
  export interface FastifySsrOptions {
12
12
  baseUrl?: string
13
13
  provide?: (
14
14
  req: FastifyRequest,
15
15
  res: FastifyReply
16
16
  ) => Promise<Record<string, unknown>>
17
+ vitrifyDir?: URL
17
18
  vite?: ViteDevServer
18
- cliDir?: URL
19
+ // frameworkDir?: URL
19
20
  appDir?: URL
21
+ publicDir?: URL
20
22
  productName?: string
21
- onRenderedHooks?: OnRenderedHook[]
23
+ onRendered?: OnRenderedHook[]
24
+ mode?: string
22
25
  }
23
26
 
24
27
  const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
@@ -26,25 +29,75 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
26
29
  options,
27
30
  done
28
31
  ) => {
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
+ options.vitrifyDir =
33
+ options.vitrifyDir || new URL('../../..', import.meta.url)
34
+ const frameworkDir = new URL('vite/vue/', options.vitrifyDir)
35
+ options.baseUrl = options.baseUrl || '/'
36
+ if (
37
+ options.baseUrl.charAt(options.baseUrl.length - 1) !== '/' ||
38
+ options.baseUrl.charAt(0) !== '/'
39
+ )
40
+ throw new Error('baseUrl should start and end with a /')
41
+ if (options.mode === 'development') {
42
+ if (!options.vitrifyDir)
43
+ throw new Error('Option vitrifyDir cannot be undefined')
44
+ // if (!options.vite) throw new Error('Option vite cannot be undefined')
45
+ // const { resolve } = await import('import-meta-resolve')
46
+ // const cliDir = new URL('../', await resolve('vitrify', import.meta.url))
47
+ options.appDir = options.appDir || new URL('../../..', import.meta.url)
48
+
49
+ const { createServer, searchForWorkspaceRoot } = await import('vite')
50
+ const { baseConfig } = await import('vitrify')
51
+ const cliDir = options.vitrifyDir
52
+ const config = await baseConfig({
53
+ ssr: 'server',
54
+ command: 'dev',
55
+ mode: 'development',
56
+ appDir: options.appDir,
57
+ publicDir: options.publicDir || new URL('public', options.appDir)
58
+ })
59
+
60
+ config.server = {
61
+ middlewareMode: true,
62
+ fs: {
63
+ allow: [
64
+ searchForWorkspaceRoot(process.cwd()),
65
+ searchForWorkspaceRoot(options.appDir.pathname),
66
+ searchForWorkspaceRoot(cliDir.pathname)
67
+ // appDir.pathname,
68
+ ]
69
+ },
70
+ watch: {
71
+ // During tests we edit the files too fast and sometimes chokidar
72
+ // misses change events, so enforce polling for consistency
73
+ usePolling: true,
74
+ interval: 100
75
+ }
76
+ }
77
+ const vite = await createServer({
78
+ configFile: false,
79
+ ...config
80
+ })
81
+
82
+ console.log('Dev mode')
83
+ const middie = (await import('@fastify/middie')).default
32
84
  await fastify.register(middie)
33
- fastify.use(options.vite.middlewares)
85
+ fastify.use(vite.middlewares)
34
86
 
35
- fastify.get('*', async (req, res) => {
87
+ fastify.get(`${options.baseUrl}*`, async (req, res) => {
36
88
  try {
37
89
  const url = req.raw.url
38
90
  const ssrContext = {
39
91
  req,
40
92
  res
41
93
  }
94
+
42
95
  const template = readFileSync(
43
- new URL('index.html', options.cliDir)
96
+ new URL('index.html', frameworkDir)
44
97
  ).toString()
45
98
 
46
- const entryUrl = new URL('ssr/entry-server.ts', options.cliDir).pathname
47
- const render = (await options.vite!.ssrLoadModule(entryUrl)).render
99
+ const entryUrl = new URL('ssr/entry-server.ts', frameworkDir).pathname
100
+ const render = (await vite!.ssrLoadModule(entryUrl)).render
48
101
  let manifest
49
102
  // TODO: https://github.com/vitejs/vite/issues/2282
50
103
  try {
@@ -53,11 +106,19 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
53
106
  manifest = {}
54
107
  }
55
108
 
109
+ const cssModules = [entryUrl]
110
+ // // @ts-ignore
111
+ // if (options.vite?.config.vitrify!.globalCss)
112
+ // cssModules.push(...options.vite?.config.vitrify.globalCss)
113
+ const matchedModules = componentsModules(cssModules, vite!)
114
+ const css = collectCss(matchedModules)
115
+
56
116
  const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
57
117
  const html = template
58
118
  .replace(`<!--preload-links-->`, preloadLinks)
59
119
  .replace(`<!--app-html-->`, appHtml)
60
120
  .replace('<!--product-name-->', options.productName || 'Product name')
121
+ .replace('<!--dev-ssr-css-->', css)
61
122
 
62
123
  res.code(200)
63
124
  res.type('text/html')
@@ -65,13 +126,13 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
65
126
  // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
66
127
  } catch (e: any) {
67
128
  console.error(e.stack)
68
- options.vite && options.vite.ssrFixStacktrace(e)
129
+ vite && vite.ssrFixStacktrace(e)
69
130
  res.code(500)
70
131
  res.send(e.stack)
71
132
  }
72
133
  })
73
134
  } else {
74
- options.baseUrl = options.baseUrl || '/'
135
+ options.appDir = options.appDir || new URL('../../..', import.meta.url)
75
136
  fastify.register(fastifyStatic, {
76
137
  root: new URL('./dist/ssr/client', options.appDir).pathname,
77
138
  wildcard: false,
@@ -80,7 +141,7 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
80
141
  })
81
142
 
82
143
  fastify.get(`${options.baseUrl}*`, async (req, res) => {
83
- const url = req.raw.url
144
+ const url = req.raw.url?.replace(options.baseUrl!, '/')
84
145
  const provide = options.provide ? await options.provide(req, res) : {}
85
146
  const ssrContext: Record<string, any> = {
86
147
  req,
@@ -111,8 +172,8 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
111
172
  .replace(`<!--preload-links-->`, preloadLinks)
112
173
  .replace(`<!--app-html-->`, appHtml)
113
174
 
114
- if (options.onRenderedHooks?.length) {
115
- for (const ssrFunction of options.onRenderedHooks) {
175
+ if (options.onRendered?.length) {
176
+ for (const ssrFunction of options.onRendered) {
116
177
  html = ssrFunction(html, ssrContext)
117
178
  }
118
179
  }
@@ -127,3 +188,4 @@ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
127
188
  }
128
189
 
129
190
  export { fastifySsrPlugin }
191
+ export type FastifySsrPlugin = typeof fastifySsrPlugin
@@ -1,18 +1,26 @@
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 { FastifySsrPlugin } from './fastify-ssr-plugin.js'
5
7
 
6
8
  export const createApp = ({
7
- setup,
9
+ onSetup,
8
10
  appDir,
9
11
  baseUrl,
10
- onRenderedHooks
12
+ onRendered,
13
+ fastifySsrPlugin,
14
+ vitrifyDir,
15
+ mode
11
16
  }: {
12
- setup: (fastify: FastifyInstance) => any
17
+ onSetup: OnSetupFile[]
13
18
  appDir: URL
14
19
  baseUrl?: string
15
- onRenderedHooks?: OnRenderedHook[]
20
+ onRendered?: OnRenderedHook[]
21
+ fastifySsrPlugin: FastifySsrPlugin
22
+ vitrifyDir?: URL
23
+ mode: string
16
24
  }) => {
17
25
  const app = fastify({
18
26
  logger: true
@@ -21,10 +29,16 @@ export const createApp = ({
21
29
  app.register(fastifySsrPlugin, {
22
30
  baseUrl,
23
31
  appDir,
24
- onRenderedHooks
32
+ onRendered,
33
+ vitrifyDir,
34
+ mode
25
35
  })
26
36
 
27
- setup(app)
37
+ // if (onSetup?.length) {
38
+ // for (const setup of onSetup) {
39
+ // setup(app)
40
+ // }
41
+ // }
28
42
 
29
43
  return app
30
44
  }
@@ -0,0 +1,77 @@
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: Set<ModuleNode>,
21
+ styles = new Map<string, string>(),
22
+ checkedComponents = new Set()
23
+ ) => {
24
+ for (const mod of mods) {
25
+ if (
26
+ (mod.file?.endsWith('.scss') ||
27
+ mod.file?.endsWith('.css') ||
28
+ mod.id?.includes('vue&type=style')) &&
29
+ mod.ssrModule
30
+ ) {
31
+ styles.set(mod.url, mod.ssrModule.default)
32
+ }
33
+ if (mod.importedModules.size > 0 && !checkedComponents.has(mod.id)) {
34
+ checkedComponents.add(mod.id)
35
+ collectCss(mod.importedModules, styles, checkedComponents)
36
+ }
37
+ }
38
+ let result = ''
39
+ styles.forEach((content, id) => {
40
+ const styleTag = `<style type="text/css" vite-module-id="${hashCode(
41
+ id
42
+ )}">${content}</style>`
43
+ result = result.concat(styleTag)
44
+ })
45
+ return result
46
+ }
47
+
48
+ /**
49
+ * Client listener to detect updated modules through HMR, and remove the initial styled attached to the head
50
+ */
51
+ export const removeCssHotReloaded = () => {
52
+ if (import.meta.hot) {
53
+ import.meta.hot.on('vite:beforeUpdate', (module: UpdatePayload) => {
54
+ module.updates.forEach((update) => {
55
+ const moduleStyle = document.querySelector(
56
+ `[vite-module-id="${hashCode(update.acceptedPath)}"]`
57
+ )
58
+ if (moduleStyle) {
59
+ moduleStyle.remove()
60
+ }
61
+ })
62
+ })
63
+ }
64
+ }
65
+
66
+ const hashCode = (moduleId: string) => {
67
+ let hash = 0,
68
+ i,
69
+ chr
70
+ if (moduleId.length === 0) return hash
71
+ for (i = 0; i < moduleId.length; i++) {
72
+ chr = moduleId.charCodeAt(i)
73
+ hash = (hash << 5) - hash + chr
74
+ hash |= 0 // Convert to 32bit integer
75
+ }
76
+ return hash
77
+ }