vike-ripple 0.3.0 → 0.4.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.
package/package.json CHANGED
@@ -1,20 +1,31 @@
1
1
  {
2
2
  "name": "vike-ripple",
3
- "version": "0.3.0",
4
- "description": "Vike extension for Ripple TS — full parity with vike-react/vike-solid/vike-vue",
3
+ "version": "0.4.1",
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/+config.js",
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
- "./useConfig": "./src/hooks/useConfig.js",
16
- "./src/integration/onRenderHtml.js": "./src/integration/onRenderHtml.js",
17
- "./src/integration/onRenderClient.js": "./src/integration/onRenderClient.js"
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"
18
29
  },
19
30
  "bin": {
20
31
  "vike-ripple": "./src/setup.js"
@@ -1,5 +1,7 @@
1
1
  export { ClientOnly }
2
2
 
3
- function ClientOnly({ children }) {
4
- return children
3
+ import { useHydrated } from '../hooks/useHydrated.js'
4
+
5
+ function ClientOnly({ children, fallback }) {
6
+ return useHydrated() ? children : (fallback ?? null)
5
7
  }
@@ -1,3 +1,8 @@
1
- export function Config() {
1
+ export { Config }
2
+
3
+ import { useConfig } from '../../hooks/useConfig/useConfig-client.js'
4
+
5
+ function Config(props) {
6
+ useConfig()(props)
2
7
  return null
3
8
  }
@@ -1,6 +1,8 @@
1
- import { useConfig } from '../hooks/useConfig.js'
1
+ export { Config }
2
2
 
3
- export function Config(values) {
4
- useConfig()(values)
3
+ import { useConfig } from '../../hooks/useConfig/useConfig-server.js'
4
+
5
+ function Config(props) {
6
+ useConfig()(props)
5
7
  return null
6
8
  }
@@ -1,3 +1 @@
1
- export function Head() {
2
- return null
3
- }
1
+ export function Head() { return null }
@@ -1,7 +1,8 @@
1
- import { useConfig } from '../hooks/useConfig.js'
1
+ export { Head }
2
2
 
3
- export function Head({ children }) {
4
- const config = useConfig()
5
- config({ Head: children })
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,21 @@
1
- import { ssrEffect } from './integration/ssrEffect.js'
1
+ // ssrEffect inlined to avoid import resolution issues during config loading
2
+ function ssrEffect({ configDefinedAt, configValue }) {
3
+ if (typeof configValue !== 'boolean') throw new Error(`${configDefinedAt} should be a boolean`)
4
+ return {
5
+ meta: {
6
+ Page: { env: { client: true, server: configValue !== false } },
7
+ Layout: { env: { client: true, server: configValue !== false } },
8
+ Wrapper: { env: { client: true, server: configValue !== false } },
9
+ },
10
+ }
11
+ }
2
12
 
3
- /** @type {import('vike/types').Config} */
4
13
  const config = {
5
14
  name: 'vike-ripple',
6
15
  require: { vike: '>=0.4.250' },
7
16
 
8
- onRenderHtml: 'import:vike-ripple/src/integration/onRenderHtml.js:onRenderHtml',
9
- onRenderClient: 'import:vike-ripple/src/integration/onRenderClient.js:onRenderClient',
17
+ onRenderHtml: 'import:vike-ripple/__internal/integration/onRenderHtml:onRenderHtml',
18
+ onRenderClient: 'import:vike-ripple/__internal/integration/onRenderClient:onRenderClient',
10
19
 
11
20
  clientRouting: true,
12
21
  hydrationCanBeAborted: true,
@@ -16,6 +25,7 @@ const config = {
16
25
  meta: {
17
26
  Head: { env: { server: true }, cumulative: true },
18
27
  Layout: { env: { server: true, client: true }, cumulative: true },
28
+ Wrapper: { env: { server: true, client: true }, cumulative: true },
19
29
  title: { env: { server: true, client: true } },
20
30
  description: { env: { server: true } },
21
31
  image: { env: { server: true } },
@@ -26,8 +36,8 @@ const config = {
26
36
  stream: { env: { server: true }, cumulative: true },
27
37
  onBeforeRenderHtml: { env: { server: true }, cumulative: true },
28
38
  onAfterRenderHtml: { env: { server: true }, cumulative: true },
29
- onBeforeRenderClient: { env: { server: false, client: true }, cumulative: true },
30
- onAfterRenderClient: { env: { server: false, client: true }, cumulative: true },
39
+ onBeforeRenderClient: { env: { client: true }, cumulative: true },
40
+ onAfterRenderClient: { env: { client: true }, cumulative: true },
31
41
  bodyHtmlBegin: { env: { server: true }, cumulative: true, global: true },
32
42
  bodyHtmlEnd: { env: { server: true }, cumulative: true, global: true },
33
43
  headHtmlBegin: { env: { server: true }, cumulative: true, global: true },
@@ -0,0 +1,4 @@
1
+ export function clientOnly() {
2
+ console.warn('[vike-ripple] clientOnly() is deprecated — use <ClientOnly>')
3
+ return (props) => props.fallback ?? null
4
+ }
@@ -0,0 +1,7 @@
1
+ export const configsCumulative = [
2
+ 'Head', 'Layout', 'Wrapper',
3
+ 'bodyHtmlBegin', 'bodyHtmlEnd', 'headHtmlBegin', 'headHtmlEnd',
4
+ 'htmlAttributes', 'bodyAttributes',
5
+ 'onBeforeRenderHtml', 'onAfterRenderHtml',
6
+ 'onBeforeRenderClient', 'onAfterRenderClient',
7
+ ]
@@ -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
+ }
@@ -1,6 +1,7 @@
1
+ export { useData }
2
+
1
3
  import { usePageContext } from './usePageContext.js'
2
4
 
3
- export function useData() {
4
- const pageContext = usePageContext()
5
- return pageContext?.data
5
+ function useData() {
6
+ return usePageContext()?.data
6
7
  }
@@ -0,0 +1,7 @@
1
+ export { useHydrated }
2
+ export { setHydrated }
3
+
4
+ let _hydrated = false
5
+
6
+ function useHydrated() { return _hydrated }
7
+ function setHydrated() { _hydrated = true }
@@ -1,6 +1,12 @@
1
- export function usePageContext() {
2
- const pageContext = typeof window !== 'undefined'
3
- ? window.__vike_pageContext
4
- : globalThis.__vike_pageContext
5
- return pageContext
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
- * vike-ripple Vike extension for Ripple TS.
3
- *
4
- * ## Setup
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 value = pageContext.config[key]
5
- if (value !== undefined && value !== null) return value
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 { getHeadSetting } from './getHeadSetting.js'
6
- import { applyHeadSettings } from './applyHeadSettings.js'
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
- await callCumulativeHooks(pageContext.config.onBeforeRenderClient, pageContext)
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
- hydratePage(pageContext, container)
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
- mountPage(pageContext, container)
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 pageContext2 = pageContext
13
- const { Page } = pageContext2
11
+ const { Page } = pageContext
14
12
  if (!Page) throw new Error('No Page')
15
13
 
16
- await callCumulativeHooks(pageContext2.config.onBeforeRenderHtml, pageContext2)
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 headHtml = getHeadHtml(pageContext2)
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(Page, { stream: rippleStream.sink }).catch(e => {
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(Page, {})
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
- const pageHtml = `<div id="root">${body}${cssHtml}</div>`
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 faviconTag = !favicon ? '' : `<link rel="icon" href="${favicon}" />`
81
- const titleTags = !title ? '' : `<title>${title}</title><meta property="og:title" content="${title}" />`
82
- const descriptionTags = !description
83
- ? ''
84
- : `<meta name="description" content="${description}" /><meta property="og:description" content="${description}" />`
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
- const langAttr = getHeadSetting('lang', pageContext)
90
- const headElementsHtml = [
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(head => (typeof head === 'function' ? head(pageContext) : head))
116
+ .map(h => (typeof h === 'function' ? h(pageContext) : h))
96
117
  .join('\n')
97
-
98
- return `${titleTags}${viewportTag}${headElementsHtml}${faviconTag}${descriptionTags}${imageTags}`
118
+ if (headElements) parts.push(headElements)
119
+ return parts.join('\n')
99
120
  }
100
121
 
101
- export function getViewportTag(viewport) {
102
- if (viewport === null || viewport === undefined) return ''
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 '<meta name="viewport" content="width=device-width, initial-scale=1.0" />'
126
+ return ''
106
127
  }
107
128
 
108
129
  function getTagAttributes(pageContext) {
109
- const htmlAttributesString = getTagAttributesString(pageContext.config.htmlAttributes)
110
- const bodyAttributesString = getTagAttributesString(pageContext.config.bodyAttributes)
111
- return { htmlAttributesString, bodyAttributesString }
130
+ return {
131
+ htmlAttributesString: getTagAttributesString(pageContext.config.htmlAttributes),
132
+ bodyAttributesString: getTagAttributesString(pageContext.config.bodyAttributes),
133
+ }
112
134
  }
113
135
 
114
- async function getHtmlInjections(pageContext) {
115
- const headHtmlBegin = (pageContext.config.headHtmlBegin ?? []).join('\n')
116
- const headHtmlEnd = (pageContext.config.headHtmlEnd ?? []).join('\n')
117
- const bodyHtmlBegin = (pageContext.config.bodyHtmlBegin ?? []).join('\n')
118
- const bodyHtmlEnd = (pageContext.config.bodyHtmlEnd ?? []).join('\n')
119
- return { headHtmlBegin, headHtmlEnd, bodyHtmlBegin, bodyHtmlEnd }
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
- env: {
9
- client: true,
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(msg) { console.log('[vike-ripple]', msg) }
18
- function warn(msg) { console.warn('[vike-ripple]', msg) }
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 — skipping'); return }
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 with Vike'); return }
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 isScriptFile.js'); exitCode = 1; return }
21
+ if (patched === src) { warn('Could not patch Vike'); exitCode = 1; return }
33
22
  writeFileSync(target, patched, 'utf-8')
34
- log('Registered .tsrx extension with Vike')
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 — skipping'); return }
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
- return cssCache.get(id);
49
- }
50
-
51
- // Handle ?direct query param added by Vite's SSR module loading
52
- if (id.includes('?direct')) {
53
- const baseId = id.replace('?direct', '');
54
- if (cssCache.has(baseId)) {
55
- return cssCache.get(baseId);
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 load hook'); exitCode = 1; return }
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 module loading')
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
- '// TW_PATCH: prepend tailwindcss so @apply works',
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 to layer(reference) (HMR-safe)')
57
+ log('Upgraded @apply patch');
85
58
  return
86
59
  }
87
-
88
- // Fresh install prepend @import with reference layer
89
- const orig = (
90
- '\t\t\t\t\tif (css) {\n' +
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 support in <style> blocks')
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 { const r = createRequire(join(projectRoot, 'package.json')); return r.resolve('vike/' + rel) } catch { return null }
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 { const r = createRequire(join(projectRoot, 'package.json')); return r.resolve('@ripple-ts/vite-plugin/' + rel) } catch { return null }
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(attributes) {
2
- if (!attributes) return ''
3
- return Object.entries(attributes)
4
- .map(([key, value]) => {
5
- if (value === true) return ` ${key}`
6
- if (value === false || value === null || value === undefined) return ''
7
- return ` ${key}="${String(value).replace(/"/g, '&quot;')}"`
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, '&quot;')}"`
8
8
  })
9
9
  .join('')
10
10
  }
@@ -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
- }
@@ -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
@@ -1,13 +0,0 @@
1
- import 'vike/types'
2
-
3
- declare global {
4
- namespace Vike {
5
- interface PageContext {
6
- _configViaHook?: Record<string, unknown>
7
- _headAlreadySet?: boolean
8
- pageHtmlString?: string
9
- }
10
- }
11
- }
12
-
13
- export type __FakeExport_PageContext = true