vitrify 0.1.1 → 0.2.2

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 (38) hide show
  1. package/dist/app-urls.js +14 -10
  2. package/dist/bin/cli.js +14 -12
  3. package/dist/bin/dev.js +5 -3
  4. package/dist/bin/run.js +5 -2
  5. package/dist/{vue → frameworks/vue}/fastify-ssr-plugin.js +0 -0
  6. package/dist/{vue → frameworks/vue}/prerender.js +1 -1
  7. package/dist/{vue → frameworks/vue}/server.js +0 -0
  8. package/dist/index.js +73 -20
  9. package/dist/plugins/quasar.js +19 -14
  10. package/dist/types/app-urls.d.ts +7 -6
  11. package/dist/types/bin/run.d.ts +2 -2
  12. package/dist/types/{vue → frameworks/vue}/fastify-ssr-plugin.d.ts +1 -1
  13. package/dist/types/{vue → frameworks/vue}/prerender.d.ts +1 -1
  14. package/dist/types/{vue → frameworks/vue}/server.d.ts +1 -1
  15. package/dist/types/index.d.ts +2 -2
  16. package/dist/types/vitrify-config.d.ts +4 -1
  17. package/package.json +16 -18
  18. package/src/node/app-urls.ts +38 -0
  19. package/src/node/bin/build.ts +87 -0
  20. package/src/node/bin/cli.ts +157 -0
  21. package/src/node/bin/dev.ts +138 -0
  22. package/src/node/bin/run.ts +47 -0
  23. package/src/node/bin/test.ts +24 -0
  24. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +137 -0
  25. package/src/node/frameworks/vue/prerender.ts +49 -0
  26. package/src/node/frameworks/vue/server.ts +38 -0
  27. package/src/node/helpers/logger.ts +142 -0
  28. package/src/node/helpers/routes.ts +29 -0
  29. package/src/node/helpers/ssr.ts.bak +52 -0
  30. package/src/node/helpers/utils.ts +37 -0
  31. package/src/node/index.ts +402 -0
  32. package/src/node/plugins/index.ts +12 -0
  33. package/src/node/plugins/quasar.ts +387 -0
  34. package/src/node/vitrify-config.ts +79 -0
  35. package/src/vite/vue/ssr/fastify-ssr-plugin.ts +1 -1
  36. package/src/vite/vue/ssr/prerender.ts +1 -1
  37. package/src/vite/vue/ssr/server.ts +6 -3
  38. package/src/vite/vue/components.d.ts +0 -25
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/node --experimental-specifier-resolution=node
2
+ import { baseConfig } from '../index.js'
3
+ // import { promises as fs } from 'fs'
4
+ // import { routesToPaths } from '../helpers/routes.js'
5
+ import { build as viteBuild } from 'vite'
6
+ // import { SsrFunction } from '../vitrify-config.js'
7
+
8
+ // export const prerender = async ({
9
+ // outDir,
10
+ // templatePath,
11
+ // manifestPath,
12
+ // entryServerPath,
13
+ // injectSsrContext
14
+ // }: {
15
+ // outDir: string
16
+ // templatePath: string
17
+ // manifestPath: string
18
+ // entryServerPath: string
19
+ // injectSsrContext: SsrFunction
20
+ // }) => {
21
+ // let template
22
+ // let manifest
23
+ // const promises = []
24
+ // template = (await fs.readFile(templatePath)).toString()
25
+ // manifest = await fs.readFile(manifestPath)
26
+ // let { render, getRoutes } = await import(entryServerPath)
27
+ // const routes = await getRoutes()
28
+ // const paths = routesToPaths(routes).filter(
29
+ // (i) => !i.includes(':') && !i.includes('*')
30
+ // )
31
+ // for (let url of paths) {
32
+ // const filename =
33
+ // (url.endsWith('/') ? 'index' : url.replace(/^\//g, '')) + '.html'
34
+ // console.log(`Generating ${filename}`)
35
+ // const ssrContext = {
36
+ // req: { headers: {}, url },
37
+ // res: {}
38
+ // }
39
+ // const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
40
+
41
+ // let html = template
42
+ // .replace(`<!--preload-links-->`, preloadLinks)
43
+ // .replace(`<!--app-html-->`, appHtml)
44
+
45
+ // html = injectSsrContext(html, ssrContext)
46
+
47
+ // promises.push(fs.writeFile(outDir + filename, html, 'utf-8'))
48
+ // }
49
+ // return Promise.all(promises)
50
+ // }
51
+
52
+ export async function build(opts: {
53
+ ssr?: 'client' | 'server' | 'ssg'
54
+ base?: string
55
+ outDir?: string
56
+ appDir?: URL
57
+ publicDir?: URL
58
+ }) {
59
+ const config = await baseConfig({
60
+ command: 'build',
61
+ mode: 'production',
62
+ ssr: opts?.ssr,
63
+ appDir: opts.appDir,
64
+ publicDir: opts.publicDir
65
+ })
66
+
67
+ config.build = {
68
+ ...config.build,
69
+ minify: false,
70
+ outDir: opts.outDir,
71
+ emptyOutDir: !!opts.outDir
72
+ }
73
+
74
+ if (opts.base) {
75
+ config.define = {
76
+ ...config.define,
77
+ __BASE_URL__: `'${opts.base}'`
78
+ }
79
+ }
80
+
81
+ return viteBuild({
82
+ configFile: false,
83
+ base: opts.base,
84
+ // logLevel: 'silent',
85
+ ...config
86
+ })
87
+ }
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import cac from 'cac'
3
+ import { getAppDir, parsePath } from '../app-urls.js'
4
+ import { printHttpServerUrls } from '../helpers/logger.js'
5
+ import type { ViteDevServer } from 'vite'
6
+ import type { Server } from 'net'
7
+
8
+ const cli = cac('vitrify')
9
+ cli
10
+ .command('build')
11
+ .option('-m, --mode [mode]', 'Build mode', { default: 'csr' })
12
+ .option('--base [base]', 'Base public path')
13
+ .option('--outDir [outDir]', 'Output directory')
14
+ .option('--appDir [appDir]', 'App directory')
15
+ .option('--publicDir [publicDir]', 'Public directory')
16
+ .option('--productName [productName]', 'Product name')
17
+ .action(async (options) => {
18
+ const { build } = await import('./build.js')
19
+ let appDir: URL
20
+ let prerender, ssrFunctions
21
+ if (options.appDir) {
22
+ if (options.appDir.slice(-1) !== '/') options.appDir += '/'
23
+ appDir = new URL(`file://${options.appDir}`)
24
+ } else {
25
+ appDir = getAppDir()
26
+ }
27
+
28
+ const baseOutDir =
29
+ parsePath(options.outDir, appDir) || new URL('dist/', appDir)
30
+
31
+ const args: {
32
+ base: string
33
+ appDir?: URL
34
+ publicDir?: URL
35
+ } = {
36
+ base: options.base,
37
+ appDir,
38
+ publicDir: parsePath(options.publicDir, appDir)
39
+ }
40
+
41
+ switch (options.mode) {
42
+ case 'csr':
43
+ await build({
44
+ ...args,
45
+ outDir: new URL('spa/', baseOutDir).pathname
46
+ })
47
+ break
48
+ case 'ssr':
49
+ await build({
50
+ ssr: 'client',
51
+ ...args,
52
+ outDir: new URL('ssr/client/', baseOutDir).pathname
53
+ })
54
+ await build({
55
+ ssr: 'server',
56
+ ...args,
57
+ outDir: new URL('ssr/server/', baseOutDir).pathname
58
+ })
59
+ break
60
+ case 'ssg':
61
+ await build({
62
+ ssr: 'client',
63
+ ...args,
64
+ outDir: new URL('static/', baseOutDir).pathname
65
+ })
66
+ await build({
67
+ ssr: 'server',
68
+ ...args,
69
+ outDir: new URL('ssr/server/', baseOutDir).pathname
70
+ })
71
+ ;({ prerender, ssrFunctions } = await import(
72
+ new URL('ssr/server/prerender.mjs', baseOutDir).pathname
73
+ ))
74
+ prerender({
75
+ outDir: new URL('static/', baseOutDir).pathname,
76
+ templatePath: new URL('static/index.html', baseOutDir).pathname,
77
+ manifestPath: new URL('static/ssr-manifest.json', baseOutDir)
78
+ .pathname,
79
+ entryServerPath: new URL('ssr/server/entry-server.mjs', baseOutDir)
80
+ .pathname,
81
+ ssrFunctions
82
+ })
83
+ break
84
+ default:
85
+ console.log('Invalid build mode')
86
+ break
87
+ }
88
+ })
89
+
90
+ cli
91
+ .command('dev')
92
+ .option('-m, --mode [mode]', 'Development server mode', { default: 'csr' })
93
+ .option(
94
+ '--host [host]',
95
+ 'Specify which IP addresses the server should listen on',
96
+ { default: '127.0.0.1' }
97
+ )
98
+ .option('--appDir [appDir]', 'Application directory')
99
+ .option('--publicDir [publicDir]', 'Public directory')
100
+ .action(async (options) => {
101
+ let server: Server
102
+ let vite: ViteDevServer
103
+ if (options.host === true) {
104
+ options.host = '0.0.0.0'
105
+ }
106
+ const { createServer } = await import('./dev.js')
107
+ const cwd = (await import('../app-urls.js')).getCwd()
108
+ switch (options.mode) {
109
+ case 'ssr':
110
+ ;({ server, vite } = await createServer({
111
+ mode: 'ssr',
112
+ host: options.host,
113
+ appDir: parsePath(options.appDir, cwd),
114
+ publicDir: parsePath(options.publicDir, cwd)
115
+ }))
116
+ break
117
+ default:
118
+ ;({ server, vite } = await createServer({
119
+ host: options.host,
120
+ appDir: parsePath(options.appDir, cwd),
121
+ publicDir: parsePath(options.publicDir, cwd)
122
+ }))
123
+ break
124
+ }
125
+ console.log('Dev server running at:')
126
+ printHttpServerUrls(server, vite.config)
127
+ })
128
+
129
+ cli.command('test').action(async (options) => {
130
+ const { test } = await import('./test.js')
131
+
132
+ let appDir: URL
133
+ if (options.appDir) {
134
+ if (options.appDir.slice(-1) !== '/') options.appDir += '/'
135
+ appDir = new URL(`file://${options.appDir}`)
136
+ } else {
137
+ appDir = getAppDir()
138
+ }
139
+ await test({
140
+ appDir
141
+ })
142
+ })
143
+
144
+ cli.command('run <file>').action(async (file, options) => {
145
+ const { run } = await import('./run.js')
146
+ const filePath = new URL(file, `file://${process.cwd()}/`)
147
+ await run(filePath.pathname)
148
+ })
149
+
150
+ // Default
151
+ cli.command('').action((command, options) => {
152
+ cli.outputHelp()
153
+ })
154
+
155
+ cli.help()
156
+
157
+ cli.parse()
@@ -0,0 +1,138 @@
1
+ import type { ViteDevServer, LogLevel } from 'vite'
2
+ import { searchForWorkspaceRoot } from 'vite'
3
+ import { baseConfig } from '../index.js'
4
+ import type { Server } from 'net'
5
+ import type { FastifyInstance } from 'fastify/types/instance'
6
+ import fastify from 'fastify'
7
+ import { readFileSync } from 'fs'
8
+
9
+ export async function createServer({
10
+ port = 3000,
11
+ logLevel = 'info',
12
+ mode = 'csr',
13
+ framework = 'vue',
14
+ host,
15
+ appDir,
16
+ publicDir
17
+ }: {
18
+ port?: number
19
+ logLevel?: LogLevel
20
+ mode?: 'csr' | 'ssr'
21
+ framework?: 'vue'
22
+ host?: string
23
+ appDir?: URL
24
+ publicDir?: URL
25
+ }) {
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
+ `../${framework}/fastify-ssr-plugin.js`
32
+ )
33
+
34
+ /**
35
+ * @type {import('vite').ViteDevServer}
36
+ */
37
+ const config = await baseConfig({
38
+ ssr: mode === 'ssr' ? 'server' : undefined,
39
+ command: 'dev',
40
+ mode: 'development',
41
+ appDir,
42
+ publicDir
43
+ })
44
+ config.logLevel = logLevel
45
+ config.server = {
46
+ port,
47
+ middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
48
+ fs: {
49
+ allow: [
50
+ searchForWorkspaceRoot(process.cwd()),
51
+ searchForWorkspaceRoot(appDir.pathname),
52
+ searchForWorkspaceRoot(cliDir.pathname)
53
+ // appDir.pathname,
54
+ ]
55
+ },
56
+ watch: {
57
+ // During tests we edit the files too fast and sometimes chokidar
58
+ // misses change events, so enforce polling for consistency
59
+ usePolling: true,
60
+ interval: 100
61
+ },
62
+ host
63
+ }
64
+ const vite = await (
65
+ await import('vite')
66
+ ).createServer({
67
+ configFile: false,
68
+ ...config
69
+ })
70
+ const { productName = 'Product name' } = JSON.parse(
71
+ readFileSync(new URL('package.json', appDir).pathname, {
72
+ encoding: 'utf-8'
73
+ })
74
+ )
75
+
76
+ let app: ViteDevServer | FastifyInstance
77
+ 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
+ // await app.register(middie)
88
+ // app.use(vite.middlewares)
89
+
90
+ // app.get('*', async (req, res) => {
91
+ // try {
92
+ // // const url = req.originalUrl
93
+ // const url = req.raw.url
94
+ // let template
95
+ // let render
96
+ // const ssrContext = {
97
+ // req,
98
+ // res
99
+ // }
100
+ // // always read fresh template in dev
101
+ // // template = readFileSync(resolve('index.html'), 'utf-8')
102
+ // template = readFileSync(new URL('index.html', cliDir)).toString()
103
+
104
+ // // template = await vite.transformIndexHtml(url, template)
105
+ // const entryUrl = new URL('ssr/entry-server.ts', cliDir).pathname
106
+ // render = (await vite.ssrLoadModule(entryUrl)).render
107
+ // let manifest
108
+ // // TODO: https://github.com/vitejs/vite/issues/2282
109
+ // try {
110
+ // manifest = {}
111
+ // } catch (e) {
112
+ // manifest = {}
113
+ // }
114
+
115
+ // const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
116
+ // const html = template
117
+ // .replace(`<!--preload-links-->`, preloadLinks)
118
+ // .replace(`<!--app-html-->`, appHtml)
119
+ // .replace('<!--product-name-->', productName)
120
+
121
+ // res.code(200)
122
+ // res.type('text/html')
123
+ // res.send(html)
124
+ // // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
125
+ // } catch (e: any) {
126
+ // console.error(e.stack)
127
+ // vite && vite.ssrFixStacktrace(e)
128
+ // res.code(500)
129
+ // res.send(e.stack)
130
+ // }
131
+ // })
132
+ await app.listen(port || 3000, host)
133
+ server = app.server
134
+ } else {
135
+ server = (await vite.listen()).httpServer as Server
136
+ }
137
+ return { server, vite }
138
+ }
@@ -0,0 +1,47 @@
1
+ import { promises as fs } from 'fs'
2
+ import readline from 'readline'
3
+ import { getAppDir, getCliDir, getProjectURLs } from '../app-urls.js'
4
+
5
+ const rl = readline.createInterface({
6
+ input: process.stdin,
7
+ output: process.stdout
8
+ })
9
+
10
+ export interface VitrifyContext {
11
+ vitrify: {
12
+ version: string
13
+ }
14
+ projectURLs: ReturnType<typeof getProjectURLs>
15
+ }
16
+
17
+ export async function run(filePath: string) {
18
+ const { run } = await import(filePath)
19
+ const appDir = getAppDir()
20
+ const cliDir = getCliDir()
21
+ const projectURLs = getProjectURLs(appDir, cliDir)
22
+ const pkg = JSON.parse(
23
+ (await fs.readFile(projectURLs.cli('package.json'), 'utf-8')).toString()
24
+ )
25
+
26
+ if (!run)
27
+ throw new Error(
28
+ `${filePath} does not have an export named run. Aborting...`
29
+ )
30
+
31
+ rl.question(
32
+ `
33
+ The script ${filePath}
34
+ will now be executed by vitrify.
35
+ Make sure you trust the content of this script before proceeding.
36
+ Press enter to proceed or CTRL+C to abort.`,
37
+ async (answer) => {
38
+ await run({
39
+ vitrify: {
40
+ version: pkg.version
41
+ },
42
+ resolve: projectURLs
43
+ })
44
+ rl.close()
45
+ }
46
+ )
47
+ }
@@ -0,0 +1,24 @@
1
+ import { startVitest } from 'vitest/node'
2
+ import { baseConfig } from '../index.js'
3
+ export async function test(opts: { appDir: URL }) {
4
+ const config = await baseConfig({
5
+ appDir: opts.appDir,
6
+ command: 'test',
7
+ mode: 'development'
8
+ })
9
+
10
+ await startVitest(
11
+ [],
12
+ {
13
+ root: opts.appDir.pathname,
14
+ dir: opts.appDir.pathname,
15
+
16
+ globals: true,
17
+ environment: 'happy-dom'
18
+ // include: [
19
+ // `${opts.appDir.pathname}**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}`
20
+ // ]
21
+ },
22
+ config
23
+ )
24
+ }
@@ -0,0 +1,137 @@
1
+ import type {
2
+ FastifyPluginCallback,
3
+ FastifyRequest,
4
+ FastifyReply
5
+ } from 'fastify'
6
+ import fastifyStatic from 'fastify-static'
7
+ import { readFileSync } from 'fs'
8
+ // import { injectSsrContext } from '../helpers/ssr.js'
9
+ import type { ViteDevServer } from 'vite'
10
+ import type { SsrFunction } from '../../vitrify-config.js'
11
+
12
+ export interface FastifySsrOptions {
13
+ baseUrl?: string
14
+ provide?: (
15
+ req: FastifyRequest,
16
+ res: FastifyReply
17
+ ) => Promise<Record<string, unknown>>
18
+ vite?: ViteDevServer
19
+ cliDir?: URL
20
+ appDir?: URL
21
+ productName?: string
22
+ ssrFunctions?: SsrFunction[]
23
+ }
24
+
25
+ const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions> = async (
26
+ fastify,
27
+ options,
28
+ done
29
+ ) => {
30
+ if (import.meta.env.MODE === 'development') {
31
+ if (!options.vite) throw new Error('Option vite cannot be undefined')
32
+ const middie = (await import('middie')).default
33
+ await fastify.register(middie)
34
+ fastify.use(options.vite.middlewares)
35
+
36
+ fastify.get('*', async (req, res) => {
37
+ try {
38
+ // const url = req.originalUrl
39
+ const url = req.raw.url
40
+ const ssrContext = {
41
+ req,
42
+ res
43
+ }
44
+ // always read fresh template in dev
45
+ // template = readFileSync(resolve('index.html'), 'utf-8')
46
+ const template = readFileSync(
47
+ new URL('index.html', options.cliDir)
48
+ ).toString()
49
+
50
+ // template = await vite.transformIndexHtml(url, template)
51
+ const entryUrl = new URL('ssr/entry-server.ts', options.cliDir).pathname
52
+ const render = (await options.vite!.ssrLoadModule(entryUrl)).render
53
+ let manifest
54
+ // TODO: https://github.com/vitejs/vite/issues/2282
55
+ try {
56
+ manifest = {}
57
+ } catch (e) {
58
+ manifest = {}
59
+ }
60
+
61
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
62
+ const html = template
63
+ .replace(`<!--preload-links-->`, preloadLinks)
64
+ .replace(`<!--app-html-->`, appHtml)
65
+ .replace('<!--product-name-->', options.productName || 'Product name')
66
+
67
+ res.code(200)
68
+ res.type('text/html')
69
+ res.send(html)
70
+ // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
71
+ } catch (e: any) {
72
+ console.error(e.stack)
73
+ options.vite && options.vite.ssrFixStacktrace(e)
74
+ res.code(500)
75
+ res.send(e.stack)
76
+ }
77
+ })
78
+ } else {
79
+ options.baseUrl = options.baseUrl || '/'
80
+ fastify.register(fastifyStatic, {
81
+ root: new URL('./dist/ssr/client', options.appDir).pathname,
82
+ wildcard: false,
83
+ index: false,
84
+ prefix: options.baseUrl
85
+ })
86
+
87
+ fastify.get(`${options.baseUrl}*`, async (req, res) => {
88
+ const url = req.raw.url
89
+ const provide = options.provide ? await options.provide(req, res) : {}
90
+ const ssrContext: Record<string, any> = {
91
+ req,
92
+ res,
93
+ provide
94
+ }
95
+
96
+ // template = readFileSync(new URL('../client/index.html', import.meta.url).pathname).toString()
97
+ // manifest = JSON.parse(readFileSync(new URL('../client/ssr-manifest.json', import.meta.url)).toString())
98
+ // render = (await import(new URL('./entry-server.mjs', import.meta.url).pathname)).render
99
+ const template = readFileSync(
100
+ new URL('./dist/ssr/client/index.html', options.appDir).pathname
101
+ ).toString()
102
+ const manifest = JSON.parse(
103
+ readFileSync(
104
+ new URL('./dist/ssr/client/ssr-manifest.json', options.appDir)
105
+ ).toString()
106
+ )
107
+ const render = (
108
+ await import(
109
+ new URL('./dist/ssr/server/entry-server.mjs', options.appDir).pathname
110
+ )
111
+ ).render
112
+
113
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
114
+
115
+ if (!ssrContext.initialState) ssrContext.initialState = {}
116
+ ssrContext.initialState.provide = provide
117
+
118
+ let html = template
119
+ .replace(`<!--preload-links-->`, preloadLinks)
120
+ .replace(`<!--app-html-->`, appHtml)
121
+
122
+ if (options.ssrFunctions?.length) {
123
+ for (const ssrFunction of options.ssrFunctions) {
124
+ html = ssrFunction(html, ssrContext)
125
+ }
126
+ }
127
+
128
+ res.code(200)
129
+ res.type('text/html')
130
+ res.send(html)
131
+ })
132
+ }
133
+
134
+ done()
135
+ }
136
+
137
+ export { fastifySsrPlugin }
@@ -0,0 +1,49 @@
1
+ import { promises as fs } from 'fs'
2
+ import { routesToPaths } from '../../helpers/routes.js'
3
+ import type { SsrFunction } from '../../vitrify-config.js'
4
+
5
+ export const prerender = async ({
6
+ outDir,
7
+ templatePath,
8
+ manifestPath,
9
+ entryServerPath,
10
+ ssrFunctions
11
+ }: {
12
+ outDir: string
13
+ templatePath: string
14
+ manifestPath: string
15
+ entryServerPath: string
16
+ ssrFunctions: SsrFunction[]
17
+ }) => {
18
+ const promises = []
19
+ const template = (await fs.readFile(templatePath)).toString()
20
+ const manifest = await fs.readFile(manifestPath)
21
+ const { render, getRoutes } = await import(entryServerPath)
22
+ const routes = await getRoutes()
23
+ const paths = routesToPaths(routes).filter(
24
+ (i) => !i.includes(':') && !i.includes('*')
25
+ )
26
+ for (const url of paths) {
27
+ const filename =
28
+ (url.endsWith('/') ? 'index' : url.replace(/^\//g, '')) + '.html'
29
+ console.log(`Generating ${filename}`)
30
+ const ssrContext = {
31
+ req: { headers: {}, url },
32
+ res: {}
33
+ }
34
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
35
+
36
+ let html = template
37
+ .replace(`<!--preload-links-->`, preloadLinks)
38
+ .replace(`<!--app-html-->`, appHtml)
39
+
40
+ if (ssrFunctions?.length) {
41
+ for (const ssrFunction of ssrFunctions) {
42
+ html = ssrFunction(html, ssrContext)
43
+ }
44
+ }
45
+
46
+ promises.push(fs.writeFile(outDir + filename, html, 'utf-8'))
47
+ }
48
+ return Promise.all(promises)
49
+ }
@@ -0,0 +1,38 @@
1
+ import type { FastifyInstance } from 'fastify'
2
+ import fastify from 'fastify'
3
+ import type { SsrFunction } from '../../vitrify-config.js'
4
+ // import { setup } from 'virtual:fastify-setup'
5
+ import { fastifySsrPlugin } from './fastify-ssr-plugin.js'
6
+ // import { getPkgJsonDir } from '../app-urls.js'
7
+
8
+ export const createApp = ({
9
+ setup,
10
+ appDir,
11
+ baseUrl,
12
+ ssrFunctions
13
+ }: {
14
+ setup: (fastify: FastifyInstance) => any
15
+ appDir: URL
16
+ baseUrl?: string
17
+ ssrFunctions?: SsrFunction[]
18
+ }) => {
19
+ const app = fastify({
20
+ logger: true
21
+ })
22
+
23
+ app.register(fastifySsrPlugin, {
24
+ baseUrl,
25
+ appDir,
26
+ ssrFunctions
27
+ })
28
+
29
+ setup(app)
30
+
31
+ return app
32
+ }
33
+
34
+ // const app = createApp({
35
+ // setup
36
+ // })
37
+
38
+ // app.listen(process.env.PORT || 3000, process.env.HOST || '127.0.0.1')