vitrify 0.2.4 → 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 (47) hide show
  1. package/dist/app-urls.js +1 -2
  2. package/dist/bin/build.js +0 -43
  3. package/dist/bin/cli.js +29 -7
  4. package/dist/bin/dev.js +58 -67
  5. package/dist/frameworks/vue/fastify-ssr-plugin.js +67 -23
  6. package/dist/frameworks/vue/prerender.js +3 -3
  7. package/dist/frameworks/vue/server.js +9 -10
  8. package/dist/helpers/collect-css-ssr.js +57 -0
  9. package/dist/helpers/logger.js +0 -72
  10. package/dist/index.js +268 -122
  11. package/dist/plugins/quasar.js +13 -106
  12. package/dist/types/bin/build.d.ts +2 -2
  13. package/dist/types/bin/dev.d.ts +39 -3
  14. package/dist/types/frameworks/vue/fastify-ssr-plugin.d.ts +6 -3
  15. package/dist/types/frameworks/vue/prerender.d.ts +3 -3
  16. package/dist/types/frameworks/vue/server.d.ts +9 -5
  17. package/dist/types/helpers/collect-css-ssr.d.ts +10 -0
  18. package/dist/types/helpers/logger.d.ts +0 -19
  19. package/dist/types/helpers/routes.d.ts +1 -1
  20. package/dist/types/index.d.ts +1 -1
  21. package/dist/types/plugins/index.d.ts +1 -1
  22. package/dist/types/vitrify-config.d.ts +20 -16
  23. package/package.json +32 -32
  24. package/src/node/app-urls.ts +1 -2
  25. package/src/node/bin/build.ts +2 -49
  26. package/src/node/bin/cli.ts +36 -8
  27. package/src/node/bin/dev.ts +89 -75
  28. package/src/node/bin/test.ts +0 -3
  29. package/src/node/frameworks/vue/fastify-ssr-plugin.ts +80 -26
  30. package/src/node/frameworks/vue/prerender.ts +5 -5
  31. package/src/node/frameworks/vue/server.ts +22 -16
  32. package/src/node/helpers/collect-css-ssr.ts +77 -0
  33. package/src/node/helpers/logger.ts +0 -87
  34. package/src/node/index.ts +302 -137
  35. package/src/node/plugins/index.ts +1 -1
  36. package/src/node/plugins/quasar.ts +14 -111
  37. package/src/node/vitrify-config.ts +31 -16
  38. package/src/vite/fastify/entry.ts +11 -0
  39. package/src/vite/fastify/server.ts +10 -0
  40. package/src/vite/vue/index.html +1 -0
  41. package/src/vite/vue/main.ts +5 -20
  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/fastify-ssr-plugin.ts +2 -118
  45. package/src/vite/vue/ssr/prerender.ts +2 -2
  46. package/src/vite/vue/ssr/server.ts +24 -15
  47. package/src/node/helpers/ssr.ts.bak +0 -52
package/dist/app-urls.js CHANGED
@@ -12,10 +12,9 @@ export const getCliDir = () => getPkgJsonDir(new URL('./', import.meta.url));
12
12
  export const getCliViteDir = (cliDir) => new URL('src/vite/', cliDir);
13
13
  export const getSrcDir = (appDir) => new URL('src/', appDir);
14
14
  export const getCwd = () => new URL(`file://${process.cwd()}/`);
