vike-ripple 0.2.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +42 -31
  2. package/package.json +12 -4
  3. package/src/setup.js +12 -8
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
- # @vike-ripple/vike-ripple
1
+ # vike-ripple
2
+
3
+ > ⚠️ **HIGHLY EXPERIMENTAL** — This package is in early development. APIs may change without notice, parts may not work, and documentation may be incomplete. Use at your own risk.
2
4
 
3
5
  [Vike](https://vike.dev) integration for [Ripple TS](https://ripple-ts.com) — SSR rendering, client hydration with mount fallback, streaming, `<head>` management, and `.tsrx` page file support.
4
6
 
5
7
  ## Install
6
8
 
7
9
  ```sh
8
- npm install @vike-ripple/vike-ripple
10
+ npm install vike-ripple
9
11
  ```
10
12
 
11
13
  ## Setup
@@ -24,35 +26,28 @@ Or add to your project's `package.json` so it runs automatically after `npm inst
24
26
  }
25
27
  ```
26
28
 
27
- ### 2. Add plugin to `vite.config.ts`
29
+ ### 2. Configure `vite.config.ts`
28
30
 
29
31
  ```ts
30
32
  import { defineConfig } from 'vite'
31
33
  import vike from 'vike/plugin'
32
34
  import { ripple } from '@ripple-ts/vite-plugin'
33
- import vikeRipple from '@vike-ripple/vike-ripple'
35
+ import vikeRipple from 'vike-ripple'
34
36
 
35
37
  export default defineConfig({
36
- optimizeDeps: {
37
- exclude: ['ripple'],
38
- },
39
- plugins: [
40
- vikeRipple(),
41
- ripple({ excludeRippleExternalModules: true }),
42
- vike(),
43
- ],
38
+ optimizeDeps: { exclude: ['ripple'] },
39
+ plugins: [vikeRipple(), ripple({ excludeRippleExternalModules: true }), vike()],
44
40
  })
45
- > **Why `optimizeDeps.exclude: ['ripple']`?** Ripple uses module-scoped variables (`first_child_getter`) shared between `hydrate()` and DOM traversal functions. Vite's dependency optimization splits these into separate bundles, breaking the scope sharing and causing `TypeError: Cannot read properties of undefined (reading 'call')` at `get_first_child` during hydration. Excluding `ripple` from optimization ensures all Ripple internals stay in one module scope.
41
+ ```
46
42
 
47
- ### 3. Add renderer files
43
+ ### 3. Add renderer config
48
44
 
49
- Copy from `node_modules/@vike-ripple/vike-ripple/src/renderer/` to your project's `renderer/`:
45
+ Create `renderer/+config.ts`:
50
46
 
51
- ```
52
- renderer/
53
- +config.ts
54
- +onRenderHtml.tsx
55
- +onRenderClient.tsx
47
+ ```ts
48
+ export default {
49
+ extends: ['import:vike-ripple/config:default'],
50
+ }
56
51
  ```
57
52
 
58
53
  ### 4. Create a page
@@ -71,22 +66,38 @@ export function Page(props: {}) @{
71
66
  }
