vitrify 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +86 -0
  2. package/dist/app-urls.js +32 -0
  3. package/dist/bin/build.js +73 -0
  4. package/dist/bin/cli.js +137 -0
  5. package/dist/bin/dev.js +106 -0
  6. package/dist/bin/run.js +26 -0
  7. package/dist/helpers/logger.js +108 -0
  8. package/dist/helpers/routes.js +24 -0
  9. package/dist/helpers/utils.js +24 -0
  10. package/dist/index.js +288 -0
  11. package/dist/plugins/index.js +1 -0
  12. package/dist/plugins/quasar.js +294 -0
  13. package/dist/types/app-urls.d.ts +11 -0
  14. package/dist/types/bin/build.d.ts +8 -0
  15. package/dist/types/bin/cli.d.ts +2 -0
  16. package/dist/types/bin/dev.d.ts +15 -0
  17. package/dist/types/bin/run.d.ts +8 -0
  18. package/dist/types/bin/test.d.ts +3 -0
  19. package/dist/types/helpers/logger.d.ts +23 -0
  20. package/dist/types/helpers/routes.d.ts +2 -0
  21. package/dist/types/helpers/utils.d.ts +5 -0
  22. package/dist/types/index.d.ts +15 -0
  23. package/dist/types/plugins/index.d.ts +7 -0
  24. package/dist/types/plugins/quasar.d.ts +16 -0
  25. package/dist/types/vitrify-config.d.ts +64 -0
  26. package/dist/types/vue/fastify-ssr-plugin.d.ts +14 -0
  27. package/dist/types/vue/prerender.d.ts +8 -0
  28. package/dist/types/vue/server.d.ts +9 -0
  29. package/dist/vitrify-config.js +1 -0
  30. package/dist/vue/fastify-ssr-plugin.js +91 -0
  31. package/dist/vue/prerender.js +29 -0
  32. package/dist/vue/server.js +20 -0
  33. package/package.json +94 -18
  34. package/src/vite/vue/components.d.ts +25 -0
  35. package/src/vite/vue/csr/entry.ts +8 -0
  36. package/src/vite/vue/index.html +16 -0
  37. package/src/vite/vue/main.ts +89 -0
  38. package/src/vite/vue/ssr/entry-client.ts +9 -0
  39. package/src/vite/vue/ssr/entry-server.ts +97 -0
  40. package/src/vite/vue/ssr/fastify-ssr-plugin.ts +120 -0
  41. package/src/vite/vue/ssr/prerender.ts +4 -0
  42. package/src/vite/vue/ssr/server.ts +15 -0
  43. package/src/vite/vue/ssr/server.ts.bak +61 -0
  44. package/src/vite/vue/ssr/tsconfig.json +9 -0
