vike-ripple 0.3.0 → 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.
- package/package.json +24 -23
- package/src/components/ClientOnly.js +4 -2
- package/src/components/Config/Config-client.js +6 -1
- package/src/components/Config/Config-server.js +5 -3
- package/src/components/Head/Head-client.js +1 -3
- package/src/components/Head/Head-server.js +5 -4
- package/src/{+config.js → config.js} +5 -5
- package/src/helpers/clientOnly.js +4 -0
- package/src/hooks/useConfig/configsCumulative.js +7 -0
- package/src/hooks/useConfig/useConfig-client.js +25 -0
- package/src/hooks/useConfig/useConfig-server.js +24 -0
- package/src/hooks/useData.js +4 -3
- package/src/hooks/useHydrated.js +7 -0
- package/src/hooks/usePageContext.js +11 -5
- package/src/index.js +4 -27
- package/src/integration/getHeadSetting.js +2 -2
- package/src/integration/onRenderClient.js +10 -39
- package/src/integration/onRenderHtml.js +64 -41
- package/src/integration/ssrEffect.js +3 -6
- package/src/setup.js +27 -69
- package/src/utils/callCumulativeHooks.js +1 -3
- package/src/utils/getTagAttributesString.js +7 -7
- package/src/hooks/useConfig.js +0 -14
- package/src/integration/applyHeadSettings.js +0 -10
- package/src/integration/getPageElement.js +0 -32
- package/src/types/Config.ts +0 -33
- package/src/types/PageContext.ts +0 -13
package/package.json
CHANGED
|
@@ -1,38 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vike-ripple",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Vike extension for Ripple TS —
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Vike extension for Ripple TS — SSR, streaming, Layout, Head, SEO configs, hooks",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"types": "./src/types/Config.ts",
|
|
7
6
|
"exports": {
|
|
8
7
|
".": "./src/index.js",
|
|
9
|
-
"./config": "./src
|
|
8
|
+
"./config": "./src/config.js",
|
|
10
9
|
"./setup": "./src/setup.js",
|
|
11
|
-
"./Head": "./src/components/Head/Head-server.js",
|
|
12
|
-
"./ClientOnly": "./src/components/ClientOnly.js",
|
|
13
10
|
"./usePageContext": "./src/hooks/usePageContext.js",
|
|
14
11
|
"./useData": "./src/hooks/useData.js",
|
|
15
|
-
"./
|
|
16
|
-
"./
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
12
|
+
"./useHydrated": "./src/hooks/useHydrated.js",
|
|
13
|
+
"./useConfig": {
|
|
14
|
+
"browser": "./src/hooks/useConfig/useConfig-client.js",
|
|
15
|
+
"default": "./src/hooks/useConfig/useConfig-server.js"
|
|
16
|
+
},
|
|
17
|
+
"./Config": {
|
|
18
|
+
"browser": "./src/components/Config/Config-client.js",
|
|
19
|
+
"default": "./src/components/Config/Config-server.js"
|
|
20
|
+
},
|
|
21
|
+
"./Head": {
|
|
22
|
+
"browser": "./src/components/Head/Head-client.js",
|
|
23
|
+
"default": "./src/components/Head/Head-server.js"
|
|
24
|
+
},
|
|
25
|
+
"./clientOnly": "./src/helpers/clientOnly.js",
|
|
26
|
+
"./ClientOnly": "./src/components/ClientOnly.js",
|
|
27
|
+
"./__internal/integration/onRenderHtml": "./src/integration/onRenderHtml.js",
|
|
28
|
+
"./__internal/integration/onRenderClient": "./src/integration/onRenderClient.js"
|
|
21
29
|
},
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
],
|
|
25
|
-
"keywords": [
|
|
26
|
-
"vike",
|
|
27
|
-
"ripple",
|
|
28
|
-
"ripplets",
|
|
29
|
-
"ssr",
|
|
30
|
-
"vite"
|
|
31
|
-
],
|
|
30
|
+
"bin": { "vike-ripple": "./src/setup.js" },
|
|
31
|
+
"files": ["src"],
|
|
32
|
+
"keywords": ["vike", "ripple", "ripplets", "ssr", "vite"],
|
|
32
33
|
"license": "MIT",
|
|
33
34
|
"peerDependencies": {
|
|
34
35
|
"vike": ">=0.4.259",
|
|
35
36
|
"@ripple-ts/vite-plugin": ">=0.3.0",
|
|
36
37
|
"ripple": ">=0.1.0"
|
|
37
38
|
}
|
|
38
|
-
}
|
|
39
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
export { Config }
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { useConfig } from '../../hooks/useConfig/useConfig-server.js'
|
|
4
|
+
|
|
5
|
+
function Config(props) {
|
|
6
|
+
useConfig()(props)
|
|
5
7
|
return null
|
|
6
8
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
export { Head }
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
import { useConfig } from '../../hooks/useConfig/useConfig-server.js'
|
|
4
|
+
|
|
5
|
+
function Head({ children }) {
|
|
6
|
+
useConfig()({ Head: children })
|
|
6
7
|
return null
|
|
7
8
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { ssrEffect } from './integration/ssrEffect.js'
|
|
2
2
|
|
|
3
|
-
/** @type {import('vike/types').Config} */
|
|
4
3
|
const config = {
|
|
5
4
|
name: 'vike-ripple',
|
|
6
5
|
require: { vike: '>=0.4.250' },
|
|
7
6
|
|
|
8
|
-
onRenderHtml: 'import:vike-ripple/
|
|
9
|
-
onRenderClient: 'import:vike-ripple/
|
|
7
|
+
onRenderHtml: 'import:vike-ripple/__internal/integration/onRenderHtml:onRenderHtml',
|
|
8
|
+
onRenderClient: 'import:vike-ripple/__internal/integration/onRenderClient:onRenderClient',
|
|
10
9
|
|
|
11
10
|
clientRouting: true,
|
|
12
11
|
hydrationCanBeAborted: true,
|
|
@@ -16,6 +15,7 @@ const config = {
|
|
|
16
15
|
meta: {
|
|
17
16
|
Head: { env: { server: true }, cumulative: true },
|
|
18
17
|
Layout: { env: { server: true, client: true }, cumulative: true },
|
|
18
|
+
Wrapper: { env: { server: true, client: true }, cumulative: true },
|
|
19
19
|
title: { env: { server: true, client: true } },
|
|
20
20
|
description: { env: { server: true } },
|
|
21
21
|
image: { env: { server: true } },
|
|
@@ -26,8 +26,8 @@ const config = {
|
|
|
26
26
|
stream: { env: { server: true }, cumulative: true },
|
|
27
27
|
onBeforeRenderHtml: { env: { server: true }, cumulative: true },
|
|
28
28
|
onAfterRenderHtml: { env: { server: true }, cumulative: true },
|
|
29
|
-
onBeforeRenderClient: { env: {
|
|
30
|
-
onAfterRenderClient: { env: {
|
|
29
|
+
onBeforeRenderClient: { env: { client: true }, cumulative: true },
|
|
30
|
+
onAfterRenderClient: { env: { client: true }, cumulative: true },
|
|
31
31
|
bodyHtmlBegin: { env: { server: true }, cumulative: true, global: true },
|
|
32
32
|
bodyHtmlEnd: { env: { server: true }, cumulative: true, global: true },
|
|
33
33
|
headHtmlBegin: { env: { server: true }, cumulative: true, global: true },
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { useConfig }
|
|
2
|
+
|
|
3
|
+
import { getPageContext } from 'vike/getPageContext'
|
|
4
|
+
import { usePageContext } from '../usePageContext.js'
|
|
5
|
+
|
|
6
|
+
function useConfig() {
|
|
7
|
+
let pageContext = getPageContext({ asyncHook: false })
|
|
8
|
+
if (pageContext) {
|
|
9
|
+
return (config) => {
|
|
10
|
+
pageContext._configViaHook ??= {}
|
|
11
|
+
Object.assign(pageContext._configViaHook, config)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pageContext = usePageContext()
|
|
16
|
+
return (config) => {
|
|
17
|
+
if (!('_headAlreadySet' in (pageContext || {}))) {
|
|
18
|
+
pageContext._configViaHook ??= {}
|
|
19
|
+
Object.assign(pageContext._configViaHook, config)
|
|
20
|
+
} else {
|
|
21
|
+
if (config.title) document.title = config.title
|
|
22
|
+
if (config.lang) document.documentElement.lang = config.lang
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export { useConfig }
|
|
2
|
+
|
|
3
|
+
import { getPageContext } from 'vike/getPageContext'
|
|
4
|
+
import { usePageContext } from '../usePageContext.js'
|
|
5
|
+
|
|
6
|
+
function useConfig() {
|
|
7
|
+
// Vike hook
|
|
8
|
+
let pageContext = getPageContext({ asyncHook: false })
|
|
9
|
+
if (pageContext) {
|
|
10
|
+
return (config) => {
|
|
11
|
+
pageContext._configViaHook ??= {}
|
|
12
|
+
Object.assign(pageContext._configViaHook, config)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Component
|
|
17
|
+
pageContext = usePageContext()
|
|
18
|
+
return (config) => {
|
|
19
|
+
if (!pageContext?._headAlreadySet) {
|
|
20
|
+
pageContext._configViaHook ??= {}
|
|
21
|
+
Object.assign(pageContext._configViaHook, config)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/hooks/useData.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
export { usePageContext }
|
|
2
|
+
export { setPageContext }
|
|
3
|
+
|
|
4
|
+
let _pageContext = null
|
|
5
|
+
|
|
6
|
+
function usePageContext() {
|
|
7
|
+
return _pageContext
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function setPageContext(ctx) {
|
|
11
|
+
_pageContext = ctx
|
|
6
12
|
}
|
package/src/index.js
CHANGED
|
@@ -1,27 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* 1. Import config in your renderer/+config.ts:
|
|
6
|
-
* import vikeRipple from 'vike-ripple/config'
|
|
7
|
-
*
|
|
8
|
-
* 2. Run setup (once):
|
|
9
|
-
* npx vike-ripple setup
|
|
10
|
-
*
|
|
11
|
-
* 3. Add optimizeDeps to vite.config.ts:
|
|
12
|
-
* optimizeDeps: { exclude: ['ripple'] }
|
|
13
|
-
*
|
|
14
|
-
* ## Usage
|
|
15
|
-
* - +Head.tsrx — inject <head> content
|
|
16
|
-
* - +Layout.tsrx — layout components
|
|
17
|
-
* - +title.ts — per-page title
|
|
18
|
-
* - +description.ts — per-page description
|
|
19
|
-
* - +ssr.ts — per-page SSR toggle
|
|
20
|
-
* - +stream.ts — per-page streaming toggle
|
|
21
|
-
*/
|
|
22
|
-
export default function vikeRipple() {
|
|
23
|
-
return {
|
|
24
|
-
name: 'vike-ripple',
|
|
25
|
-
enforce: 'pre',
|
|
26
|
-
}
|
|
27
|
-
}
|
|
1
|
+
console.warn(
|
|
2
|
+
"[vike-ripple] Replace `import vikeRipple from 'vike-ripple'` with `import vikeRipple from 'vike-ripple/config'`",
|
|
3
|
+
)
|
|
4
|
+
export { default } from './config.js'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { getHeadSetting }
|
|
2
2
|
|
|
3
3
|
function getHeadSetting(key, pageContext) {
|
|
4
|
-
const
|
|
5
|
-
if (
|
|
4
|
+
const v = pageContext.config[key]
|
|
5
|
+
if (v !== undefined && v !== null) return v
|
|
6
6
|
return pageContext._configViaHook?.[key] ?? null
|
|
7
7
|
}
|
|
@@ -1,62 +1,33 @@
|
|
|
1
|
-
// https://vike.dev/onRenderClient
|
|
2
1
|
export { onRenderClient }
|
|
3
2
|
|
|
4
3
|
import { hydrate } from 'ripple'
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { callCumulativeHooks } from '../utils/callCumulativeHooks.js'
|
|
4
|
+
import { setPageContext } from '../hooks/usePageContext.js'
|
|
5
|
+
import { setHydrated } from '../hooks/useHydrated.js'
|
|
8
6
|
|
|
9
7
|
let rendered = false
|
|
10
8
|
|
|
11
9
|
const onRenderClient = async (pageContext) => {
|
|
12
|
-
|
|
10
|
+
const { Page } = pageContext
|
|
11
|
+
if (!Page) return
|
|
13
12
|
|
|
13
|
+
setPageContext(pageContext)
|
|
14
14
|
const container = document.getElementById('root')
|
|
15
15
|
if (!container) return
|
|
16
16
|
|
|
17
|
-
pageContext._headAlreadySet = pageContext.isHydration
|
|
18
|
-
|
|
19
17
|
if (pageContext.isHydration && container.innerHTML !== '') {
|
|
20
18
|
try {
|
|
21
|
-
|
|
19
|
+
hydrate(Page, { target: container, props: {} })
|
|
22
20
|
rendered = true
|
|
21
|
+
setHydrated()
|
|
23
22
|
} catch (err) {
|
|
24
23
|
console.warn('[vike-ripple] hydrate failed, falling back to mount:', err)
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
if (!rendered) {
|
|
29
|
-
|
|
28
|
+
const { mount } = await import('ripple')
|
|
29
|
+
mount(Page, { target: container, props: {} })
|
|
30
30
|
rendered = true
|
|
31
|
+
setHydrated()
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
updateHead(pageContext)
|
|
34
|
-
|
|
35
|
-
await callCumulativeHooks(pageContext.config.onAfterRenderClient, pageContext)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function hydratePage(pageContext, container) {
|
|
39
|
-
hydrate(pageContext.Page, { target: container, props: {} })
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async function mountPage(pageContext, container) {
|
|
43
|
-
const { mount } = await import('ripple')
|
|
44
|
-
mount(pageContext.Page, { target: container, props: {} })
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function updateHead(pageContext) {
|
|
48
|
-
if (pageContext._headAlreadySet) return
|
|
49
|
-
|
|
50
|
-
const title = getHeadSetting('title', pageContext)
|
|
51
|
-
if (title && document.title !== title) {
|
|
52
|
-
document.title = title
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const lang = getHeadSetting('lang', pageContext)
|
|
56
|
-
if (lang) {
|
|
57
|
-
document.documentElement.lang = lang
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
applyHeadSettings(pageContext.config.Head, document.head)
|
|
61
|
-
applyHeadSettings(pageContext._configViaHook?.Head, document.head)
|
|
62
33
|
}
|
|
@@ -2,27 +2,48 @@ export { onRenderHtml }
|
|
|
2
2
|
|
|
3
3
|
import { render, create_ssr_stream } from 'ripple/server'
|
|
4
4
|
import { escapeInject, dangerouslySkipEscape } from 'vike/server'
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { setPageContext } from '../hooks/usePageContext.js'
|
|
7
6
|
import { getHeadSetting } from './getHeadSetting.js'
|
|
8
|
-
import { callCumulativeHooks } from '../utils/callCumulativeHooks.js'
|
|
9
7
|
import { getTagAttributesString } from '../utils/getTagAttributesString.js'
|
|
8
|
+
import { callCumulativeHooks } from '../utils/callCumulativeHooks.js'
|
|
10
9
|
|
|
11
10
|
const onRenderHtml = async (pageContext) => {
|
|
12
|
-
const
|
|
13
|
-
const { Page } = pageContext2
|
|
11
|
+
const { Page } = pageContext
|
|
14
12
|
if (!Page) throw new Error('No Page')
|
|
15
13
|
|
|
16
|
-
await callCumulativeHooks(
|
|
14
|
+
await callCumulativeHooks(pageContext.config.onBeforeRenderHtml, pageContext)
|
|
15
|
+
|
|
16
|
+
setPageContext(pageContext)
|
|
17
|
+
|
|
18
|
+
const headHtml = getHeadHtml(pageContext)
|
|
19
|
+
const { headHtmlBegin, headHtmlEnd, bodyHtmlBegin, bodyHtmlEnd } = getHtmlInjections(pageContext)
|
|
20
|
+
const { htmlAttributesString, bodyAttributesString } = getTagAttributes(pageContext)
|
|
21
|
+
|
|
22
|
+
// Wrap in Layout(s) + Wrapper(s)
|
|
23
|
+
let wrappedPage = Page
|
|
24
|
+
const Layout = pageContext.config.Layout
|
|
25
|
+
const Wrapper = pageContext.config.Wrapper
|
|
26
|
+
if (Layout) {
|
|
27
|
+
const layouts = Array.isArray(Layout) ? Layout : [Layout]
|
|
28
|
+
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
29
|
+
const L = layouts[i]
|
|
30
|
+
const prev = wrappedPage
|
|
31
|
+
wrappedPage = (props) => L({ ...props, children: prev })
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (Wrapper) {
|
|
35
|
+
const wrappers = Array.isArray(Wrapper) ? Wrapper : [Wrapper]
|
|
36
|
+
for (const W of wrappers) {
|
|
37
|
+
const prev = wrappedPage
|
|
38
|
+
wrappedPage = (props) => W({ ...props, children: prev })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
17
41
|
|
|
18
|
-
const
|
|
19
|
-
const { headHtmlBegin, headHtmlEnd, bodyHtmlBegin, bodyHtmlEnd } = await getHtmlInjections(pageContext2)
|
|
20
|
-
const { htmlAttributesString, bodyAttributesString } = getTagAttributes(pageContext2)
|
|
21
|
-
const enableStream = !!(pageContext2.config.stream ?? pageContext2.config.rippleStream)
|
|
42
|
+
const enableStream = !!(pageContext.config.stream ?? pageContext.config.rippleStream)
|
|
22
43
|
|
|
23
44
|
if (enableStream) {
|
|
24
45
|
const rippleStream = create_ssr_stream()
|
|
25
|
-
render(
|
|
46
|
+
render(wrappedPage, { stream: rippleStream.sink }).catch(e => {
|
|
26
47
|
console.error('[ripple] render err:', e?.message)
|
|
27
48
|
})
|
|
28
49
|
return escapeInject`<!DOCTYPE html>
|
|
@@ -41,16 +62,19 @@ const onRenderHtml = async (pageContext) => {
|
|
|
41
62
|
</html>`
|
|
42
63
|
}
|
|
43
64
|
|
|
44
|
-
const { head, body, css } = await render(
|
|
65
|
+
const { head, body, css, topLevelError } = await render(wrappedPage, {})
|
|
66
|
+
if (topLevelError) {
|
|
67
|
+
console.error('[vike-ripple] SSR render error:', topLevelError)
|
|
68
|
+
throw topLevelError
|
|
69
|
+
}
|
|
45
70
|
|
|
71
|
+
// Ripple's render() already extracts <head> content into `head` and CSS into `css`
|
|
46
72
|
const cssHtml = css?.size
|
|
47
73
|
? `<style data-ripple-ssr>${[...css].join('')}<` + `/style>`
|
|
48
74
|
: ''
|
|
49
75
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
pageContext2.pageHtmlString = body
|
|
53
|
-
await callCumulativeHooks(pageContext2.config.onAfterRenderHtml, pageContext2)
|
|
76
|
+
pageContext.pageHtmlString = body
|
|
77
|
+
await callCumulativeHooks(pageContext.config.onAfterRenderHtml, pageContext)
|
|
54
78
|
|
|
55
79
|
return escapeInject`<!DOCTYPE html>
|
|
56
80
|
<html${dangerouslySkipEscape(htmlAttributesString)}>
|
|
@@ -77,44 +101,43 @@ function getHeadHtml(pageContext) {
|
|
|
77
101
|
const description = getHeadSetting('description', pageContext)
|
|
78
102
|
const image = getHeadSetting('image', pageContext)
|
|
79
103
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const imageTags = !image
|
|
86
|
-
? ''
|
|
87
|
-
: `<meta property="og:image" content="${image}"><meta name="twitter:card" content="summary_large_image">`
|
|
104
|
+
const parts = []
|
|
105
|
+
if (favicon) parts.push(`<link rel="icon" href="${favicon}" />`)
|
|
106
|
+
if (title) parts.push(`<title>${title}</title>`)
|
|
107
|
+
if (description) parts.push(`<meta name="description" content="${description}" />`)
|
|
108
|
+
if (image) parts.push(`<meta property="og:image" content="${image}">`)
|
|
88
109
|
const viewportTag = getViewportTag(getHeadSetting('viewport', pageContext))
|
|
89
|
-
|
|
90
|
-
const
|
|
110
|
+
if (viewportTag) parts.push(viewportTag)
|
|
111
|
+
const headElements = [
|
|
91
112
|
...(pageContext.config.Head ?? []),
|
|
92
113
|
...(pageContext._configViaHook?.Head ?? []),
|
|
93
114
|
]
|
|
94
115
|
.filter(Boolean)
|
|
95
|
-
.map(
|
|
116
|
+
.map(h => (typeof h === 'function' ? h(pageContext) : h))
|
|
96
117
|
.join('\n')
|
|
97
|
-
|
|
98
|
-
return
|
|
118
|
+
if (headElements) parts.push(headElements)
|
|
119
|
+
return parts.join('\n')
|
|
99
120
|
}
|
|
100
121
|
|
|
101
|
-
|
|
102
|
-
if (viewport
|
|
122
|
+
function getViewportTag(viewport) {
|
|
123
|
+
if (!viewport && viewport !== 0) return ''
|
|
103
124
|
if (viewport === 'responsive') return '<meta name="viewport" content="width=device-width, initial-scale=1.0" />'
|
|
104
125
|
if (typeof viewport === 'number') return `<meta name="viewport" content="width=${viewport}" />`
|
|
105
|
-
return '
|
|
126
|
+
return ''
|
|
106
127
|
}
|
|
107
128
|
|
|
108
129
|
function getTagAttributes(pageContext) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
return {
|
|
131
|
+
htmlAttributesString: getTagAttributesString(pageContext.config.htmlAttributes),
|
|
132
|
+
bodyAttributesString: getTagAttributesString(pageContext.config.bodyAttributes),
|
|
133
|
+
}
|
|
112
134
|
}
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
function getHtmlInjections(pageContext) {
|
|
137
|
+
return {
|
|
138
|
+
headHtmlBegin: (pageContext.config.headHtmlBegin ?? []).join('\n'),
|
|
139
|
+
headHtmlEnd: (pageContext.config.headHtmlEnd ?? []).join('\n'),
|
|
140
|
+
bodyHtmlBegin: (pageContext.config.bodyHtmlBegin ?? []).join('\n'),
|
|
141
|
+
bodyHtmlEnd: (pageContext.config.bodyHtmlEnd ?? []).join('\n'),
|
|
142
|
+
}
|
|
120
143
|
}
|
|
@@ -4,12 +4,9 @@ function ssrEffect({ configDefinedAt, configValue }) {
|
|
|
4
4
|
if (typeof configValue !== 'boolean') throw new Error(`${configDefinedAt} should be a boolean`)
|
|
5
5
|
return {
|
|
6
6
|
meta: {
|
|
7
|
-
Page: {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
server: configValue !== false,
|
|
11
|
-
},
|
|
12
|
-
},
|
|
7
|
+
Page: { env: { client: true, server: configValue !== false } },
|
|
8
|
+
Layout: { env: { client: true, server: configValue !== false } },
|
|
9
|
+
Wrapper: { env: { client: true, server: configValue !== false } },
|
|
13
10
|
},
|
|
14
11
|
}
|
|
15
12
|
}
|
package/src/setup.js
CHANGED
|
@@ -1,124 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* vike-ripple setup — patches Vike and Ripple for .tsrx support.
|
|
4
|
-
*
|
|
5
|
-
* Run once: npx vike-ripple setup
|
|
6
|
-
* Or add to project's package.json: "postinstall": "vike-ripple setup"
|
|
7
|
-
*/
|
|
8
2
|
import { createRequire } from 'module'
|
|
9
3
|
import { join } from 'path'
|
|
10
4
|
import { readFileSync, writeFileSync, existsSync } from 'fs'
|
|
11
|
-
import { fileURLToPath } from 'url'
|
|
12
5
|
|
|
13
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
14
6
|
const projectRoot = process.cwd()
|
|
15
7
|
let exitCode = 0
|
|
16
8
|
|
|
17
|
-
function log(
|
|
18
|
-
function warn(
|
|
9
|
+
function log(m) { console.log('[vike-ripple]', m) }
|
|
10
|
+
function warn(m) { console.warn('[vike-ripple]', m) }
|
|
19
11
|
|
|
20
|
-
// ── Patch 1: Register .tsrx with Vike ─────────────────────────
|
|
21
12
|
function patchVikeExtensions() {
|
|
22
13
|
const target = resolveVike('dist/utils/isScriptFile.js')
|
|
23
|
-
if (!target) { warn('vike not found
|
|
24
|
-
|
|
14
|
+
if (!target) { warn('vike not found'); return }
|
|
25
15
|
let src = readFileSync(target, 'utf-8')
|
|
26
|
-
if (src.includes("'tsrx'")) { log('.tsrx already registered
|
|
27
|
-
|
|
16
|
+
if (src.includes("'tsrx'")) { log('.tsrx already registered'); return }
|
|
28
17
|
const patched = src.replace(
|
|
29
18
|
'const scriptFileExtensionList = [...extJsOrTs, ...extJsxOrTsx, ...extTemplates];',
|
|
30
19
|
"const scriptFileExtensionList = [...extJsOrTs, ...extJsxOrTsx, ...extTemplates, 'tsrx'];",
|
|
31
20
|
)
|
|
32
|
-
if (patched === src) { warn('Could not patch Vike
|
|
21
|
+
if (patched === src) { warn('Could not patch Vike'); exitCode = 1; return }
|
|
33
22
|
writeFileSync(target, patched, 'utf-8')
|
|
34
|
-
log('Registered .tsrx extension
|
|
23
|
+
log('Registered .tsrx extension')
|
|
35
24
|
}
|
|
36
25
|
|
|
37
|
-
// ── Patch 2: Fix ?direct in Ripple's load hook ────────────────
|
|
38
26
|
function patchRippleDirect() {
|
|
39
27
|
const target = resolveRipple('src/index.js')
|
|
40
|
-
if (!target) { warn('@ripple-ts/vite-plugin not found
|
|
41
|
-
|
|
28
|
+
if (!target) { warn('@ripple-ts/vite-plugin not found'); return }
|
|
42
29
|
let src = readFileSync(target, 'utf-8')
|
|
43
30
|
if (src.includes('Handle ?direct query param')) { log('?direct fix already applied'); return }
|
|
44
|
-
|
|
45
31
|
const patched = src.replace(
|
|
46
32
|
'if (cssCache.has(id)) {\n\t\t\t\t\treturn cssCache.get(id);\n\t\t\t\t}',
|
|
47
33
|
`if (cssCache.has(id)) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
}`,
|
|
34
|
+
\t\t\t\t\treturn cssCache.get(id);
|
|
35
|
+
\t\t\t\t}
|
|
36
|
+
\t\t\t\tif (id.includes('?direct')) {
|
|
37
|
+
\t\t\t\t\tconst baseId = id.replace('?direct', '');
|
|
38
|
+
\t\t\t\t\tif (cssCache.has(baseId)) {
|
|
39
|
+
\t\t\t\t\t\treturn cssCache.get(baseId);
|
|
40
|
+
\t\t\t\t\t}
|
|
41
|
+
\t\t\t\t}`,
|
|
58
42
|
)
|
|
59
|
-
if (patched === src) { warn('Could not patch Ripple plugin
|
|
43
|
+
if (patched === src) { warn('Could not patch Ripple plugin'); exitCode = 1; return }
|
|
60
44
|
writeFileSync(target, patched, 'utf-8')
|
|
61
|
-
log('Patched Ripple plugin for ?direct CSS
|
|
45
|
+
log('Patched Ripple plugin for ?direct CSS loading')
|
|
62
46
|
}
|
|
63
47
|
|
|
64
|
-
// ── Patch 3: @apply support ───────────────────────────────────
|
|
65
48
|
function patchRippleApply() {
|
|
66
49
|
const target = resolveRipple('src/index.js')
|
|
67
50
|
if (!target) return
|
|
68
|
-
|
|
69
51
|
let src = readFileSync(target, 'utf-8')
|
|
70
|
-
|
|
71
52
|
if (src.includes('TW_PATCH_APPLY')) { log('@apply patch already applied'); return }
|
|
72
|
-
|
|
73
|
-
// Upgrade from old TW_PATCH format
|
|
74
53
|
if (src.includes('TW_PATCH:')) {
|
|
75
|
-
src = src.replace(
|
|
76
|
-
|
|
77
|
-
'// TW_PATCH_APPLY: bring tailwindcss into scope for @apply',
|
|
78
|
-
)
|
|
79
|
-
src = src.replace(
|
|
80
|
-
"css = '@import \"tailwindcss\";\\n' + css;",
|
|
81
|
-
"css = '@import \"tailwindcss\" layer(reference);\\n' + css;",
|
|
82
|
-
)
|
|
54
|
+
src = src.replace('// TW_PATCH: prepend tailwindcss','// TW_PATCH_APPLY: apply')
|
|
55
|
+
src = src.replace("css = '@import \"tailwindcss\";\\n' + css;","css = '@import \"tailwindcss\" layer(reference);\\n' + css;")
|
|
83
56
|
writeFileSync(target, src, 'utf-8')
|
|
84
|
-
log('Upgraded @apply patch
|
|
57
|
+
log('Upgraded @apply patch');
|
|
85
58
|
return
|
|
86
59
|
}
|
|
87
|
-
|
|
88
|
-
//
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
'\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n' +
|
|
92
|
-
'\t\t\t\t\t\tcssCache.set(cssId, css);'
|
|
93
|
-
)
|
|
94
|
-
const patched = (
|
|
95
|
-
'\t\t\t\t\tif (css) {\n' +
|
|
96
|
-
'\t\t\t\t\t\t// TW_PATCH_APPLY: bring tailwindcss into scope for @apply\n' +
|
|
97
|
-
"\t\t\t\t\t\tcss = '@import \"tailwindcss\" layer(reference);\\n' + css;\n" +
|
|
98
|
-
'\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n' +
|
|
99
|
-
'\t\t\t\t\t\tcssCache.set(cssId, css);'
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
const result = src.replace(orig, patched)
|
|
103
|
-
if (result === src) { warn('Could not patch Ripple plugin for @apply'); return }
|
|
60
|
+
const orig = '\t\t\t\t\tif (css) {\n\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n\t\t\t\t\t\tcssCache.set(cssId, css);'
|
|
61
|
+
const rep = '\t\t\t\t\tif (css) {\n\t\t\t\t\t\t// TW_PATCH_APPLY: @apply support\n\t\t\t\t\t\tcss = \'@import "tailwindcss" layer(reference);\\n\' + css;\n\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n\t\t\t\t\t\tcssCache.set(cssId, css);'
|
|
62
|
+
const result = src.replace(orig, rep)
|
|
63
|
+
if (result === src) { warn('Could not patch @apply'); return }
|
|
104
64
|
writeFileSync(target, result, 'utf-8')
|
|
105
|
-
log('Patched Ripple plugin for @apply
|
|
65
|
+
log('Patched Ripple plugin for @apply')
|
|
106
66
|
}
|
|
107
67
|
|
|
108
|
-
// ── Resolve helpers ────────────────────────────────────────────
|
|
109
68
|
function resolveVike(rel) {
|
|
110
69
|
const p = join(projectRoot, 'node_modules', 'vike', rel)
|
|
111
70
|
if (existsSync(p)) return p
|
|
112
|
-
try {
|
|
71
|
+
try { return createRequire(join(projectRoot, 'package.json')).resolve('vike/' + rel) } catch { return null }
|
|
113
72
|
}
|
|
114
73
|
|
|
115
74
|
function resolveRipple(rel) {
|
|
116
75
|
const p = join(projectRoot, 'node_modules', '@ripple-ts', 'vite-plugin', rel)
|
|
117
76
|
if (existsSync(p)) return p
|
|
118
|
-
try {
|
|
77
|
+
try { return createRequire(join(projectRoot, 'package.json')).resolve('@ripple-ts/vite-plugin/' + rel) } catch { return null }
|
|
119
78
|
}
|
|
120
79
|
|
|
121
|
-
// ── Main ──────────────────────────────────────────────────────
|
|
122
80
|
log('Applying patches...')
|
|
123
81
|
patchVikeExtensions()
|
|
124
82
|
patchRippleDirect()
|
|
@@ -3,9 +3,7 @@ export async function callCumulativeHooks(hooks, ...args) {
|
|
|
3
3
|
for (const hook of hooks) {
|
|
4
4
|
if (typeof hook === 'function') {
|
|
5
5
|
const result = hook(...args)
|
|
6
|
-
if (result && typeof result.then === 'function')
|
|
7
|
-
await result
|
|
8
|
-
}
|
|
6
|
+
if (result && typeof result.then === 'function') await result
|
|
9
7
|
}
|
|
10
8
|
}
|
|
11
9
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export function getTagAttributesString(
|
|
2
|
-
if (!
|
|
3
|
-
return Object.entries(
|
|
4
|
-
.map(([
|
|
5
|
-
if (
|
|
6
|
-
if (
|
|
7
|
-
return ` ${
|
|
1
|
+
export function getTagAttributesString(attrs) {
|
|
2
|
+
if (!attrs) return ''
|
|
3
|
+
return Object.entries(attrs)
|
|
4
|
+
.map(([k, v]) => {
|
|
5
|
+
if (v === true) return ` ${k}`
|
|
6
|
+
if (!v) return ''
|
|
7
|
+
return ` ${k}="${String(v).replace(/"/g, '"')}"`
|
|
8
8
|
})
|
|
9
9
|
.join('')
|
|
10
10
|
}
|
package/src/hooks/useConfig.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { useConfig } from '../hooks/useConfig.js'
|
|
2
|
-
|
|
3
|
-
export function useConfig() {
|
|
4
|
-
const pageContext = typeof window !== 'undefined'
|
|
5
|
-
? window.__vike_pageContext
|
|
6
|
-
: globalThis.__vike_pageContext
|
|
7
|
-
|
|
8
|
-
return (values) => {
|
|
9
|
-
if (!pageContext._configViaHook) {
|
|
10
|
-
pageContext._configViaHook = {}
|
|
11
|
-
}
|
|
12
|
-
Object.assign(pageContext._configViaHook, values)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function applyHeadSettings(headList, target) {
|
|
2
|
-
if (!headList || !Array.isArray(headList)) return
|
|
3
|
-
for (const head of headList) {
|
|
4
|
-
if (typeof head === 'string') {
|
|
5
|
-
target.insertAdjacentHTML('beforeend', head)
|
|
6
|
-
} else if (head instanceof Node) {
|
|
7
|
-
target.appendChild(head.cloneNode(true))
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export { getPageElement }
|
|
2
|
-
|
|
3
|
-
import { getHeadSetting } from './getHeadSetting.js'
|
|
4
|
-
|
|
5
|
-
function getPageElement(pageContext) {
|
|
6
|
-
const { Page } = pageContext
|
|
7
|
-
if (!Page) {
|
|
8
|
-
return { page: null, pageElement: null }
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const Layout = pageContext.config.Layout
|
|
12
|
-
const Wrapper = pageContext.config.Wrapper
|
|
13
|
-
|
|
14
|
-
let page = Page
|
|
15
|
-
|
|
16
|
-
if (Layout) {
|
|
17
|
-
const layouts = Array.isArray(Layout) ? Layout : [Layout]
|
|
18
|
-
for (let i = layouts.length - 1; i >= 0; i--) {
|
|
19
|
-
const LayoutComponent = layouts[i]
|
|
20
|
-
page = function NestedPage(props) { return LayoutComponent({ ...props, children: page }) }
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (Wrapper) {
|
|
25
|
-
const wrappers = Array.isArray(Wrapper) ? Wrapper : [Wrapper]
|
|
26
|
-
for (const W of wrappers) {
|
|
27
|
-
page = function WrappedPage(props) { return W({ ...props, children: page }) }
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return { page, pageElement: page }
|
|
32
|
-
}
|
package/src/types/Config.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import 'vike/types'
|
|
2
|
-
|
|
3
|
-
declare global {
|
|
4
|
-
namespace Vike {
|
|
5
|
-
interface Config {
|
|
6
|
-
Head?: unknown[]
|
|
7
|
-
Layout?: unknown[]
|
|
8
|
-
title?: string | null
|
|
9
|
-
description?: string | null
|
|
10
|
-
image?: string | null
|
|
11
|
-
viewport?: 'responsive' | number | null
|
|
12
|
-
favicon?: string | null
|
|
13
|
-
lang?: string | null
|
|
14
|
-
ssr?: boolean
|
|
15
|
-
stream?: boolean
|
|
16
|
-
rippleStream?: boolean
|
|
17
|
-
Wrapper?: unknown[]
|
|
18
|
-
Loading?: unknown
|
|
19
|
-
onBeforeRenderHtml?: ((pageContext: unknown) => void | Promise<void>)[]
|
|
20
|
-
onAfterRenderHtml?: ((pageContext: unknown) => void | Promise<void>)[]
|
|
21
|
-
onBeforeRenderClient?: ((pageContext: unknown) => void | Promise<void>)[]
|
|
22
|
-
onAfterRenderClient?: ((pageContext: unknown) => void | Promise<void>)[]
|
|
23
|
-
bodyHtmlBegin?: string[]
|
|
24
|
-
bodyHtmlEnd?: string[]
|
|
25
|
-
headHtmlBegin?: string[]
|
|
26
|
-
headHtmlEnd?: string[]
|
|
27
|
-
htmlAttributes?: Record<string, string | boolean>
|
|
28
|
-
bodyAttributes?: Record<string, string | boolean>
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export type __FakeExport_Config = true
|
package/src/types/PageContext.ts
DELETED