72
67
  ```
73
68
 
69
+ ## Features
70
+
71
+ | Feature | Status |
72
+ |---|---|
73
+ | `.tsrx` page file support | ✅ |
74
+ | SSR rendering | ✅ |
75
+ | Client hydration with mount fallback | ✅ |
76
+ | Streaming SSR (`rippleStream` config) | ✅ |
77
+ | `<head>` tag extraction | ✅ |
78
+ | `+Layout.tsrx` support | ✅ |
79
+ | `+Head.tsrx` support | ✅ |
80
+ | Config: `title`, `description`, `image`, `viewport`, `favicon`, `lang` | ✅ |
81
+ | Config: `ssr` toggle, `stream` toggle | ✅ |
82
+ | Config: `htmlAttributes`, `bodyAttributes` | ✅ |
83
+ | Config: `headHtmlBegin/End`, `bodyHtmlBegin/End` | ✅ |
84
+ | Hooks: `onBefore/AfterRenderHtml`, `onBefore/AfterRenderClient` | ✅ |
85
+ | `@tailwindcss` integration (via `vike-ripple-tailwindcss`) | ✅ |
86
+ | `@apply` in `<style>` blocks (via `vike-ripple-tailwindcss`) | ✅ |
87
+ | HMR stability during development | 🟡 |
88
+ | TypeScript types for `Vike.Config` / `Vike.PageContext` | 🟡 |
89
+ | Production build testing | 🔴 |
90
+
74
91
  ## What this does
75
92
 
76
93
  | Patch | Why |
77
94
  |---|---|
78
95
  | **`.tsrx` extension** | Vike doesn't know `.tsrx` is a valid page extension — adds it to `isScriptFile.js` |
79
96
  | **`?direct` CSS loading** | Vite's SSR module loader appends `?direct` to module IDs; Ripple's `load` hook checks cache with the wrong key |
80
- | **Hydrate → mount fallback** | Ripple's `hydrate` can mismatch when `<title>` or `<head>` content is extracted during SSR but missing from the client DOM; falls back to `mount` gracefully |
81
-
82
- ## API
83
-
84
- ### `vikeRipple()`
85
-
86
- Vite plugin. Must be placed before `ripple()` in the plugins array, with `enforce: 'pre'` behavior.
97
+ | **`@apply` support** | Prepends `@import "tailwindcss" layer(reference)` to extracted CSS so `@apply` resolves in `<style>` blocks |
87
98
 
88
- ### Renderer files
99
+ ## Known Issues
89
100
 
90
- - **`+onRenderHtml.tsx`** SSR via `ripple/server`'s `render()`, extracts `<head>`, `<body>`, and CSS, injects them into Vike's HTML template. Supports streaming via `rippleStream` config.
91
- - **`+onRenderClient.tsx`** Hydrates with `hydrate()` from `ripple`, falls back to `mount()` on error. Imports `tailwind.css` if present.
92
- - **`+config.ts`** Disables prerender by default, registers `rippleStream` meta config.
101
+ - **Hydration errors**: Ripple's `hydrate()` may throw `TypeError: Illegal invocation` due to Vite dep optimization. Fixed by `optimizeDeps.exclude: ['ripple']` and the mount fallback in the client renderer.
102
+ - **HMR hang**: Editing `.tsrx` files during dev may occasionally cause HMR to hang. Restarting the dev server resolves it.
103
+ - **`</style>` in template literals**: If a `.tsx` file contains `</style>` inside a JavaScript string, the Tailwind Oxide scanner may emit a `CssSyntaxError`. Workaround: break the literal with string concatenation: `"<" + "/style>"`. See [tailwindcss#20000](https://github.com/tailwindlabs/tailwindcss/issues/20000).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-ripple",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Vike extension for Ripple TS — full parity with vike-react/vike-solid/vike-vue",
5
5
  "type": "module",
6
6
  "types": "./src/types/Config.ts",
@@ -19,12 +19,20 @@
19
19
  "bin": {
20
20
  "vike-ripple": "./src/setup.js"
21
21
  },
22
- "files": ["src"],
23
- "keywords": ["vike", "ripple", "ripplets", "ssr", "vite"],
22
+ "files": [
23
+ "src"
24
+ ],
25
+ "keywords": [
26
+ "vike",
27
+ "ripple",
28
+ "ripplets",
29
+ "ssr",
30
+ "vite"
31
+ ],
24
32
  "license": "MIT",
25
33
  "peerDependencies": {
26
34
  "vike": ">=0.4.259",
27
35
  "@ripple-ts/vite-plugin": ">=0.3.0",
28
36
  "ripple": ">=0.1.0"
29
37
  }
30
- }
38
+ }
package/src/setup.js CHANGED
@@ -6,11 +6,11 @@
6
6
  * Or add to project's package.json: "postinstall": "vike-ripple setup"
7
7
  */
8
8
  import { createRequire } from 'module'
9
- import { join, dirname } from 'path'
9
+ import { join } from 'path'
10
10
  import { readFileSync, writeFileSync, existsSync } from 'fs'
11
11
  import { fileURLToPath } from 'url'
12
12
 
13
- const __dirname = dirname(fileURLToPath(import.meta.url))
13
+ const __dirname = fileURLToPath(new URL('.', import.meta.url))
14
14
  const projectRoot = process.cwd()
15
15
  let exitCode = 0
16
16
 
@@ -61,7 +61,7 @@ function patchRippleDirect() {
61
61
  log('Patched Ripple plugin for ?direct CSS module loading')
62
62
  }
63
63
 
64
- // ── Patch 3: @apply support (tailwindcss integration) ──────────
64
+ // ── Patch 3: @apply support ───────────────────────────────────
65
65
  function patchRippleApply() {
66
66
  const target = resolveRipple('src/index.js')
67
67
  if (!target) return
@@ -76,12 +76,16 @@ function patchRippleApply() {
76
76
  '// TW_PATCH: prepend tailwindcss so @apply works',
77
77
  '// TW_PATCH_APPLY: bring tailwindcss into scope for @apply',
78
78
  )
79
+ src = src.replace(
80
+ "css = '@import \"tailwindcss\";\\n' + css;",
81
+ "css = '@import \"tailwindcss\" layer(reference);\\n' + css;",
82
+ )
79
83
  writeFileSync(target, src, 'utf-8')
80
- log('Upgraded @apply patch format')
84
+ log('Upgraded @apply patch to layer(reference) (HMR-safe)')
81
85
  return
82
86
  }
83
87
 
84
- // Fresh install — original unpatched code
88
+ // Fresh install — prepend @import with reference layer
85
89
  const orig = (
86
90
  '\t\t\t\t\tif (css) {\n' +
87
91
  '\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n' +
@@ -90,7 +94,7 @@ function patchRippleApply() {
90
94
  const patched = (
91
95
  '\t\t\t\t\tif (css) {\n' +
92
96
  '\t\t\t\t\t\t// TW_PATCH_APPLY: bring tailwindcss into scope for @apply\n' +
93
- "\t\t\t\t\t\tcss = '@import \"tailwindcss\";\\n' + css;\n" +
97
+ "\t\t\t\t\t\tcss = '@import \"tailwindcss\" layer(reference);\\n' + css;\n" +
94
98
  '\t\t\t\t\t\tconst cssId = createVirtualImportId(filename, root, \'style\');\n' +
95
99
  '\t\t\t\t\t\tcssCache.set(cssId, css);'
96
100
  )
@@ -105,13 +109,13 @@ function patchRippleApply() {
105
109
  function resolveVike(rel) {
106
110
  const p = join(projectRoot, 'node_modules', 'vike', rel)
107
111
  if (existsSync(p)) return p
108
- try { return createRequire(join(projectRoot, 'noop.js')).resolve('vike/' + rel) } catch { return null }
112
+ try { const r = createRequire(join(projectRoot, 'package.json')); return r.resolve('vike/' + rel) } catch { return null }
109
113
  }
110
114
 
111
115
  function resolveRipple(rel) {
112
116
  const p = join(projectRoot, 'node_modules', '@ripple-ts', 'vite-plugin', rel)
113
117
  if (existsSync(p)) return p
114
- try { return createRequire(join(projectRoot, 'noop.js')).resolve('@ripple-ts/vite-plugin/' + rel) } catch { return null }
118
+ try { const r = createRequire(join(projectRoot, 'package.json')); return r.resolve('@ripple-ts/vite-plugin/' + rel) } catch { return null }
115
119
  }
116
120
 
117
121
  // ── Main ──────────────────────────────────────────────────────