vitrify 0.20.0 → 0.22.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.
@@ -9,6 +9,7 @@ import {
9
9
  } from '../../helpers/utils.js'
10
10
  import type { ViteDevServer } from 'vite'
11
11
  import type { OnRenderedHook } from '../../vitrify-config.js'
12
+ import { getAppDir } from '../../app-urls.js'
12
13
 
13
14
  type ProvideFn = (
14
15
  req: FastifyRequest,
@@ -78,7 +79,10 @@ const fastifySsrPlugin: FastifyPluginAsync<FastifySsrOptions> = async (
78
79
  const entryUrl = fileURLToPath(
79
80
  new URL('ssr/entry-server.ts', frameworkDir)
80
81
  )
81
- const render = (await vite!.ssrLoadModule(entryUrl)).render
82
+ const environment = vite.environments.ssr
83
+ // @ts-expect-error missing type
84
+ const { render } = await environment.runner.import(entryUrl)
85
+ // const render = (await vite!.ssrLoadModule(entryUrl)).render
82
86
  let manifest
83
87
  // TODO: https://github.com/vitejs/vite/issues/2282
84
88
  try {
@@ -123,31 +127,9 @@ const fastifySsrPlugin: FastifyPluginAsync<FastifySsrOptions> = async (
123
127
  const url = req.raw.url?.replace(options.baseUrl!, '/')
124
128
  const provide = options.provide ? await options.provide(req, res) : {}
125
129
 
126
- const template = readFileSync(
127
- fileURLToPath(new URL('./dist/ssr/client/index.html', options.appDir))
128
- ).toString()
129
- const manifest = JSON.parse(
130
- readFileSync(
131
- new URL('./dist/ssr/client/.vite/ssr-manifest.json', options.appDir)
132
- ).toString()
133
- )
134
- const render = (
135
- await import(
136
- fileURLToPath(
137
- new URL('./dist/ssr/server/entry-server.mjs', options.appDir)
138
- )
139
- )
140
- ).render
141
- const onRendered = (
142
- await import(
143
- fileURLToPath(
144
- new URL(
145
- './dist/ssr/server/virtual_vitrify-hooks.mjs',
146
- options.appDir
147
- )
148
- )
149
- )
150
- ).onRendered
130
+ const { template, manifest, render, onRendered } = await loadSSRAssets({
131
+ distDir: new URL('./dist/', options.appDir)
132
+ })
151
133
 
152
134
  const html = await renderHtml({
153
135
  request: req,
@@ -232,5 +214,60 @@ const renderHtml = async (options: {
232
214
  return html
233
215
  }
234
216
 
235
- export { fastifySsrPlugin, renderHtml }
217
+ const loadSSRAssets = async (
218
+ {
219
+ mode,
220
+ distDir
221
+ }: {
222
+ mode?: 'ssr' | 'ssg'
223
+ distDir?: URL
224
+ } = {
225
+ mode: 'ssr'
226
+ }
227
+ ) => {
228
+ const appDir = getAppDir(new URL(import.meta.url))
229
+ const baseOutDir = distDir || new URL('dist/', appDir)
230
+
231
+ let templatePath, manifestPath, entryServerPath
232
+ const onRenderedPath = fileURLToPath(
233
+ new URL('ssr/server/virtual_vitrify-hooks.mjs', baseOutDir)
234
+ )
235
+ if (mode === 'ssg') {
236
+ templatePath = fileURLToPath(new URL('static/index.html', baseOutDir))
237
+ manifestPath = fileURLToPath(
238
+ new URL('static/.vite/ssr-manifest.json', baseOutDir)
239
+ )
240
+ entryServerPath = fileURLToPath(
241
+ new URL('ssr/server/entry-server.mjs', baseOutDir)
242
+ )
243
+ } else {
244
+ templatePath = fileURLToPath(new URL('ssr/client/index.html', baseOutDir))
245
+ manifestPath = fileURLToPath(
246
+ new URL('ssr/client/.vite/ssr-manifest.json', baseOutDir)
247
+ )
248
+ entryServerPath = fileURLToPath(
249
+ new URL('ssr/server/entry-server.mjs', baseOutDir)
250
+ )
251
+ }
252
+ try {
253
+ const template = readFileSync(templatePath).toString()
254
+ const manifest = JSON.parse(readFileSync(manifestPath).toString())
255
+ const entryServer = await import(entryServerPath)
256
+ const { render, getRoutes } = entryServer
257
+ const onRendered = (await import(onRenderedPath)).onRendered
258
+
259
+ return {
260
+ template,
261
+ manifest,
262
+ render,
263
+ getRoutes,
264
+ onRendered
265
+ }
266
+ } catch (e) {
267
+ console.error(e)
268
+ throw new Error('Unable to load SSR asset files')
269
+ }
270
+ }
271
+
272
+ export { fastifySsrPlugin, renderHtml, loadSSRAssets }
236
273
  export type FastifySsrPlugin = typeof fastifySsrPlugin
@@ -2,25 +2,24 @@ import { existsSync, promises as fs, mkdirSync } from 'fs'
2
2
  import type { OnRenderedHook } from 'src/node/vitrify-config.js'
3
3
  import { routesToPaths } from '../../helpers/routes.js'
4
4
  import { renderHtml } from './fastify-ssr-plugin.js'
5
+ import { type RouteRecordRaw } from 'vue-router'
5
6
 
6
7
  export const prerender = async ({
7
8
  outDir,
8
- templatePath,
9
- manifestPath,
10
- entryServerPath,
9
+ template,
10
+ manifest,
11
+ render,
12
+ routes,
11
13
  onRendered
12
14
  }: {
13
15
  outDir: string
14
- templatePath: string
15
- manifestPath: string
16
- entryServerPath: string
16
+ template: string
17
+ manifest: Record<string, unknown>
18
+ render: unknown
19
+ routes: RouteRecordRaw[]
17
20
  onRendered: OnRenderedHook[]
18
21
  }) => {
19
22
  const promises = []
20
- const template = (await fs.readFile(templatePath)).toString()
21
- const manifest = JSON.parse((await fs.readFile(manifestPath)).toString())
22
- const { render, getRoutes } = await import(entryServerPath)
23
- const routes = await getRoutes()
24
23
  const paths = routesToPaths(routes).filter(
25
24
  (i) => !i.includes(':') && !i.includes('*')
26
25
  )
@@ -23,6 +23,9 @@ export const createApp = ({
23
23
  }) => {
24
24
  const app = fastify({
25
25
  logger: {
26
+ transport: {
27
+ target: '@fastify/one-line-logger'
28
+ },
26
29
  level: process.env.DEBUG ? 'debug' : process.env.PINO_LOG_LEVEL || 'info'
27
30
  }
28
31
  })
package/src/node/index.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import vuePlugin from '@vitejs/plugin-vue'
2
- import type { Alias, InlineConfig, UserConfig as ViteUserConfig } from 'vite'
2
+ import type {
3
+ Alias,
4
+ InlineConfig,
5
+ Plugin,
6
+ UserConfig as ViteUserConfig
7
+ } from 'vite'
3
8
  import { findDepPkgJsonPath } from 'vitefu'
4
9
  import { mergeConfig } from 'vite'
5
10
  import { build } from 'esbuild'
@@ -29,10 +34,10 @@ import type { VitrifyPlugin } from './plugins/index.js'
29
34
  import { resolve } from './app-urls.js'
30
35
  import type { ManualChunksOption, RollupOptions } from 'rollup'
31
36
  import { addOrReplaceTitle, appendToBody } from './helpers/utils.js'
32
- import type { ComponentResolver } from 'unplugin-vue-components'
33
37
  import Components from 'unplugin-vue-components/vite'
34
38
  import { VitePWA } from 'vite-plugin-pwa'
35
39
  import UnoCSS from 'unocss/vite'
40
+ import { searchForWorkspaceRoot } from 'vite'
36
41
 
37
42
  const internalServerModules = [
38
43
  'util',
@@ -50,21 +55,6 @@ const internalServerModules = [
50
55
  'abort-controller'
51
56
  ]
52
57
 
53
- const configPluginMap: Record<string, () => Promise<VitrifyPlugin>> = {
54
- quasar: () =>
55
- import('./plugins/quasar.js').then((module) => module.QuasarPlugin)
56
- }
57
-
58
- const configResolverMap: Record<
59
- string,
60
- () => Promise<ComponentResolver | ComponentResolver[]>
61
- > = {
62
- quasar: () =>
63
- import('unplugin-vue-components/resolvers').then((module) =>
64
- module.QuasarResolver()
65
- )
66
- }
67
-
68
58
  const manualChunkNames = [
69
59
  'prerender',
70
60
  'fastify-ssr-plugin',
@@ -74,13 +64,16 @@ const manualChunkNames = [
74
64
 
75
65
  const moduleChunks = {
76
66
  vue: ['vue', '@vue', 'vue-router'],
77
- quasar: ['quasar', '@quasar']
67
+ quasar: ['quasar'],
68
+ atQuasar: ['@quasar']
78
69
  }
79
70
  const manualChunksFn = (manualChunkList?: string[]): ManualChunksOption => {
80
71
  return (id: string) => {
81
72
  const matchedModule = Object.entries(moduleChunks).find(
82
73
  ([chunkName, moduleNames]) =>
83
- moduleNames.some((moduleName) => id.includes(moduleName + '/'))
74
+ moduleNames.some((moduleName) =>
75
+ new RegExp(`\/${moduleName}\/`).test(id)
76
+ )
84
77
  )
85
78
  if (id.includes('vitrify/src/')) {
86
79
  const name = id.split('/').at(-1)?.split('.').at(0)
@@ -100,31 +93,6 @@ const manualChunksFn = (manualChunkList?: string[]): ManualChunksOption => {
100
93
  }
101
94
  }
102
95
 
103
- // const manualChunks: ManualChunksOption = (
104
- // id: string,
105
- // manualChunkList?: string[]
106
- // ) => {
107
- // const matchedModule = Object.entries(moduleChunks).find(
108
- // ([chunkName, moduleNames]) =>
109
- // moduleNames.some((moduleName) => id.includes(moduleName + '/'))
110
- // )
111
- // if (id.includes('vitrify/src/')) {
112
- // const name = id.split('/').at(-1)?.split('.').at(0)
113
- // if (name && manualChunkNames.includes(name)) return name
114
- // } else if (
115
- // VIRTUAL_MODULES.some((virtualModule) => id.includes(virtualModule))
116
- // ) {
117
- // return VIRTUAL_MODULES.find((name) => id.includes(name))
118
- // } else if (manualChunkList?.some((file) => id.includes(file))) {
119
- // return manualChunkList.find((file) => id.includes(file))
120
- // } else if (id.includes('node_modules')) {
121
- // if (matchedModule) {
122
- // return matchedModule[0]
123
- // }
124
- // return 'vendor'
125
- // }
126
- // }
127
-
128
96
  export const VIRTUAL_MODULES = [
129
97
  'virtual:vitrify-hooks',
130
98
  'virtual:static-imports',
@@ -238,7 +206,6 @@ export const baseConfig = async ({
238
206
  fs.writeFileSync(configPath + '.js', bundledConfig.code)
239
207
 
240
208
  rawVitrifyConfig = (await import('file://' + configPath + '.js')).default
241
- // vitrifyConfig = (await import(configPath + '.js')).default
242
209
  fs.unlinkSync(configPath + '.js')
243
210
  } else {
244
211
  rawVitrifyConfig = (
@@ -255,9 +222,11 @@ export const baseConfig = async ({
255
222
  throw e
256
223
  }
257
224
 
258
- const localPackages = ['vue', 'vue-router', '@vue/server-renderer']
259
- // const localPackages: string[] = []
260
- const cliPackages = []
225
+ const localPackages = []
226
+ if (framework === 'vue')
227
+ localPackages.push('vue', 'vue-router', '@vue/server-renderer')
228
+
229
+ const cliPackages: string[] = []
261
230
  const packageUrls: Record<string, URL> =
262
231
  vitrifyConfig.vitrify?.urls?.packages || {}
263
232
  await (async () => {
@@ -266,14 +235,6 @@ export const baseConfig = async ({
266
235
  if (pkgDir) packageUrls![val] = new URL(`file://${pkgDir}`)
267
236
  }
268
237
  })()
269
-
270
- // await (async () => {
271
- // for (const val of cliPackages)
272
- // packageUrls[val] = getPkgJsonDir(
273
- // new URL(await resolve(val, cliDir!.href))
274
- // )
275
- // })()
276
-
277
238
  if (!productName) {
278
239
  try {
279
240
  ;({ productName } = JSON.parse(
@@ -291,20 +252,28 @@ export const baseConfig = async ({
291
252
 
292
253
  const isPwa = !!vitrifyConfig.vitrify?.pwa || false
293
254
 
294
- const frameworkPlugins = []
295
- const resolvers = []
296
- for (const framework of Object.keys(configPluginMap)) {
297
- if (Object.keys(vitrifyConfig).includes(framework)) {
298
- const plugin = await configPluginMap[framework]()
299
- const resolver = await configResolverMap[framework]()
300
-
301
- frameworkPlugins.push(
302
- await plugin({
303
- ssr,
304
- pwa: isPwa
305
- })
306
- )
307
- resolvers.push(resolver)
255
+ const frameworkPlugins: Plugin[] = []
256
+ if (framework === 'vue') {
257
+ frameworkPlugins.push(vuePlugin())
258
+ }
259
+
260
+ const vitrifyPlugins: Plugin[] = []
261
+ if (vitrifyConfig.vitrify?.plugins) {
262
+ for (const vitrifyPluginConfig of vitrifyConfig.vitrify.plugins) {
263
+ const vitrifyPlugin = await vitrifyPluginConfig.plugin({
264
+ ssr,
265
+ pwa: isPwa,
266
+ options: vitrifyPluginConfig.options
267
+ })
268
+ if ('plugin' in vitrifyPlugin) {
269
+ vitrifyPlugins.push(vitrifyPlugin.plugin)
270
+ } else if ('plugins' in vitrifyPlugin) {
271
+ vitrifyPlugins.push(...vitrifyPlugin.plugins)
272
+ }
273
+
274
+ if (vitrifyPlugin.config) {
275
+ vitrifyConfig = mergeConfig(vitrifyConfig, vitrifyPlugin.config)
276
+ }
308
277
  }
309
278
  }
310
279
 
@@ -375,14 +344,13 @@ export const baseConfig = async ({
375
344
  /<style lang="sass">(.*?)<\/style>/,
376
345
  '<style lang="sass">' + sass + '</style>'
377
346
  )
378
- // code = code.replace(/<\/style>/, sass + '</style>')
379
347
  }
380
348
 
381
349
  return code
382
350
  }
383
351
  },
384
- vuePlugin(),
385
352
  ...frameworkPlugins,
353
+ ...vitrifyPlugins,
386
354
  {
387
355
  name: 'vitrify-setup',
388
356
  enforce: 'post',
@@ -442,10 +410,6 @@ export const baseConfig = async ({
442
410
  return `import ${varName} from '${
443
411
  new URL(url, appDir).pathname
444
412
  }'; onSetup.push(${varName})`
445
-
446
- // return `import ${varName} from '${fileURLToPath(
447
- // url
448
- // )}'; onSetup.push(${varName})`
449
413
  })
450
414
  .join('\n')}`
451
415
  } else if (id === 'virtual:static-imports') {
@@ -462,11 +426,7 @@ export const baseConfig = async ({
462
426
  ),
463
427
  ...globalSass.map((sass) => `@import '${sass}'`)
464
428
  ].join('\n')
465
- }
466
- // else if (id === 'vitrify.css') {
467
- // return `${globalCss.map((css) => `@import '${css}'`).join('\n')}`
468
- // }
469
- else if (id === 'virtual:vitrify-config') {
429
+ } else if (id === 'virtual:vitrify-config') {
470
430
  return `export default ${JSON.stringify(vitrifyConfig)}`
471
431
  }
472
432
  return null
@@ -496,14 +456,14 @@ export const baseConfig = async ({
496
456
  }
497
457
  },
498
458
  Components({
459
+ ...vitrifyConfig.vitrify?.unpluginVueComponents,
499
460
  exclude: [
500
461
  new RegExp(
501
462
  `[\\/]node_modules[\\/].*[\\/]!(${serverModules.join('|')})`
502
463
  ),
503
464
  /[\\/]\.git[\\/]/,
504
465
  /[\\/]\.nuxt[\\/]/
505
- ],
506
- resolvers
466
+ ]
507
467
  }),
508
468
  UnoCSS({
509
469
  ...vitrifyConfig.vitrify?.unocss,
@@ -556,32 +516,13 @@ export const baseConfig = async ({
556
516
  } else {
557
517
  entryScript = `<script type="module" src="${entry}"></script>`
558
518
  }
559
- // html = html.replace('<!--entry-script-->', entryScript)
560
519
  html = appendToBody(entryScript, html)
561
520
  if (productName) html = addOrReplaceTitle(productName, html)
562
- // html = html.replace('<!--product-name-->', productName)
563
521
  return html
564
522
  }
565
523
  }
566
524
  })
567
525
 
568
- // plugins.unshift({
569
- // name: 'product-name',
570
- // enforce: 'post',
571
- // config: (config: VitrifyConfig, env) => {
572
- // if (config.vitrify?.productName)
573
- // productName = config.vitrify?.productName
574
- // return
575
- // },
576
- // transformIndexHtml: {
577
- // enforce: 'post',
578
- // transform: (html) => {
579
- // html = html.replace('<!--product-name-->', productName)
580
- // return html
581
- // }
582
- // }
583
- // })
584
-
585
526
  if (debug) plugins.push(visualizer())
586
527
  }
587
528
 
@@ -596,19 +537,40 @@ export const baseConfig = async ({
596
537
  ]
597
538
 
598
539
  const vuePkgAliases: Alias[] = []
599
- for (const pkg of vueInternalPkgs) {
600
- const specifier = pkg.split('/').at(-1)
601
- const pkgJsonPath = await findDepPkgJsonPath(pkg, fileURLToPath(appDir!))
602
- if (pkgJsonPath)
603
- vuePkgAliases.push({
604
- find: pkg,
605
- replacement: fileURLToPath(
606
- new URL(
607
- `./dist/${specifier}.esm-bundler.js`,
608
- `file://${pkgJsonPath}` || ''
540
+ if (packageUrls['vue']) {
541
+ for (const pkg of vueInternalPkgs) {
542
+ const specifier = pkg.split('/').at(-1)
543
+ const pkgJsonPath = await findDepPkgJsonPath(pkg, fileURLToPath(appDir!))
544
+ if (pkgJsonPath)
545
+ vuePkgAliases.push({
546
+ find: pkg,
547
+ replacement: fileURLToPath(
548
+ new URL(
549
+ `./dist/${specifier}.esm-bundler.js`,
550
+ `file://${pkgJsonPath}` || ''
551
+ )
609
552
  )
610
- )
611
- })
553
+ })
554
+
555
+ vuePkgAliases.push(
556
+ {
557
+ find: new RegExp('^vue$'),
558
+ replacement: fileURLToPath(
559
+ new URL('./dist/vue.runtime.esm-bundler.js', packageUrls['vue'])
560
+ )
561
+ },
562
+ {
563
+ find: new RegExp('^vue-router$'),
564
+ replacement: fileURLToPath(
565
+ new URL(
566
+ './dist/vue-router.esm-bundler.js',
567
+ packageUrls['vue-router']
568
+ )
569
+ )
570
+ },
571
+ ...vuePkgAliases
572
+ )
573
+ }
612
574
  }
613
575
 
614
576
  const alias: Alias[] = [
@@ -616,21 +578,11 @@ export const baseConfig = async ({
616
578
  { find: 'app', replacement: fileURLToPath(appDir) },
617
579
  { find: 'cwd', replacement: fileURLToPath(cwd) },
618
580
  { find: 'boot', replacement: fileURLToPath(new URL('boot/', srcDir)) },
619
- { find: 'assets', replacement: fileURLToPath(new URL('assets/', srcDir)) },
620
- {
621
- find: new RegExp('^vue$'),
622
- replacement: fileURLToPath(
623
- new URL('./dist/vue.runtime.esm-bundler.js', packageUrls['vue'])
624
- )
625
- },
626
- {
627
- find: new RegExp('^vue-router$'),
628
- replacement: fileURLToPath(
629
- new URL('./dist/vue-router.esm-bundler.js', packageUrls['vue-router'])
630
- )
631
- },
632
- ...vuePkgAliases
581
+ { find: 'assets', replacement: fileURLToPath(new URL('assets/', srcDir)) }
633
582
  ]
583
+
584
+ if (framework === 'vue') alias.push(...vuePkgAliases)
585
+
634
586
  if (mode === 'development' && vitrifyConfig.vitrify?.dev?.alias)
635
587
  alias.push(...vitrifyConfig.vitrify.dev.alias)
636
588
 
@@ -701,6 +653,7 @@ export const baseConfig = async ({
701
653
 
702
654
  const config = {
703
655
  root: fileURLToPath(appDir),
656
+ appType: ssr ? 'custom' : 'spa',
704
657
  publicDir: fileURLToPath(publicDir),
705
658
  base,
706
659
  envDir: fileURLToPath(appDir),
@@ -737,6 +690,28 @@ export const baseConfig = async ({
737
690
  __HOST__: `'localhost'`,
738
691
  __BASE_URL__: `'${base}'`,
739
692
  __IS_PWA__: `${isPwa}`
693
+ },
694
+ // environments: {
695
+ // },
696
+ server: {
697
+ https: vitrifyConfig.server?.https,
698
+ // middlewareMode: mode === 'ssr' ? 'ssr' : undefined,
699
+ middlewareMode: ssr ? true : false,
700
+ fs: {
701
+ strict: false, // https://github.com/vitejs/vite/issues/8175
702
+ allow: [
703
+ searchForWorkspaceRoot(process.cwd()),
704
+ searchForWorkspaceRoot(fileURLToPath(appDir)),
705
+ searchForWorkspaceRoot(fileURLToPath(cliDir)),
706
+ fileURLToPath(appDir)
707
+ ]
708
+ },
709
+ watch: {
710
+ // During tests we edit the files too fast and sometimes chokidar
711
+ // misses change events, so enforce polling for consistency
712
+ usePolling: true,
713
+ interval: 100
714
+ }
740
715
  }
741
716
  } as VitrifyConfig
742
717
 
@@ -1,12 +1,28 @@
1
1
  import type { Plugin } from 'vite'
2
+ import { VitrifyConfig } from '../vitrify-config.js'
2
3
 
3
- export type VitrifyPlugin = ({
4
+ type VitrifyPluginReturnType =
5
+ | {
6
+ plugin: Plugin
7
+ config?: Partial<VitrifyConfig>
8
+ }
9
+ | {
10
+ plugins: Plugin[]
11
+ config?: Partial<VitrifyConfig>
12
+ }
13
+
14
+ export type VitrifyPlugin<Options> = ({
4
15
  ssr,
16
+ pwa,
5
17
  mode,
6
- command
18
+ command,
19
+ options
7
20
  }: {
8
21
  ssr?: 'server' | 'client' | 'ssg' | 'fastify' | false
9
22
  pwa?: boolean
10
23
  mode?: 'production' | 'development'
11
24
  command?: 'build' | 'dev' | 'test'
12
- }) => Promise<Plugin | Plugin[]> | Plugin | Plugin[]
25
+ options: Options
26
+ }) => Promise<VitrifyPluginReturnType> | VitrifyPluginReturnType
27
+
28
+ export * from './quasar/index.js'