15
- // export const quasarDir = getPkgJsonDir(new URL('./', await resolve('quasar', appDir.href)))
16
15
  export const parsePath = (path, basePath) => {
17
16
  if (path) {
18
- if (path.slice(-1) !== '/')
17
+ if (!path.includes('.') && path.slice(-1) !== '/')
19
18
  path += '/';
20
19
  if (path.startsWith('.')) {
21
20
  return new URL(path, basePath);
package/dist/bin/build.js CHANGED
@@ -1,49 +1,6 @@
1
1
  #!/usr/bin/node --experimental-specifier-resolution=node
2
2
  import { baseConfig } from '../index.js';
3
- // import { promises as fs } from 'fs'
4
- // import { routesToPaths } from '../helpers/routes.js'
5
3
  import { build as viteBuild } from 'vite';
6
- // import { SsrFunction } from '../vitrify-config.js'
7
- // export const prerender = async ({
8
- // outDir,
9
- // templatePath,
10
- // manifestPath,
11
- // entryServerPath,
12
- // injectSsrContext
13
- // }: {
14
- // outDir: string
15
- // templatePath: string
16
- // manifestPath: string
17
- // entryServerPath: string
18
- // injectSsrContext: SsrFunction
19
- // }) => {
20
- // let template
21
- // let manifest
22
- // const promises = []
23
- // template = (await fs.readFile(templatePath)).toString()
24
- // manifest = await fs.readFile(manifestPath)
25
- // let { render, getRoutes } = await import(entryServerPath)
26
- // const routes = await getRoutes()
27
- // const paths = routesToPaths(routes).filter(
28
- // (i) => !i.includes(':') && !i.includes('*')
29
- // )
30
- // for (let url of paths) {
31
- // const filename =
32
- // (url.endsWith('/') ? 'index' : url.replace(/^\//g, '')) + '.html'
33
- // console.log(`Generating ${filename}`)
34
- // const ssrContext = {
35
- // req: { headers: {}, url },
36
- // res: {}
37
- // }
38
- // const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
39
- // let html = template
40
- // .replace(`<!--preload-links-->`, preloadLinks)
41
- // .replace(`<!--app-html-->`, appHtml)
42
- // html = injectSsrContext(html, ssrContext)
43
- // promises.push(fs.writeFile(outDir + filename, html, 'utf-8'))
44
- // }
45
- // return Promise.all(promises)
46
- // }
47
4
  export async function build(opts) {
48
5
  const config = await baseConfig({
49
6
  command: 'build',
package/dist/bin/cli.js CHANGED
@@ -14,7 +14,7 @@ cli
14
14
  .action(async (options) => {
15
15
  const { build } = await import('./build.js');
16
16
  let appDir;
17
- let prerender, ssrFunctions;
17
+ let prerender, onRenderedHooks;
18
18
  if (options.appDir) {
19
19
  if (options.appDir.slice(-1) !== '/')
20
20
  options.appDir += '/';
@@ -36,6 +36,13 @@ cli
36
36
  outDir: new URL('spa/', baseOutDir).pathname
37
37
  });
38
38
  break;
39
+ case 'fastify':
40
+ await build({
41
+ ssr: 'fastify',
42
+ ...args,
43
+ outDir: new URL('server/', baseOutDir).pathname
44
+ });
45
+ break;
39
46
  case 'ssr':
40
47
  await build({
41
48
  ssr: 'client',
@@ -59,7 +66,7 @@ cli
59
66
  ...args,
60
67
  outDir: new URL('ssr/server/', baseOutDir).pathname
61
68
  });
62
- ({ prerender, ssrFunctions } = await import(new URL('ssr/server/prerender.mjs', baseOutDir).pathname));
69
+ ({ prerender, onRenderedHooks } = await import(new URL('ssr/server/prerender.mjs', baseOutDir).pathname));
63
70
  prerender({
64
71
  outDir: new URL('static/', baseOutDir).pathname,
65
72
  templatePath: new URL('static/index.html', baseOutDir).pathname,
@@ -67,7 +74,7 @@ cli
67
74
  .pathname,
68
75
  entryServerPath: new URL('ssr/server/entry-server.mjs', baseOutDir)
69
76
  .pathname,
70
- ssrFunctions
77
+ onRenderedHooks
71
78
  });
72
79
  break;
73
80
  default:
@@ -80,28 +87,43 @@ cli
80
87
  .option('-m, --mode [mode]', 'Development server mode', { default: 'csr' })
81
88
  .option('--host [host]', 'Specify which IP addresses the server should listen on', { default: '127.0.0.1' })
82
89
  .option('--appDir [appDir]', 'Application directory')
90
+ .option('--app [app]', 'Fastify app instance path')
83
91
  .option('--publicDir [publicDir]', 'Public directory')
84
92
  .action(async (options) => {
85
93
  let server;
86
- let vite;
94
+ let config;
87
95
  if (options.host === true) {
88
96
  options.host = '0.0.0.0';
89
97
  }
90
98
  const { createServer } = await import('./dev.js');
91
99
  const cwd = (await import('../app-urls.js')).getCwd();
100
+ let app;
101
+ const appPath = parsePath(options.app, cwd)?.pathname;
102
+ if (appPath) {
103
+ app = await import(appPath);
104
+ }
92
105
  switch (options.mode) {
93
106
  case 'ssr':
94
107
  ;
95
- ({ server, vite } = await createServer({
108
+ ({ server, config } = await createServer({
96
109
  mode: 'ssr',
97
110
  host: options.host,
98
111
  appDir: parsePath(options.appDir, cwd),
99
112
  publicDir: parsePath(options.publicDir, cwd)
100
113
  }));
101
114
  break;
115
+ case 'fastify':
116
+ ;
117
+ ({ server, config } = await createServer({
118
+ mode: 'fastify',
119
+ host: options.host,
120
+ appDir: parsePath(options.appDir, cwd),
121
+ publicDir: parsePath(options.publicDir, cwd)
122
+ }));
123
+ break;
102
124
  default:
103
125
  ;
104
- ({ server, vite } = await createServer({
126
+ ({ server, config } = await createServer({
105
127
  host: options.host,
106
128
  appDir: parsePath(options.appDir, cwd),
107
129
  publicDir: parsePath(options.publicDir, cwd)
@@ -109,7 +131,7 @@ cli
109
131
  break;
110
132
  }
111
133
  console.log('Dev server running at:');
112
- printHttpServerUrls(server, vite.config);
134
+ printHttpServerUrls(server, config);
113
135
  });
114
136
  cli.command('test').action(async (options) => {
115
137
  const { test } = await import('./test.js');
package/dist/bin/dev.js CHANGED
@@ -1,19 +1,20 @@
1
1
  import { searchForWorkspaceRoot } from 'vite';
2
2
  import { baseConfig } from '../index.js';
3
3
  import fastify from 'fastify';
4
- import { readFileSync } from 'fs';
5
- export async function createServer({ port = 3000, logLevel = 'info', mode = 'csr', framework = 'vue', host, appDir, publicDir }) {
6
- const { getAppDir, getCliDir, getCwd } = await import('../app-urls.js');
7
- const cwd = getCwd();
4
+ export async function createVitrifyDevServer({ port = 3000, logLevel = 'info', mode = 'csr', framework = 'vue', host, appDir, publicDir }) {
5
+ const { getAppDir, getCliDir, getCliViteDir, getCwd } = await import('../app-urls.js');
8
6
  const cliDir = getCliDir();
9
7
  if (!appDir)
10
8
  appDir = getAppDir();
11
- const { fastifySsrPlugin } = await import(`../${framework}/fastify-ssr-plugin.js`);
12
- /**
13
- * @type {import('vite').ViteDevServer}
14
- */
15
- const config = await baseConfig({
16
- ssr: mode === 'ssr' ? 'server' : undefined,
9
+ let config = {};
10
+ let ssrMode;
11
+ if (mode === 'ssr')
12
+ ssrMode = 'server';
13
+ if (mode === 'fastify')
14
+ ssrMode = 'fastify';
15
+ config = await baseConfig({
16
+ framework,
17
+ ssr: ssrMode,
17
18
  command: 'dev',
18
19
  mode: 'development',
19
20
  appDir,
@@ -21,12 +22,16 @@ export async function createServer({ port = 3000, logLevel = 'info', mode = 'csr
21
22
  });
22
23
  config.logLevel = logLevel;
23
24
  config.server = {
25
+ https: config.server?.https,
24
26
  port,
25
- middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
27
+ // middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
28
+ middlewareMode: mode !== 'csr' ? 'ssr' : false,
26
29
  fs: {
27
30
  allow: [
28
31
  searchForWorkspaceRoot(process.cwd()),
29
- searchForWorkspaceRoot(appDir.pathname),
32
+ ...(Array.isArray(appDir)
33
+ ? appDir.map((dir) => searchForWorkspaceRoot(dir.pathname))
34
+ : [searchForWorkspaceRoot(appDir.pathname)]),
30
35
  searchForWorkspaceRoot(cliDir.pathname)
31
36
  // appDir.pathname,
32
37
  ]
@@ -39,70 +44,56 @@ export async function createServer({ port = 3000, logLevel = 'info', mode = 'csr
39
44
  },
40
45
  host
41
46
  };
42
- const vite = await (await import('vite')).createServer({
47
+ const vitrifyDevServer = await (await import('vite')).createServer({
43
48
  configFile: false,
44
49
  ...config
45
50
  });
46
- const { productName = 'Product name' } = JSON.parse(readFileSync(new URL('package.json', appDir).pathname, {
47
- encoding: 'utf-8'
48
- }));
49
- let app;
51
+ return vitrifyDevServer;
52
+ }
53
+ export async function createServer({ port = 3000, logLevel = 'info', mode = 'csr', framework = 'vue', host, appDir, publicDir }) {
54
+ const { getAppDir, getCliDir, getCliViteDir, getCwd } = await import('../app-urls.js');
55
+ const cliDir = getCliDir();
56
+ const vite = await createVitrifyDevServer({
57
+ port,
58
+ logLevel,
59
+ mode,
60
+ framework,
61
+ host,
62
+ appDir,
63
+ publicDir
64
+ });
65
+ let entryUrl;
66
+ let setup;
50
67
  let server;
51
- if (mode === 'ssr') {
52
- console.log('SSR mode');
53
- app = fastify();
54
- await app.register(fastifySsrPlugin, {
55
- appDir,
56
- cliDir,
57
- vite,
58
- productName
68
+ console.log(`Development mode: ${mode}`);
69
+ if (['ssr', 'fastify'].includes(mode)) {
70
+ const entryUrl = mode === 'fastify'
71
+ ? new URL('src/vite/fastify/entry.ts', cliDir).pathname
72
+ : new URL(`src/vite/${framework}/ssr/entry-server.ts`, cliDir).pathname;
73
+ ({ setup } = await vite.ssrLoadModule(entryUrl));
74
+ const app = fastify({
75
+ https: typeof vite.config.server.https === 'object'
76
+ ? vite.config.server.https
77
+ : {}
59
78
  });
60
- // await app.register(middie)
61
- // app.use(vite.middlewares)
62
- // app.get('*', async (req, res) => {
63
- // try {
64
- // // const url = req.originalUrl
65
- // const url = req.raw.url
66
- // let template
67
- // let render
68
- // const ssrContext = {
69
- // req,
70
- // res
71
- // }
72
- // // always read fresh template in dev
73
- // // template = readFileSync(resolve('index.html'), 'utf-8')
74
- // template = readFileSync(new URL('index.html', cliDir)).toString()
75
- // // template = await vite.transformIndexHtml(url, template)
76
- // const entryUrl = new URL('ssr/entry-server.ts', cliDir).pathname
77
- // render = (await vite.ssrLoadModule(entryUrl)).render
78
- // let manifest
79
- // // TODO: https://github.com/vitejs/vite/issues/2282
80
- // try {
81
- // manifest = {}
82
- // } catch (e) {
83
- // manifest = {}
84
- // }
85
- // const [appHtml, preloadLinks] = await render(url, manifest, ssrContext)
86
- // const html = template
87
- // .replace(`<!--preload-links-->`, preloadLinks)
88
- // .replace(`<!--app-html-->`, appHtml)
89
- // .replace('<!--product-name-->', productName)
90
- // res.code(200)
91
- // res.type('text/html')
92
- // res.send(html)
93
- // // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
94
- // } catch (e: any) {
95
- // console.error(e.stack)
96
- // vite && vite.ssrFixStacktrace(e)
97
- // res.code(500)
98
- // res.send(e.stack)
99
- // }
79
+ if (setup) {
80
+ await setup({
81
+ fastify: app
82
+ });
83
+ }
84
+ // await app.register(fastifySsrPlugin, {
85
+ // appDir,
86
+ // vitrifyDir: new URL('../..', import.meta.url),
87
+ // mode: 'development'
100
88
  // })
101
- await app.listen(port || 3000, host);
89
+ await app.listen({
90
+ port: Number(port || 3000),
91
+ host
92
+ });
102
93
  server = app.server;
103
94
  }
104
95
  else {
105
96
  server = (await vite.listen()).httpServer;
106
97
  }
107
- return { server, vite };
98
+ return { server, config: vite.config };
108
99
  }
@@ -1,26 +1,66 @@
1
- import fastifyStatic from 'fastify-static';
1
+ import fastifyStatic from '@fastify/static';
2
2
  import { readFileSync } from 'fs';
3
+ import { componentsModules, collectCss } from '../../helpers/collect-css-ssr.js';
3
4
  const fastifySsrPlugin = async (fastify, options, done) => {
4
- if (import.meta.env.MODE === 'development') {
5
- if (!options.vite)
6
- throw new Error('Option vite cannot be undefined');
7
- const middie = (await import('middie')).default;
5
+ options.vitrifyDir =
6
+ options.vitrifyDir || new URL('../../..', import.meta.url);
7
+ const frameworkDir = new URL('vite/vue/', options.vitrifyDir);
8
+ options.baseUrl = options.baseUrl || '/';
9
+ if (options.baseUrl.charAt(options.baseUrl.length - 1) !== '/' ||
10
+ options.baseUrl.charAt(0) !== '/')
11
+ throw new Error('baseUrl should start and end with a /');
12
+ if (options.mode === 'development') {
13
+ if (!options.vitrifyDir)
14
+ throw new Error('Option vitrifyDir cannot be undefined');
15
+ // if (!options.vite) throw new Error('Option vite cannot be undefined')
16
+ // const { resolve } = await import('import-meta-resolve')
17
+ // const cliDir = new URL('../', await resolve('vitrify', import.meta.url))
18
+ options.appDir = options.appDir || new URL('../../..', import.meta.url);
19
+ const { createServer, searchForWorkspaceRoot } = await import('vite');
20
+ const { baseConfig } = await import('vitrify');
21
+ const cliDir = options.vitrifyDir;
22
+ const config = await baseConfig({
23
+ ssr: 'server',
24
+ command: 'dev',
25
+ mode: 'development',
26
+ appDir: options.appDir,
27
+ publicDir: options.publicDir || new URL('public', options.appDir)
28
+ });
29
+ config.server = {
30
+ middlewareMode: true,
31
+ fs: {
32
+ allow: [
33
+ searchForWorkspaceRoot(process.cwd()),
34
+ searchForWorkspaceRoot(options.appDir.pathname),
35
+ searchForWorkspaceRoot(cliDir.pathname)
36
+ // appDir.pathname,
37
+ ]
38
+ },
39
+ watch: {
40
+ // During tests we edit the files too fast and sometimes chokidar
41
+ // misses change events, so enforce polling for consistency
42
+ usePolling: true,
43
+ interval: 100
44
+ }
45
+ };
46
+ const vite = await createServer({
47
+ configFile: false,
48
+ ...config
49
+ });
50
+ console.log('Dev mode');
51
+ const middie = (await import('@fastify/middie')).default;
8
52
  await fastify.register(middie);
9
- fastify.use(options.vite.middlewares);
10
- fastify.get('*', async (req, res) => {
53
+ fastify.use(vite.middlewares);
54
+ fastify.get(`${options.baseUrl}*`, async (req, res) => {
11
55
  try {
12
- // const url = req.originalUrl
13
56
  const url = req.raw.url;
14
57
  const ssrContext = {
15
58
  req,
16
59
  res
17
60
  };
18
- // always read fresh template in dev
19
- // template = readFileSync(resolve('index.html'), 'utf-8')
20
- const template = readFileSync(new URL('index.html', options.cliDir)).toString();
21
- // template = await vite.transformIndexHtml(url, template)
22
- const entryUrl = new URL('ssr/entry-server.ts', options.cliDir).pathname;
23
- const render = (await options.vite.ssrLoadModule(entryUrl)).render;
61
+ const template = readFileSync(new URL('index.html', frameworkDir)).toString();
62
+ const entryUrl = new URL('ssr/entry-server.ts', frameworkDir).pathname;
63
+ const render = (await vite.ssrLoadModule(entryUrl)).render;
24
64
  let manifest;
25
65
  // TODO: https://github.com/vitejs/vite/issues/2282
26
66
  try {
@@ -29,11 +69,18 @@ const fastifySsrPlugin = async (fastify, options, done) => {
29
69
  catch (e) {
30
70
  manifest = {};
31
71
  }
72
+ const cssModules = [entryUrl];
73
+ // // @ts-ignore
74
+ // if (options.vite?.config.vitrify!.globalCss)
75
+ // cssModules.push(...options.vite?.config.vitrify.globalCss)
76
+ const matchedModules = componentsModules(cssModules, vite);
77
+ const css = collectCss(matchedModules);
32
78
  const [appHtml, preloadLinks] = await render(url, manifest, ssrContext);
33
79
  const html = template
34
80
  .replace(`<!--preload-links-->`, preloadLinks)
35
81
  .replace(`<!--app-html-->`, appHtml)
36
- .replace('<!--product-name-->', options.productName || 'Product name');
82
+ .replace('<!--product-name-->', options.productName || 'Product name')
83
+ .replace('<!--dev-ssr-css-->', css);
37
84
  res.code(200);
38
85
  res.type('text/html');
39
86
  res.send(html);
@@ -41,14 +88,14 @@ const fastifySsrPlugin = async (fastify, options, done) => {
41
88
  }
42
89
  catch (e) {
43
90
  console.error(e.stack);
44
- options.vite && options.vite.ssrFixStacktrace(e);
91
+ vite && vite.ssrFixStacktrace(e);
45
92
  res.code(500);
46
93
  res.send(e.stack);
47
94
  }
48
95
  });
49
96
  }
50
97
  else {
51
- options.baseUrl = options.baseUrl || '/';
98
+ options.appDir = options.appDir || new URL('../../..', import.meta.url);
52
99
  fastify.register(fastifyStatic, {
53
100
  root: new URL('./dist/ssr/client', options.appDir).pathname,
54
101
  wildcard: false,
@@ -56,16 +103,13 @@ const fastifySsrPlugin = async (fastify, options, done) => {
56
103
  prefix: options.baseUrl
57
104
  });
58
105
  fastify.get(`${options.baseUrl}*`, async (req, res) => {
59
- const url = req.raw.url;
106
+ const url = req.raw.url?.replace(options.baseUrl, '/');
60
107
  const provide = options.provide ? await options.provide(req, res) : {};
61
108
  const ssrContext = {
62
109
  req,
63
110
  res,
64
111
  provide
65
112
  };
66
- // template = readFileSync(new URL('../client/index.html', import.meta.url).pathname).toString()
67
- // manifest = JSON.parse(readFileSync(new URL('../client/ssr-manifest.json', import.meta.url)).toString())
68
- // render = (await import(new URL('./entry-server.mjs', import.meta.url).pathname)).render
69
113
  const template = readFileSync(new URL('./dist/ssr/client/index.html', options.appDir).pathname).toString();
70
114
  const manifest = JSON.parse(readFileSync(new URL('./dist/ssr/client/ssr-manifest.json', options.appDir)).toString());
71
115
  const render = (await import(new URL('./dist/ssr/server/entry-server.mjs', options.appDir).pathname)).render;
@@ -76,8 +120,8 @@ const fastifySsrPlugin = async (fastify, options, done) => {
76
120
  let html = template
77
121
  .replace(`<!--preload-links-->`, preloadLinks)
78
122
  .replace(`<!--app-html-->`, appHtml);
79
- if (options.ssrFunctions?.length) {
80
- for (const ssrFunction of options.ssrFunctions) {
123
+ if (options.onRendered?.length) {
124
+ for (const ssrFunction of options.onRendered) {
81
125
  html = ssrFunction(html, ssrContext);
82
126
  }
83
127
  }
@@ -1,6 +1,6 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import { routesToPaths } from '../../helpers/routes.js';
3
- export const prerender = async ({ outDir, templatePath, manifestPath, entryServerPath, ssrFunctions }) => {
3
+ export const prerender = async ({ outDir, templatePath, manifestPath, entryServerPath, onRenderedHooks }) => {
4
4
  const promises = [];
5
5
  const template = (await fs.readFile(templatePath)).toString();
6
6
  const manifest = await fs.readFile(manifestPath);
@@ -18,8 +18,8 @@ export const prerender = async ({ outDir, templatePath, manifestPath, entryServe
18
18
  let html = template
19
19
  .replace(`<!--preload-links-->`, preloadLinks)
20
20
  .replace(`<!--app-html-->`, appHtml);
21
- if (ssrFunctions?.length) {
22
- for (const ssrFunction of ssrFunctions) {
21
+ if (onRenderedHooks?.length) {
22
+ for (const ssrFunction of onRenderedHooks) {
23
23
  html = ssrFunction(html, ssrContext);
24
24
  }
25
25
  }
@@ -1,20 +1,19 @@
1
1
  import fastify from 'fastify';
2
- // import { setup } from 'virtual:fastify-setup'
3
- import { fastifySsrPlugin } from './fastify-ssr-plugin.js';
4
- // import { getPkgJsonDir } from '../app-urls.js'
5
- export const createApp = ({ setup, appDir, baseUrl, ssrFunctions }) => {
2
+ export const createApp = ({ onSetup, appDir, baseUrl, onRendered, fastifySsrPlugin, vitrifyDir, mode }) => {
6
3
  const app = fastify({
7
4
  logger: true
8
5
  });
9
6
  app.register(fastifySsrPlugin, {
10
7
  baseUrl,
11
8
  appDir,
12
- ssrFunctions
9
+ onRendered,
10
+ vitrifyDir,
11
+ mode
13
12
  });
14
- setup(app);
13
+ // if (onSetup?.length) {
14
+ // for (const setup of onSetup) {
15
+ // setup(app)
16
+ // }
17
+ // }
15
18
  return app;
16
19
  };
17
- // const app = createApp({
18
- // setup
19
- // })
20
- // app.listen(process.env.PORT || 3000, process.env.HOST || '127.0.0.1')
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Collect SSR CSS for Vite
3
+ */
4
+ export const componentsModules = (components, vite) => {
5
+ const matchedModules = new Set();
6
+ components.forEach((component) => {
7
+ const modules = vite.moduleGraph.getModulesByFile(component);
8
+ modules?.forEach((mod) => matchedModules.add(mod));
9
+ });
10
+ return matchedModules;
11
+ };
12
+ export const collectCss = (mods, styles = new Map(), checkedComponents = new Set()) => {
13
+ for (const mod of mods) {
14
+ if ((mod.file?.endsWith('.scss') ||
15
+ mod.file?.endsWith('.css') ||
16
+ mod.id?.includes('vue&type=style')) &&
17
+ mod.ssrModule) {
18
+ styles.set(mod.url, mod.ssrModule.default);
19
+ }
20
+ if (mod.importedModules.size > 0 && !checkedComponents.has(mod.id)) {
21
+ checkedComponents.add(mod.id);
22
+ collectCss(mod.importedModules, styles, checkedComponents);
23
+ }
24
+ }
25
+ let result = '';
26
+ styles.forEach((content, id) => {
27
+ const styleTag = `<style type="text/css" vite-module-id="${hashCode(id)}">${content}</style>`;
28
+ result = result.concat(styleTag);
29
+ });
30
+ return result;
31
+ };
32
+ /**
33
+ * Client listener to detect updated modules through HMR, and remove the initial styled attached to the head
34
+ */
35
+ export const removeCssHotReloaded = () => {
36
+ if (import.meta.hot) {
37
+ import.meta.hot.on('vite:beforeUpdate', (module) => {
38
+ module.updates.forEach((update) => {
39
+ const moduleStyle = document.querySelector(`[vite-module-id="${hashCode(update.acceptedPath)}"]`);
40
+ if (moduleStyle) {
41
+ moduleStyle.remove();
42
+ }
43
+ });
44
+ });
45
+ }
46
+ };
47
+ const hashCode = (moduleId) => {
48
+ let hash = 0, i, chr;
49
+ if (moduleId.length === 0)
50
+ return hash;
51
+ for (i = 0; i < moduleId.length; i++) {
52
+ chr = moduleId.charCodeAt(i);
53
+ hash = (hash << 5) - hash + chr;
54
+ hash |= 0; // Convert to 32bit integer
55
+ }
56
+ return hash;
57
+ };
@@ -1,79 +1,7 @@
1
1
  // https://github.com/quasarframework/quasar/blob/dev/app/lib/helpers/logger.js
2
2
  import chalk from 'chalk';
3
- const { bgGreen, green, inverse, bgRed, red, bgYellow, yellow } = chalk;
4
- import readline from 'readline';
5
3
  import os from 'os';
6
4
  import { resolveHostname } from '../helpers/utils.js';
7
- /**
8
- * Main approach - App CLI related
9
- */
10
- const dot = '•';
11
- const banner = 'App ' + dot;
12
- const greenBanner = green(banner);
13
- const redBanner = red(banner);
14
- const yellowBanner = yellow(banner);
15
- export const clearConsole = process.stdout.isTTY
16
- ? () => {
17
- // Fill screen with blank lines. Then move to 0 (beginning of visible part) and clear it
18
- const blank = '\n'.repeat(process.stdout.rows);
19
- console.log(blank);
20
- readline.cursorTo(process.stdout, 0, 0);
21
- readline.clearScreenDown(process.stdout);
22
- }
23
- : () => { };
24
- export const log = function (msg) {
25
- console.log(msg ? ` ${greenBanner} ${msg}` : '');
26
- };
27
- export const warn = function (msg, pill) {
28
- if (msg !== void 0) {
29
- const pillBanner = pill !== void 0 ? bgYellow.black('', pill, '') + ' ' : '';
30
- console.warn(` ${yellowBanner} ⚠️ ${pillBanner}${msg}`);
31
- }
32
- else {
33
- console.warn();
34
- }
35
- };
36
- export const fatal = function (msg, pill) {
37
- if (msg !== void 0) {
38
- const pillBanner = pill !== void 0 ? errorPill(pill) + ' ' : '';
39
- console.error(`\n ${redBanner} ⚠️ ${pillBanner}${msg}\n`);
40
- }
41
- else {
42
- console.error();
43
- }
44
- process.exit(1);
45
- };
46
- /**
47
- * Extended approach - Compilation status & pills
48
- */
49
- export const successPill = (msg) => bgGreen.black('', msg, '');
50
- export const infoPill = (msg) => inverse('', msg, '');
51
- export const errorPill = (msg) => bgRed.white('', msg, '');
52
- export const warningPill = (msg) => bgYellow.black('', msg, '');
53
- export const success = function (msg, title = 'SUCCESS') {
54
- console.log(` ${greenBanner} ${successPill(title)} ${green(dot + ' ' + msg)}`);
55
- };
56
- export const getSuccess = function (msg, title) {
57
- return ` ${greenBanner} ${successPill(title)} ${green(dot + ' ' + msg)}`;
58
- };
59
- export const info = function (msg, title = 'INFO') {
60
- console.log(` ${greenBanner} ${infoPill(title)} ${green(dot)} ${msg}`);
61
- };
62
- export const getInfo = function (msg, title) {
63
- return ` ${greenBanner} ${infoPill(title)} ${green(dot)} ${msg}`;
64
- };
65
- export const error = function (msg, title = 'ERROR') {
66
- console.log(` ${redBanner} ${errorPill(title)} ${red(dot + ' ' + msg)}`);
67
- };
68
- export const getError = function (msg, title = 'ERROR') {
69
- return ` ${redBanner} ${errorPill(title)} ${red(dot + ' ' + msg)}`;
70
- };
71
- export const warning = function (msg, title = 'WARNING') {
72
- console.log(` ${yellowBanner} ${warningPill(title)} ${yellow(dot + ' ' + msg)}`);
73
- };
74
- export const getWarning = function (msg, title = 'WARNING') {
75
- return ` ${yellowBanner} ${warningPill(title)} ${yellow(dot + ' ' + msg)}`;
76
- };
77
5
  export function printHttpServerUrls(server, config) {
78
6
  const address = server.address();
79
7
  const isAddressInfo = (x) => x?.address;