@@ -0,0 +1,15 @@
1
+ import type { InlineConfig } from 'vite';
2
+ import type { VitrifyConfig } from './vitrify-config.js';
3
+ import type { VitrifyContext } from './bin/run.js';
4
+ import type { VitrifyPlugin } from './plugins/index.js';
5
+ export declare const VIRTUAL_MODULES: string[];
6
+ export declare const baseConfig: ({ ssr, appDir, publicDir, command, mode, framework, pwa }: {
7
+ ssr?: "server" | "client" | "ssg" | undefined;
8
+ appDir?: URL | undefined;
9
+ publicDir?: URL | undefined;
10
+ command?: "build" | "dev" | "test" | undefined;
11
+ mode?: "production" | "development" | undefined;
12
+ framework?: "vue" | undefined;
13
+ pwa?: boolean | undefined;
14
+ }) => Promise<InlineConfig>;
15
+ export type { VitrifyConfig, VitrifyPlugin, VitrifyContext };
@@ -0,0 +1,7 @@
1
+ import type { Plugin } from 'vite';
2
+ export declare type VitrifyPlugin = ({ ssr, mode, command }: {
3
+ ssr?: 'server' | 'client' | 'ssg' | false;
4
+ pwa?: boolean;
5
+ mode?: 'production' | 'development';
6
+ command?: 'build' | 'dev' | 'test';
7
+ }) => Promise<Plugin | Plugin[]> | Plugin | Plugin[];
@@ -0,0 +1,16 @@
1
+ import type { VitrifyPlugin } from './index.js';
2
+ export interface QuasarConf {
3
+ ctx: Record<string, any>;
4
+ css: string[];
5
+ boot: string[];
6
+ framework: {
7
+ components?: string[];
8
+ directives?: string[];
9
+ plugins?: string[];
10
+ };
11
+ animations: string[];
12
+ extras: string[];
13
+ }
14
+ export declare const injectSsrContext: (html: string, ssrContext: Record<string, any>) => string;
15
+ export declare const QuasarPlugin: VitrifyPlugin;
16
+ export default QuasarPlugin;
@@ -0,0 +1,64 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { UserConfig } from 'vite';
3
+ import type { QuasarConf } from './plugins/quasar.js';
4
+ import type { ComponentInternalInstance } from '@vue/runtime-core';
5
+ export declare type BootFunction = ({ app, ssrContext, staticImports }: {
6
+ app: any;
7
+ ssrContext: Record<string, unknown>;
8
+ staticImports: Record<string, any>;
9
+ }) => Promise<void> | void;
10
+ export declare type OnMountedHook = (instance: ComponentInternalInstance) => Promise<void> | void;
11
+ export declare type StaticImports = Record<string, string[]>;
12
+ export declare type SsrFunction = (html: string, ssrContext: Record<string, any>) => string;
13
+ export interface VitrifyConfig extends UserConfig {
14
+ vitrify?: {
15
+ /**
16
+ * Global CSS imports
17
+ */
18
+ globalCss?: string[];
19
+ /**
20
+ * Functions which run after initializing the app
21
+ */
22
+ bootFunctions?: BootFunction[];
23
+ /**
24
+ * Functions which run on the server after rendering the app
25
+ */
26
+ ssrFunctions?: SsrFunction[];
27
+ /**
28
+ * Static imports in the app: packageName: [imports]
29
+ */
30
+ staticImports?: StaticImports;
31
+ hooks?: {
32
+ /**
33
+ * Functions which run in the onMounted hook of the app
34
+ */
35
+ onMounted: OnMountedHook[];
36
+ };
37
+ /**
38
+ * Global SASS variables
39
+ */
40
+ sassVariables?: Record<string, string>;
41
+ fastify?: {
42
+ /**
43
+ * setup() is called directly after instantiating fastify. Use it to register your own plugins, routes etc.
44
+ */
45
+ setup: (fastify: FastifyInstance) => any;
46
+ };
47
+ /**
48
+ * Product name of the application. Will be used for the HTML title tag
49
+ */
50
+ productName?: string;
51
+ /**
52
+ * URL's for common dev paths and packages, automatically generated
53
+ */
54
+ urls?: {
55
+ app?: URL;
56
+ cli?: URL;
57
+ src?: URL;
58
+ cwd?: URL;
59
+ packages?: Record<string, URL>;
60
+ };
61
+ };
62
+ quasar?: QuasarConf;
63
+ }
64
+ export declare const defineConfig: (config: VitrifyConfig) => VitrifyConfig;
@@ -0,0 +1,14 @@
1
+ import type { FastifyPluginCallback, FastifyRequest, FastifyReply } from 'fastify';
2
+ import type { ViteDevServer } from 'vite';
3
+ import type { SsrFunction } from '../vitrify-config.js';
4
+ export interface FastifySsrOptions {
5
+ baseUrl?: string;
6
+ provide?: (req: FastifyRequest, res: FastifyReply) => Promise<Record<string, unknown>>;
7
+ vite?: ViteDevServer;
8
+ cliDir?: URL;
9
+ appDir?: URL;
10
+ productName?: string;
11
+ ssrFunctions?: SsrFunction[];
12
+ }
13
+ declare const fastifySsrPlugin: FastifyPluginCallback<FastifySsrOptions>;
14
+ export { fastifySsrPlugin };
@@ -0,0 +1,8 @@
1
+ import type { SsrFunction } from '../vitrify-config.js';
2
+ export declare const prerender: ({ outDir, templatePath, manifestPath, entryServerPath, ssrFunctions }: {
3
+ outDir: string;
4
+ templatePath: string;
5
+ manifestPath: string;
6
+ entryServerPath: string;
7
+ ssrFunctions: SsrFunction[];
8
+ }) => Promise<void[]>;
@@ -0,0 +1,9 @@
1
+ /// <reference types="node" />
2
+ import type { FastifyInstance } from 'fastify';
3
+ import type { SsrFunction } from '../vitrify-config.js';
4
+ export declare const createApp: ({ setup, appDir, baseUrl, ssrFunctions }: {
5
+ setup: (fastify: FastifyInstance) => any;
6
+ appDir: URL;
7
+ baseUrl?: string | undefined;
8
+ ssrFunctions?: SsrFunction[] | undefined;
9
+ }) => FastifyInstance<import("http").Server, import("http").IncomingMessage, import("http").ServerResponse, import("fastify").FastifyLoggerInstance> & PromiseLike<FastifyInstance<import("http").Server, import("http").IncomingMessage, import("http").ServerResponse, import("fastify").FastifyLoggerInstance>>;
@@ -0,0 +1 @@
1
+ export const defineConfig = (config) => config;
@@ -0,0 +1,91 @@
1
+ import fastifyStatic from 'fastify-static';
2
+ import { readFileSync } from 'fs';
3
+ 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;
8
+ await fastify.register(middie);
9
+ fastify.use(options.vite.middlewares);
10
+ fastify.get('*', async (req, res) => {
11
+ try {
12
+ // const url = req.originalUrl
13
+ const url = req.raw.url;
14
+ const ssrContext = {
15
+ req,
16
+ res
17
+ };
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;
24
+ let manifest;
25
+ // TODO: https://github.com/vitejs/vite/issues/2282
26
+ try {
27
+ manifest = {};
28
+ }
29
+ catch (e) {
30
+ manifest = {};
31
+ }
32
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext);
33
+ const html = template
34
+ .replace(`<!--preload-links-->`, preloadLinks)
35
+ .replace(`<!--app-html-->`, appHtml)
36
+ .replace('<!--product-name-->', options.productName || 'Product name');
37
+ res.code(200);
38
+ res.type('text/html');
39
+ res.send(html);
40
+ // res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
41
+ }
42
+ catch (e) {
43
+ console.error(e.stack);
44
+ options.vite && options.vite.ssrFixStacktrace(e);
45
+ res.code(500);
46
+ res.send(e.stack);
47
+ }
48
+ });
49
+ }
50
+ else {
51
+ options.baseUrl = options.baseUrl || '/';
52
+ fastify.register(fastifyStatic, {
53
+ root: new URL('./dist/ssr/client', options.appDir).pathname,
54
+ wildcard: false,
55
+ index: false,
56
+ prefix: options.baseUrl
57
+ });
58
+ fastify.get(`${options.baseUrl}*`, async (req, res) => {
59
+ const url = req.raw.url;
60
+ const provide = options.provide ? await options.provide(req, res) : {};
61
+ const ssrContext = {
62
+ req,
63
+ res,
64
+ provide
65
+ };
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
+ const template = readFileSync(new URL('./dist/ssr/client/index.html', options.appDir).pathname).toString();
70
+ const manifest = JSON.parse(readFileSync(new URL('./dist/ssr/client/ssr-manifest.json', options.appDir)).toString());
71
+ const render = (await import(new URL('./dist/ssr/server/entry-server.mjs', options.appDir).pathname)).render;
72
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext);
73
+ if (!ssrContext.initialState)
74
+ ssrContext.initialState = {};
75
+ ssrContext.initialState.provide = provide;
76
+ let html = template
77
+ .replace(`<!--preload-links-->`, preloadLinks)
78
+ .replace(`<!--app-html-->`, appHtml);
79
+ if (options.ssrFunctions?.length) {
80
+ for (const ssrFunction of options.ssrFunctions) {
81
+ html = ssrFunction(html, ssrContext);
82
+ }
83
+ }
84
+ res.code(200);
85
+ res.type('text/html');
86
+ res.send(html);
87
+ });
88
+ }
89
+ done();
90
+ };
91
+ export { fastifySsrPlugin };
@@ -0,0 +1,29 @@
1
+ import { promises as fs } from 'fs';
2
+ import { routesToPaths } from '../helpers/routes.js';
3
+ export const prerender = async ({ outDir, templatePath, manifestPath, entryServerPath, ssrFunctions }) => {
4
+ const promises = [];
5
+ const template = (await fs.readFile(templatePath)).toString();
6
+ const manifest = await fs.readFile(manifestPath);
7
+ const { render, getRoutes } = await import(entryServerPath);
8
+ const routes = await getRoutes();
9
+ const paths = routesToPaths(routes).filter((i) => !i.includes(':') && !i.includes('*'));
10
+ for (const url of paths) {
11
+ const filename = (url.endsWith('/') ? 'index' : url.replace(/^\//g, '')) + '.html';
12
+ console.log(`Generating ${filename}`);
13
+ const ssrContext = {
14
+ req: { headers: {}, url },
15
+ res: {}
16
+ };
17
+ const [appHtml, preloadLinks] = await render(url, manifest, ssrContext);
18
+ let html = template
19
+ .replace(`<!--preload-links-->`, preloadLinks)
20
+ .replace(`<!--app-html-->`, appHtml);
21
+ if (ssrFunctions?.length) {
22
+ for (const ssrFunction of ssrFunctions) {
23
+ html = ssrFunction(html, ssrContext);
24
+ }
25
+ }
26
+ promises.push(fs.writeFile(outDir + filename, html, 'utf-8'));
27
+ }
28
+ return Promise.all(promises);
29
+ };
@@ -0,0 +1,20 @@
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 }) => {
6
+ const app = fastify({
7
+ logger: true
8
+ });
9
+ app.register(fastifySsrPlugin, {
10
+ baseUrl,
11
+ appDir,
12
+ ssrFunctions
13
+ });
14
+ setup(app);
15
+ return app;
16
+ };
17
+ // const app = createApp({
18
+ // setup
19
+ // })
20
+ // app.listen(process.env.PORT || 3000, process.env.HOST || '127.0.0.1')
package/package.json CHANGED
@@ -1,21 +1,40 @@
1
1
  {
2
2
  "name": "vitrify",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "author": "Stefan van Herwijnen",
6
- "description": "Pre-configured Vite CLI",
6
+ "description": "Pre-configured Vite CLI for your framework",
7
+ "type": "module",
7
8
  "bin": {
8
- "vitrify": "bin/vitrify.js"
9
+ "vitrify": "./dist/bin/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": "./dist/index.js",
13
+ "./*": "./dist/*.js",
14
+ "./build": "./dist/bin/build.js",
15
+ "./dev": "./dist/bin/dev.js",
16
+ "./helpers/*": "./dist/helpers/*.js",
17
+ "./vite/*": "./src/vite/*"
18
+ },
19
+ "typesVersions": {
20
+ "*": {
21
+ "*": [
22
+ "./dist/types/index.d.ts"
23
+ ],
24
+ "helpers/*": [
25
+ "./dist/types/helpers/*.d.ts"
26
+ ],
27
+ "build": [
28
+ "./dist/types/node/build.d.ts"
29
+ ],
30
+ "dev": [
31
+ "./dist/types/node/dev.d.ts"
32
+ ],
33
+ "help": [
34
+ "./dist/types/node/help.d.ts"
35
+ ]
36
+ }
9
37
  },
10
- "main": "dist/node/index.js",
11
- "types": "dist/node/index.d.ts",
12
- "files": [
13
- "bin",
14
- "dist",
15
- "client.d.ts",
16
- "src/client",
17
- "types"
18
- ],
19
38
  "engines": {
20
39
  "node": ">=12.2.0"
21
40
  },
@@ -28,9 +47,66 @@
28
47
  "url": "https://github.com/simsustech/vitrify/issues"
29
48
  },
