Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/server-only-templates-hmr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-solid': patch
---

Keep `$ServerOnly` templates in client transforms while HMR is active so hot updates of components using `$ServerOnly` no longer throw `template is not a function`. An explicit `solid.omitServerOnlyTemplates` setting still takes precedence.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ Pass any additional [babel transform options](https://babeljs.io/docs/en/options
Pass any additional [babel-plugin-jsx-dom-expressions](https://github.com/ryansolid/dom-expressions/tree/main/packages/babel-plugin-jsx-dom-expressions#plugin-options).
They will be merged with the defaults sets by [babel-preset-solid](https://github.com/solidjs/solid/blob/main/packages/babel-preset-solid/index.js#L8-L25).

In dev with HMR enabled, the plugin sets `omitServerOnlyTemplates: false` for client transforms so that components containing `$ServerOnly` elements can be re-created by Solid Refresh. Pass `omitServerOnlyTemplates` explicitly to override this.

#### options.typescript

- Type: [@babel/preset-typescript](https://babeljs.io/docs/en/babel-preset-typescript)
Expand Down
26 changes: 25 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,19 @@ export interface Options {
*/
omitQuotes?: boolean;

/**
* Only applies when `hydratable` is `true`. When `true`, an element marked
* `$ServerOnly` registers no client template, so it can only be obtained by
* hydrating server-rendered DOM and throws if it is ever re-created on the client.
*
* The plugin sets this to `false` for client transforms in dev while HMR is
* enabled, since Solid Refresh re-runs components outside of hydration. Pass
* an explicit value to override that.
*
* @default true
*/
omitServerOnlyTemplates?: boolean;

/**
* The name of the runtime module to import the methods from.
*
Expand Down Expand Up @@ -397,11 +410,22 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
plugins.push('typescript');
}

// babel-plugin-jsx-dom-expressions >= 0.40.10 omits the client template of
// `$ServerOnly` elements by default, so re-creating such an element outside
// of hydration throws "template is not a function". Solid Refresh does
// exactly that on every hot update, so keep the templates in client HMR
// transforms. An explicit user setting still wins.
const presetOptions = {
...solidOptions,
...(needHmr && !isSsr ? { omitServerOnlyTemplates: false } : {}),
...(options.solid || {}),
};

const opts: babel.TransformOptions = {
root: projectRoot,
filename: id,
sourceFileName: id,
presets: [[solid, { ...solidOptions, ...(options.solid || {}) }]],
presets: [[solid, presetOptions]],
plugins: needHmr && !isSsr && !inNodeModules ? [[solidRefresh, { bundler: 'vite' }]] : [],
ast: false,
sourceMaps: true,
Expand Down
Loading