@@ -5,10 +5,12 @@ import type { Config as ConfigCore } from 'vite-plugin-ssr/types'; | ||
export type Config = ConfigCore & { | ||
/** Vue component rendered and appended into <head></head> */ | ||
Head?: Component; | ||
Layout?: Component; | ||
/** <title>${title}</title> */ | ||
/** <title>${title}</title> */ | ||
title?: string; | ||
/** <meta name="description" content="${description}" /> */ | ||
/** <meta name="description" content="${description}" /> */ | ||
description?: string; | ||
/** <link rel="icon" href="${favicon}" /> */ | ||
/** <link rel="icon" href="${favicon}" /> */ | ||
favicon?: string; | ||
/** <html lang="${lang}"> | ||
/** <html lang="${lang}"> | ||
* | ||
@@ -40,2 +42,5 @@ * @default 'en' | ||
meta: { | ||
Head: { | ||
env: "server-only"; | ||
}; | ||
Layout: { | ||
@@ -42,0 +47,0 @@ env: "server-and-client"; |
@@ -28,2 +28,5 @@ // Depending on the value of `config.meta.ssr`, set other config options' `env` | ||
meta: { | ||
Head: { | ||
env: 'server-only' | ||
}, | ||
Layout: { | ||
@@ -30,0 +33,0 @@ env: 'server-and-client' |
import type { PageContext } from './types'; | ||
export { createApp }; | ||
declare function createApp(pageContext: PageContext): import("vue").App<Element> & { | ||
export { createVueApp }; | ||
/** | ||
* Isomorphic function to create a Vue app. | ||
* | ||
* @param pageContext Object providing the Vue component to be rendered, the props for that component, and additional | ||
* config and data. | ||
* @param ssrApp Whether to use `createSSRApp()` or `createApp()`. See https://vuejs.org/api/application.html | ||
* @param renderHead If true, `pageContext.config.Head` will be rendered instead of `pageContext.Page`. | ||
*/ | ||
declare function createVueApp(pageContext: PageContext, ssrApp?: boolean, renderHead?: boolean): import("vue").App<Element> & { | ||
changePage: (pageContext: PageContext) => void; | ||
}; |
@@ -1,10 +0,19 @@ | ||
import { createSSRApp, defineComponent, h, markRaw, reactive } from 'vue'; | ||
import { createApp, createSSRApp, defineComponent, h, markRaw, reactive } from 'vue'; | ||
import { setPageContext } from '../components/usePageContext'; | ||
export { createApp }; | ||
function createApp(pageContext) { | ||
export { createVueApp }; | ||
/** | ||
* Isomorphic function to create a Vue app. | ||
* | ||
* @param pageContext Object providing the Vue component to be rendered, the props for that component, and additional | ||
* config and data. | ||
* @param ssrApp Whether to use `createSSRApp()` or `createApp()`. See https://vuejs.org/api/application.html | ||
* @param renderHead If true, `pageContext.config.Head` will be rendered instead of `pageContext.Page`. | ||
*/ | ||
function createVueApp(pageContext, ssrApp = true, renderHead = false) { | ||
const { Page } = pageContext; | ||
const Head = renderHead ? pageContext.config.Head : undefined; | ||
let rootComponent; | ||
const PageWithLayout = defineComponent({ | ||
data: () => ({ | ||
Page: markRaw(Page), | ||
Page: markRaw(Head ? Head : Page), | ||
pageProps: markRaw(pageContext.pageProps || {}), | ||
@@ -17,3 +26,3 @@ config: markRaw(pageContext.config) | ||
render() { | ||
if (!!this.config.Layout) { | ||
if (!!this.config.Layout && !renderHead) { | ||
return h(this.config.Layout, {}, { | ||
@@ -28,3 +37,3 @@ default: () => { | ||
}); | ||
const app = createSSRApp(PageWithLayout); | ||
const app = ssrApp ? createSSRApp(PageWithLayout) : createApp(PageWithLayout); | ||
// We use `app.changePage()` to do Client Routing, see `_default.page.client.js` | ||
@@ -31,0 +40,0 @@ objectAssign(app, { |
export default onRenderClient; | ||
import { createApp } from './app'; | ||
import { createVueApp } from './app'; | ||
import { getTitle } from './getTitle.js'; | ||
@@ -7,4 +7,6 @@ let app; | ||
if (!app) { | ||
app = createApp(pageContext); | ||
app.mount('#page-view'); | ||
const container = document.getElementById('page-view'); | ||
const ssr = container.innerHTML !== ''; | ||
app = createVueApp(pageContext, ssr); | ||
app.mount(container); | ||
} | ||
@@ -11,0 +13,0 @@ else { |
export default onRenderHtml; | ||
import type { PageContextServer } from './types'; | ||
declare function onRenderHtml(pageContext: PageContextServer): Promise<{ | ||
documentHtml: import("vite-plugin-ssr/dist/types/node/runtime/html/renderHtml.js").TemplateWrapped; | ||
documentHtml: import("vite-plugin-ssr/dist/esm/node/runtime/html/renderHtml.js").TemplateWrapped; | ||
pageContext: { | ||
@@ -6,0 +6,0 @@ enableEagerStreaming: boolean; |
export default onRenderHtml; | ||
import { renderToNodeStream } from '@vue/server-renderer'; | ||
import { escapeInject } from 'vite-plugin-ssr/server'; | ||
import { renderToNodeStream, renderToString } from '@vue/server-renderer'; | ||
import { dangerouslySkipEscape, escapeInject } from 'vite-plugin-ssr/server'; | ||
import { getTitle } from './getTitle.js'; | ||
import { createApp } from './app'; | ||
import { createVueApp } from './app'; | ||
async function onRenderHtml(pageContext) { | ||
const app = createApp(pageContext); | ||
const stream = renderToNodeStream(app); | ||
let pageStream = ''; | ||
if (pageContext.Page !== undefined) { | ||
// SSR is enabled | ||
const app = createVueApp(pageContext); | ||
pageStream = renderToNodeStream(app); | ||
} | ||
const title = getTitle(pageContext); | ||
@@ -15,2 +19,7 @@ const titleTag = !title ? '' : escapeInject `<title>${title}</title>`; | ||
const faviconTag = !favicon ? '' : escapeInject `<link rel="icon" href="${favicon}" />`; | ||
let headHtml = ''; | ||
if (pageContext.config.Head !== undefined) { | ||
const app = createVueApp(pageContext, /*ssrApp*/ true, /*renderHead*/ true); | ||
headHtml = await renderToString(app); | ||
} | ||
const lang = pageContext.config.lang || 'en'; | ||
@@ -24,5 +33,6 @@ const documentHtml = escapeInject `<!DOCTYPE html> | ||
${descriptionTag} | ||
${dangerouslySkipEscape(headHtml)} | ||
</head> | ||
<body> | ||
<div id="page-view">${stream}</div> | ||
<div id="page-view">${pageStream}</div> | ||
</body> | ||
@@ -29,0 +39,0 @@ </html>`; |
{ | ||
"name": "vike-vue", | ||
"version": "0.1.1", | ||
"version": "0.2.0", | ||
"type": "module", | ||
@@ -24,3 +24,3 @@ "main": "./dist/renderer/+config.js", | ||
"vite": "^4.4.9", | ||
"vite-plugin-ssr": "^0.4.136", | ||
"vite-plugin-ssr": "^0.4.137", | ||
"vue": "^3.3.4" | ||
@@ -30,4 +30,4 @@ }, | ||
"@brillout/release-me": "^0.1.7", | ||
"@types/node": "^20.5.1", | ||
"typescript": "^5.1.6", | ||
"@types/node": "^20.5.7", | ||
"typescript": "^5.2.2", | ||
"vue": "^3.3.4" | ||
@@ -34,0 +34,0 @@ }, |
@@ -1,1 +0,18 @@ | ||
Vue integration for Vike, see [`vike-*` packages](https://vite-plugin-ssr.com/vike-packages). | ||
[<img src="https://avatars.githubusercontent.com/u/86403530?s=200&v=4" align="right" width="64" height="64">](https://vite-plugin-ssr.com) | ||
[](https://www.npmjs.com/package/vike-vue) | ||
# `vike-vue` | ||
Vue integration for Vike, for building a Vue web framework. Vike is the upcoming | ||
major version of [vite-plugin-ssr](https://vite-plugin-ssr.com/), a fast and | ||
modular Vite-based web framework. | ||
> **NOTE:** For Vike integrations with other UI frameworks (e.g. React), see | ||
> [`vike-*` packages](https://vite-plugin-ssr.com/vike-packages). | ||
To run the example: | ||
- Clone the repo: `git clone git@github.com:vikejs/vike-vue` | ||
- Install dependencies: `pnpm install` | ||
- Build vike-vue: `pnpm run build` | ||
- Run the example: `cd examples/basic/ && pnpm run dev` |
15378
19.43%373
11.01%19
850%