30
49
  "homepage": "https://github.com/simsustech/vitrify/tree/main/#readme",
31
- "dependencies": {},
32
- "optionalDependencies": {},
33
- "devDependencies": {},
34
- "peerDependencies": {},
35
- "scripts": {}
36
- }
50
+ "scripts": {
51
+ "build": "tsc",
52
+ "test": "echo \"Error: no test specified\" && exit 0"
53
+ },
54
+ "dependencies": {
55
+ "@quasar/extras": "^1.13.5",
56
+ "@vitejs/plugin-vue": "^2.3.1",
57
+ "@vue/compiler-sfc": "^3.2.31",
58
+ "@vue/server-renderer": "^3.2.31",
59
+ "builtin-modules": "^3.2.0",
60
+ "cac": "^6.7.12",
61
+ "chalk": "^5.0.1",
62
+ "cross-env": "^7.0.3",
63
+ "fastify": "^3.28.0",
64
+ "fastify-static": "^4.6.1",
65
+ "glob": "^7.2.0",
66
+ "happy-dom": "^2.55.0",
67
+ "import-meta-resolve": "^1.1.1",
68
+ "local-pkg": "^0.4.1",
69
+ "magic-string": "^0.26.1",
70
+ "merge-deep": "^3.0.3",
71
+ "middie": "^6.0.0",
72
+ "readline": "^1.3.0",
73
+ "sass": "1.50.0",
74
+ "vite": "^2.9.1",
75
+ "vitest": "^0.9.3"
76
+ },
77
+ "devDependencies": {
78
+ "@types/glob": "^7.2.0",
79
+ "@types/merge-deep": "^3.0.0",
80
+ "@types/node": "^17.0.23",
81
+ "@types/ws": "^8.5.3",
82
+ "@vue/runtime-core": "^3.2.31",
83
+ "quasar": "^2.6.6",
84
+ "rollup": "^2.70.1",
85
+ "typescript": "^4.6.3",
86
+ "unplugin-vue-components": "^0.19.2",
87
+ "vite": "^2.9.1",
88
+ "vitrify": "^0.1.1",
89
+ "vue": "^3.2.31",
90
+ "vue-router": "^4.0.14"
91
+ },
92
+ "peerDependencies": {
93
+ "fastify": "^3.28.0",
94
+ "fastify-plugin": "^3.0.1",
95
+ "fastify-sensible": "^3.1.2",
96
+ "fastify-static": "^4.6.1",
97
+ "quasar": "^2.6.6",
98
+ "vue": "^3.2.31",
99
+ "vue-router": "^4.0.14"
100
+ },
101
+ "publishConfig": {
102
+ "access": "public",
103
+ "registry": "https://registry.npmjs.org/"
104
+ },
105
+ "files": [
106
+ "dist",
107
+ "src/node/helpers/ssr.ts",
108
+ "src/vite",
109
+ "!dist/**/*.test.js",
110
+ "!dist/**/test.js"
111
+ ]
112
+ }
@@ -0,0 +1,25 @@
1
+ // generated by unplugin-vue-components
2
+ // We suggest you to commit this file into source control
3
+ // Read more: https://github.com/vuejs/vue-next/pull/3399
4
+
5
+ declare module '@vue/runtime-core' {
6
+ export interface GlobalComponents {
7
+ QAvatar: typeof import('quasar')['QAvatar']
8
+ QBtn: typeof import('quasar')['QBtn']
9
+ QCard: typeof import('quasar')['QCard']
10
+ QCardSection: typeof import('quasar')['QCardSection']
11
+ QDrawer: typeof import('quasar')['QDrawer']
12
+ QHeader: typeof import('quasar')['QHeader']
13
+ QItemLabel: typeof import('quasar')['QItemLabel']
14
+ QLayout: typeof import('quasar')['QLayout']
15
+ QList: typeof import('quasar')['QList']
16
+ QPage: typeof import('quasar')['QPage']
17
+ QPageContainer: typeof import('quasar')['QPageContainer']
18
+ QToolbar: typeof import('quasar')['QToolbar']
19
+ QToolbarTitle: typeof import('quasar')['QToolbarTitle']
20
+ RouterLink: typeof import('vue-router')['RouterLink']
21
+ RouterView: typeof import('vue-router')['RouterView']
22
+ }
23
+ }
24
+
25
+ export {}
@@ -0,0 +1,8 @@
1
+ import { createApp } from '../main'
2
+
3
+ createApp().then(({ app, router }) => {
4
+ // wait until router is ready before mounting to ensure hydration match
5
+ router.isReady().then(() => {
6
+ app.mount('#app')
7
+ })
8
+ })
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><!--product-name--></title>
7
+ <!--preload-links-->
8
+ </head>
9
+
10
+ <body>
11
+ <!-- Do not add whitespace or newlines to #app, this will cause hydration errors -->
12
+ <div id="app"><!--app-html--></div>
13
+ <!--entry-script-->
14
+ <!--initial-state-->
15
+ </body>
16
+ </html>
@@ -0,0 +1,89 @@
1
+ import App from 'src/App.vue'
2
+ import createRouter from 'src/router'
3
+ import {
4
+ createSSRApp,
5
+ createApp as createVueApp,
6
+ h,
7
+ onMounted,
8
+ getCurrentInstance
9
+ } from 'vue'
10
+ // import { Quasar, useQuasar } from 'quasar'
11
+ // import quasarPlugins from 'virtual:quasar-plugins'
12
+ // import bootFunctions from 'virtual:quasar-boot'
13
+ import bootFunctions from 'virtual:boot-functions'
14
+ import onMountedHooks from 'virtual:on-mounted-hooks'
15
+ // import 'virtual:quasar-extras'
16
+ // import * as directives from 'quasar/directives'
17
+ import routes from 'src/router/routes'
18
+ import 'virtual:global-css'
19
+ import * as staticImports from 'virtual:static-imports'
20
+
21
+ interface ssrContext {
22
+ ssr: boolean
23
+ provide?: Record<string, unknown>
24
+ [key: string]: unknown
25
+ }
26
+
27
+ export async function createApp(
28
+ ssr?: 'client' | 'server',
29
+ ssrContext?: ssrContext
30
+ ) {
31
+ let app
32
+ const RootComponent = {
33
+ name: 'AppWrapper',
34
+ setup(props) {
35
+ const instance = getCurrentInstance()
36
+
37
+ onMounted(async () => {
38
+ for (let fn of onMountedHooks) {
39
+ await fn(instance, staticImports)
40
+ }
41
+ // onAppMounted()
42
+ // const { proxy: { $q } } = getCurrentInstance()
43
+ // $q.onSSRHydrated !== void 0 && $q.onSSRHydrated()
44
+ })
45
+
46
+ return () => h(App, props)
47
+ }
48
+ }
49
+ if (ssr) {
50
+ app = createSSRApp(RootComponent)
51
+ } else {
52
+ app = createVueApp(RootComponent)
53
+ }
54
+ const router = createRouter()
55
+ app.use(router)
56
+
57
+ // Workaround to fix hydration errors when serving html files directly
58
+ router.beforeEach((to, from, next) => {
59
+ if (to.path.endsWith('.html')) {
60
+ next({ path: to.path.replace('.html', '') })
61
+ }
62
+
63
+ next()
64
+ })
65
+
66
+ // app.use(Quasar, {
67
+ // plugins: quasarPlugins,
68
+ // directives
69
+ // }, ssrContext)
70
+
71
+ let provide: Record<string, unknown> = {}
72
+ if (import.meta.env.SSR) {
73
+ if (ssrContext?.provide) {
74
+ provide = ssrContext?.provide
75
+ }
76
+ } else {
77
+ // @ts-ignore
78
+ provide = window.__INITIAL_STATE__?.provide
79
+ }
80
+ for (let key in provide) {
81
+ app.provide(key, provide[key])
82
+ }
83
+
84
+ for (let fn of bootFunctions) {
85
+ await fn({ app, ssrContext, staticImports })
86
+ }
87
+
88
+ return { app, router, routes }
89
+ }
@@ -0,0 +1,9 @@
1
+ import { createApp } from '../main.js'
2
+
3
+ // const { app, router } = createApp()
4
+ createApp('client').then(({ app, router }) => {
5
+ // wait until router is ready before mounting to ensure hydration match
6
+ router.isReady().then(() => {
7
+ app.mount('#app')
8
+ })
9
+ })
@@ -0,0 +1,97 @@
1
+ import { createApp } from '../main.js'
2
+ import { renderToString } from '@vue/server-renderer'
3
+ // import * as ApolloSSR from '@vue/apollo-ssr'
4
+ // import { ApolloClients } from '@vue/apollo-composable'
5
+ // import serialize from 'serialize-javascript'
6
+
7
+ const initializeApp = async (url, ssrContext) => {
8
+ const onRenderedList = []
9
+ Object.assign(ssrContext, {
10
+ _modules: new Set(),
11
+ _meta: {},
12
+ onRendered: (fn) => {
13
+ onRenderedList.push(fn)
14
+ }
15
+ })
16
+
17
+ const { app, router, routes } = await createApp('server', ssrContext)
18
+ // set the router to the desired URL before rendering
19
+
20
+ router.push({ path: url })
21
+ ssrContext.initialState = {}
22
+
23
+ onRenderedList.forEach((fn) => {
24
+ fn()
25
+ })
26
+
27
+ await router.isReady()
28
+
29
+ return { app, router, routes }
30
+ }
31
+
32
+ export const getRoutes = async () =>
33
+ (
34
+ await initializeApp('/', {
35
+ ssr: false,
36
+ req: { headers: {}, url: '/' },
37
+ res: {}
38
+ })
39
+ ).routes
40
+
41
+ export async function render(url, manifest, ssrContext) {
42
+ const { app, router } = await initializeApp(url, ssrContext)
43
+
44
+ // passing SSR context object which will be available via useSSRContext()
45
+ // @vitejs/plugin-vue injects code into a component's setup() that registers
46
+ // itself on ctx.modules. After the render, ctx.modules would contain all the
47
+ // components that have been instantiated during this render call.
48
+ const ctx = {
49
+ __qMetaList: []
50
+ }
51
+ let html = await renderToString(app, ctx)
52
+ // html = injectSsrContext(html, ssrContext)
53
+ // the SSR manifest generated by Vite contains module -> chunk/asset mapping
54
+ // which we can then use to determine what files need to be preloaded for this
55
+ // request.
56
+ const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
57
+
58
+ return [html, preloadLinks]
59
+ }
60
+
61
+ function renderPreloadLinks(modules, manifest) {
62
+ let links = ''
63
+ const seen = new Set()
64
+ modules.forEach((id) => {
65
+ const files = manifest[id]
66
+ if (files) {
67
+ files.forEach((file) => {
68
+ if (!seen.has(file)) {
69
+ seen.add(file)
70
+ links += renderPreloadLink(file)
71
+ }
72
+ })
73
+ }
74
+ })
75
+ return links
76
+ }
77
+
78
+ function renderPreloadLink(file) {
79
+ if (file.endsWith('.js')) {
80
+ return `<link rel="modulepreload" crossorigin href="${file}">`
81
+ } else if (file.endsWith('.css')) {
82
+ return `<link rel="stylesheet" href="${file}">`
83
+ } else if (file.endsWith('.woff')) {
84
+ return ` <link rel="preload" href="${file}" as="font" type="font/woff" crossorigin>`
85
+ } else if (file.endsWith('.woff2')) {
86
+ return ` <link rel="preload" href="${file}" as="font" type="font/woff2" crossorigin>`
87
+ } else if (file.endsWith('.gif')) {
88
+ return ` <link rel="preload" href="${file}" as="image" type="image/gif">`
89
+ } else if (file.endsWith('.jpg') || file.endsWith('.jpeg')) {
90
+ return ` <link rel="preload" href="${file}" as="image" type="image/jpeg">`
91
+ } else if (file.endsWith('.png')) {
92
+ return ` <link rel="preload" href="${file}" as="image" type="image/png">`
93
+ } else {
94
+ // TODO
95
+ return ''
96
+ }
97
+ }