vike-solid 0.2.9 → 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.
package/README.md CHANGED
@@ -5,7 +5,4 @@
5
5
 
6
6
  SolidJS integration for [Vike](https://github.com/vikejs/vike).
7
7
 
8
- > [!NOTE]
9
- > For integrations with React and Vue, see the other [`vike-*` packages](https://vike.dev/vike-packages).
10
-
11
8
  See [examples/](https://github.com/vikejs/vike-solid/tree/main/examples).
package/dist/+config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // Depending on the value of `config.meta.ssr`, set other config options' `env`
2
2
  // accordingly.
3
- // See https://vike.dev/meta#modify-existing-configurations
3
+ // See https://vike.dev/meta#:~:text=Modifying%20the%20environment%20of%20existing%20hooks
4
4
  const toggleSsrRelatedConfig = ({
5
5
  configDefinedAt,
6
6
  configValue
@@ -26,19 +26,14 @@ const toggleSsrRelatedConfig = ({
26
26
  };
27
27
  };
28
28
  var _config = {
29
+ // https://vike.dev/onRenderHtml
29
30
  onRenderHtml: "import:vike-solid/renderer/onRenderHtml:onRenderHtml",
31
+ // https://vike.dev/onRenderClient
30
32
  onRenderClient: "import:vike-solid/renderer/onRenderClient:onRenderClient",
31
- // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data)
32
- // TODO/next-major-release: remove support for setting title over onBeforeRender()
33
- // A page can define an onBeforeRender() hook to be run on the server, which
34
- // can fetch data and return it as additional page context. Typically it will
35
- // return the page's root Solid component's props and additional data that can
36
- // be used by the renderers.
37
- // It is a cumulative config option, so a web app using vike-solid can extend
38
- // this list.
39
- passToClient: ["pageProps", "title", "lang"],
33
+ // https://vike.dev/clientRouting
40
34
  clientRouting: true,
41
35
  hydrationCanBeAborted: true,
36
+ // https://vike.dev/meta
42
37
  meta: {
43
38
  Head: {
44
39
  env: {
@@ -57,14 +52,10 @@ var _config = {
57
52
  client: true
58
53
  }
59
54
  },
60
- description: {
61
- env: {
62
- server: true
63
- }
64
- },
65
55
  favicon: {
66
56
  env: {
67
- server: true
57
+ server: true,
58
+ client: true
68
59
  }
69
60
  },
70
61
  lang: {
@@ -88,5 +79,6 @@ var _config = {
88
79
  };
89
80
 
90
81
  // We purposely define the ConfigVikeSolid interface in this file: that way we ensure it's always applied whenever the user `import vikeSolid from 'vike-solid'`
82
+ // https://vike.dev/pageContext#typescript
91
83
 
92
84
  export { _config as default };
@@ -1,4 +1,4 @@
1
- import { createComponent, Dynamic, mergeProps, memo, hydrate, render } from 'solid-js/web';
1
+ import { createComponent, Dynamic, memo, hydrate, render } from 'solid-js/web';
2
2
  import { P as PageContextProvider, u as usePageContext } from './PageContextProvider-OTjP33FZ.js';
3
3
  import { createStore, reconcile } from 'solid-js/store';
4
4
  import 'solid-js';
@@ -7,43 +7,21 @@ function isCallable(thing) {
7
7
  return thing instanceof Function || typeof thing === 'function';
8
8
  }
9
9
 
10
- /**
11
- * Get the page's title if defined, either from the additional data fetched by
12
- * the page's data() and onBeforeRender() hook or from the config.
13
- */
14
- function getTitle(pageContext) {
15
- // from data() hook
16
- if (pageContext.data?.title !== undefined) {
17
- return pageContext.data.title;
18
- }
19
-
20
- // TODO/next-major-release: remove support for setting title over onBeforeRender()
21
- // from onBeforeRender() hook
22
- if (pageContext.title !== undefined) {
23
- return pageContext.title;
24
- }
25
- const titleConfig = pageContext.configEntries.title?.[0];
26
- if (!titleConfig) {
27
- return null;
28
- }
29
- const title = titleConfig.configValue;
30
- if (typeof title === "string") {
31
- return title;
32
- }
33
- if (!title) {
34
- return null;
35
- }
36
- const {
37
- configDefinedAt
38
- } = titleConfig;
39
- if (isCallable(title)) {
40
- const val = title(pageContext);
41
- if (typeof val !== "string") {
42
- throw new Error(configDefinedAt + " should return a string");
10
+ function getHeadSetting(headSetting, pageContext) {
11
+ const config = pageContext.configEntries[headSetting]?.[0];
12
+ if (!config) return undefined;
13
+ const val = config.configValue;
14
+ if (typeof val === "string") return val;
15
+ if (!val) return null;
16
+ if (isCallable(val)) {
17
+ const valStr = val(pageContext);
18
+ if (typeof valStr !== "string") {
19
+ throw new Error(config.configDefinedAt + " should return a string");
43
20
  }
44
- return val;
21
+ return valStr;
22
+ } else {
23
+ throw new Error(config.configDefinedAt + " should be a string or a function returning a string");
45
24
  }
46
- throw new Error(configDefinedAt + " should be a string or a function returning a string");
47
25
  }
48
26
 
49
27
  function getPageElement(pageContext) {
@@ -72,50 +50,16 @@ function Layout(props) {
72
50
  }
73
51
  function Page() {
74
52
  const pageContext = usePageContext();
75
- // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data)
76
- return createComponent(Dynamic, mergeProps({
53
+ return createComponent(Dynamic, {
77
54
  get component() {
78
55
  return pageContext.Page;
79
56
  }
80
- }, () => pageContext.pageProps ?? {}));
57
+ });
81
58
  }
82
59
  function Passthrough(props) {
83
60
  return memo(() => props.children);
84
61
  }
85
62
 
86
- /**
87
- * Get the page's lang if defined, either from the config, the additional data fetched by
88
- * the page's data() and onBeforeRender() hooks or from other hooks.
89
- */
90
- function getLang(pageContext) {
91
- // from onBeforeRoute() hook & other hooks, e.g. onPrerenderStart() hook
92
- if (pageContext.lang !== undefined) {
93
- return pageContext.lang;
94
- }
95
- const langConfig = pageContext.configEntries.lang?.[0];
96
- if (!langConfig) {
97
- return null;
98
- }
99
- const lang = langConfig.configValue;
100
- if (typeof lang === 'string') {
101
- return lang;
102
- }
103
- if (!lang) {
104
- return null;
105
- }
106
- const {
107
- configDefinedAt
108
- } = langConfig;
109
- if (isCallable(lang)) {
110
- const val = lang(pageContext);
111
- if (typeof val !== 'string') {
112
- throw new Error(configDefinedAt + ' should return a string');
113
- }
114
- return val;
115
- }
116
- throw new Error(configDefinedAt + ' should be a string or a function returning a string');
117
- }
118
-
119
63
  // https://vike.dev/onRenderClient
120
64
  const [pageContextStore, setPageContext] = createStore({});
121
65
  let dispose;
@@ -135,19 +79,37 @@ const onRenderClient = async pageContext => {
135
79
  }
136
80
  rendered = true;
137
81
  } else {
138
- // Client routing
139
- // See https://vike.dev/server-routing-vs-client-routing
82
+ // Client-side navigation
140
83
 
141
84
  setPageContext(reconcile(pageContext));
85
+ const title = getHeadSetting("title", pageContext) || "";
86
+ const lang = getHeadSetting("lang", pageContext) || "en";
87
+ const favicon = getHeadSetting("favicon", pageContext);
142
88
 
143
- // Get the page's `title` config value, which may be different from the
144
- // previous page. It can even be null, in which case we should unset the
145
- // document title.
146
- const title = getTitle(pageContext);
147
- const lang = getLang(pageContext) || 'en';
148
- document.title = title || "";
149
- document.documentElement.lang = lang;
89
+ // We skip if the value is undefined because we shouldn't remove values set in HTML (by the Head setting).
90
+ // - This also means that previous values will leak: upon client-side navigation, the title set by the previous
91
+ // page won't be removed if the next page doesn't override it. But that's okay because usually pages always have
92
+ // a favicon and title, which means that previous values are always overridden. Also, as a workaround, the user
93
+ // can set the value to `null` to ensure that previous values are overridden.
94
+ if (title !== undefined) document.title = title;
95
+ if (lang !== undefined) document.documentElement.lang = lang;
96
+ if (favicon !== undefined) setFavicon(favicon);
150
97
  }
151
98
  };
152
99
 
100
+ // https://stackoverflow.com/questions/260857/changing-website-favicon-dynamically/260876#260876
101
+ function setFavicon(faviconUrl) {
102
+ let link = document.querySelector("link[rel~='icon']");
103
+ if (!faviconUrl) {
104
+ if (link) document.head.removeChild(link);
105
+ return;
106
+ }
107
+ if (!link) {
108
+ link = document.createElement("link");
109
+ link.rel = "icon";
110
+ document.head.appendChild(link);
111
+ }
112
+ link.href = faviconUrl;
113
+ }
114
+
153
115
  export { onRenderClient };
@@ -1,4 +1,4 @@
1
- import { createComponent, Dynamic, mergeProps, renderToString, renderToStream, generateHydrationScript } from 'solid-js/web';
1
+ import { createComponent, Dynamic, renderToString, renderToStream, generateHydrationScript } from 'solid-js/web';
2
2
  import { version, escapeInject, dangerouslySkipEscape, stampPipe } from 'vike/server';
3
3
  import { P as PageContextProvider, u as usePageContext } from './PageContextProvider-OTjP33FZ.js';
4
4
  import 'solid-js';
@@ -7,43 +7,21 @@ function isCallable(thing) {
7
7
  return thing instanceof Function || typeof thing === 'function';
8
8
  }
9
9
 
10
- /**
11
- * Get the page's title if defined, either from the additional data fetched by
12
- * the page's data() and onBeforeRender() hook or from the config.
13
- */
14
- function getTitle(pageContext) {
15
- // from data() hook
16
- if (pageContext.data?.title !== undefined) {
17
- return pageContext.data.title;
18
- }
19
-
20
- // TODO/next-major-release: remove support for setting title over onBeforeRender()
21
- // from onBeforeRender() hook
22
- if (pageContext.title !== undefined) {
23
- return pageContext.title;
24
- }
25
- const titleConfig = pageContext.configEntries.title?.[0];
26
- if (!titleConfig) {
27
- return null;
28
- }
29
- const title = titleConfig.configValue;
30
- if (typeof title === "string") {
31
- return title;
32
- }
33
- if (!title) {
34
- return null;
35
- }
36
- const {
37
- configDefinedAt
38
- } = titleConfig;
39
- if (isCallable(title)) {
40
- const val = title(pageContext);
41
- if (typeof val !== "string") {
42
- throw new Error(configDefinedAt + " should return a string");
10
+ function getHeadSetting(headSetting, pageContext) {
11
+ const config = pageContext.configEntries[headSetting]?.[0];
12
+ if (!config) return undefined;
13
+ const val = config.configValue;
14
+ if (typeof val === "string") return val;
15
+ if (!val) return null;
16
+ if (isCallable(val)) {
17
+ const valStr = val(pageContext);
18
+ if (typeof valStr !== "string") {
19
+ throw new Error(config.configDefinedAt + " should return a string");
43
20
  }
44
- return val;
21
+ return valStr;
22
+ } else {
23
+ throw new Error(config.configDefinedAt + " should be a string or a function returning a string");
45
24
  }
46
- throw new Error(configDefinedAt + " should be a string or a function returning a string");
47
25
  }
48
26
 
49
27
  function getPageElement(pageContext) {
@@ -72,61 +50,23 @@ function Layout(props) {
72
50
  }
73
51
  function Page() {
74
52
  const pageContext = usePageContext();
75
- // TODO/next-major-release: remove pageProps (i.e. tell users to use data() instead of onBeforeRender() to fetch data)
76
- return createComponent(Dynamic, mergeProps({
53
+ return createComponent(Dynamic, {
77
54
  get component() {
78
55
  return pageContext.Page;
79
56
  }
80
- }, () => pageContext.pageProps ?? {}));
57
+ });
81
58
  }
82
59
  function Passthrough(props) {
83
60
  return props.children;
84
61
  }
85
62
 
86
- /**
87
- * Get the page's lang if defined, either from the config, the additional data fetched by
88
- * the page's data() and onBeforeRender() hooks or from other hooks.
89
- */
90
- function getLang(pageContext) {
91
- // from onBeforeRoute() hook & other hooks, e.g. onPrerenderStart() hook
92
- if (pageContext.lang !== undefined) {
93
- return pageContext.lang;
94
- }
95
- const langConfig = pageContext.configEntries.lang?.[0];
96
- if (!langConfig) {
97
- return null;
98
- }
99
- const lang = langConfig.configValue;
100
- if (typeof lang === 'string') {
101
- return lang;
102
- }
103
- if (!lang) {
104
- return null;
105
- }
106
- const {
107
- configDefinedAt
108
- } = langConfig;
109
- if (isCallable(lang)) {
110
- const val = lang(pageContext);
111
- if (typeof val !== 'string') {
112
- throw new Error(configDefinedAt + ' should return a string');
113
- }
114
- return val;
115
- }
116
- throw new Error(configDefinedAt + ' should be a string or a function returning a string');
117
- }
118
-
119
63
  checkVikeVersion();
120
64
  const onRenderHtml = async pageContext => {
121
- const {
122
- stream,
123
- favicon,
124
- description
125
- } = pageContext.config;
126
- const title = getTitle(pageContext);
65
+ const title = getHeadSetting("title", pageContext);
66
+ const favicon = getHeadSetting("favicon", pageContext);
67
+ const lang = getHeadSetting("lang", pageContext) || "en";
127
68
  const titleTag = !title ? "" : escapeInject`<title>${title}</title>`;
128
- const faviconTag = !favicon ? '' : escapeInject`<link rel="icon" href="${favicon}" />`;
129
- const descriptionTag = !description ? '' : escapeInject`<meta name="description" content="${description}" />`;
69
+ const faviconTag = !favicon ? "" : escapeInject`<link rel="icon" href="${favicon}" />`;
130
70
  const Head = pageContext.config.Head || (() => []);
131
71
  const headHtml = renderToString(() => createComponent(PageContextProvider, {
132
72
  pageContext: pageContext,
@@ -134,24 +74,22 @@ const onRenderHtml = async pageContext => {
134
74
  return createComponent(Head, {});
135
75
  }
136
76
  }));
137
- let pageView = '';
77
+ let pageView = "";
138
78
  if (!!pageContext.Page) {
139
- if (!stream) {
79
+ if (!pageContext.config.stream) {
140
80
  pageView = dangerouslySkipEscape(renderToString(() => getPageElement(pageContext)));
141
81
  } else {
142
82
  pageView = renderToStream(() => getPageElement(pageContext)).pipe;
143
83
  stampPipe(pageView, "node-stream");
144
84
  }
145
85
  }
146
- const lang = getLang(pageContext) || "en";
147
86
  const documentHtml = escapeInject`<!DOCTYPE html>
148
87
  <html lang='${lang}'>
149
88
  <head>
150
89
  <meta charset="UTF-8" />
151
90
  ${titleTag}
152
- ${faviconTag}
153
- ${descriptionTag}
154
91
  ${dangerouslySkipEscape(headHtml)}
92
+ ${faviconTag}
155
93
  ${dangerouslySkipEscape(generateHydrationScript())}
156
94
  </head>
157
95
  <body>
@@ -163,12 +101,12 @@ const onRenderHtml = async pageContext => {
163
101
  };
164
102
  function checkVikeVersion() {
165
103
  if (version) {
166
- const versionParts = version.split('.').map(s => parseInt(s, 10));
104
+ const versionParts = version.split(".").map(s => parseInt(s, 10));
167
105
  if (versionParts[0] > 0) return;
168
106
  if (versionParts[1] > 4) return;
169
107
  if (versionParts[2] >= 147) return;
170
108
  }
171
- throw new Error('Update Vike to its latest version (or vike@0.4.147 and any version above)');
109
+ throw new Error("Update Vike to 0.4.147 or above");
172
110
  }
173
111
 
174
112
  export { onRenderHtml };
@@ -1,21 +1,11 @@
1
1
  import { PageContext, ConfigEffect } from 'vike/types';
2
2
  import { JSX, Component } from 'solid-js';
3
3
 
4
- type Page = (pageProps: PageProps) => JSX.Element;
5
- type PageProps = Record<string, unknown>;
4
+ type Page = () => JSX.Element;
6
5
  declare global {
7
6
  namespace Vike {
8
7
  interface PageContext {
9
8
  Page?: Page;
10
- /** Properties of the page's root Solid component - e.g. set by onBeforeRender() hook */
11
- pageProps?: Record<string, unknown>;
12
- /** &lt;title>${title}&lt;/title> - set by onBeforeRender() hook, has precedence over the config */
13
- title?: string;
14
- lang?: string;
15
- data?: {
16
- /** &lt;title>${title}&lt;/title> - set by data() hook, has precedence over the onBeforeRender() hook */
17
- title?: string;
18
- };
19
9
  }
20
10
  }
21
11
  }
@@ -23,7 +13,6 @@ declare global {
23
13
  declare const _default: {
24
14
  onRenderHtml: "import:vike-solid/renderer/onRenderHtml:onRenderHtml";
25
15
  onRenderClient: "import:vike-solid/renderer/onRenderClient:onRenderClient";
26
- passToClient: string[];
27
16
  clientRouting: true;
28
17
  hydrationCanBeAborted: true;
29
18
  meta: {
@@ -44,14 +33,10 @@ declare const _default: {
44
33
  client: true;
45
34
  };
46
35
  };
47
- description: {
48
- env: {
49
- server: true;
50
- };
51
- };
52
36
  favicon: {
53
37
  env: {
54
38
  server: true;
39
+ client: true;
55
40
  };
56
41
  };
57
42
  lang: {
@@ -84,7 +69,6 @@ declare global {
84
69
  /** A component, usually common to several pages, that wraps the root component `Page` */
85
70
  Layout?: Component;
86
71
  title?: string | ((pageContext: PageContext) => string);
87
- description?: string;
88
72
  favicon?: string;
89
73
  /**
90
74
  * @default 'en'
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "vike-solid",
3
- "version": "0.2.9",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "dependencies": {
6
- "vite-plugin-solid": "^2.8.0"
6
+ "vite-plugin-solid": "^2.9.1"
7
7
  },
8
8
  "peerDependencies": {
9
9
  "solid-js": "^1.8.7",
10
10
  "vite": "^4.4 || ^5.0.2",
11
- "vike": "^0.4.152"
11
+ "vike": "^0.4.159"
12
12
  },
13
13
  "devDependencies": {
14
14
  "@babel/core": "^7.23.7",
@@ -17,15 +17,15 @@
17
17
  "@rollup/plugin-babel": "^6.0.4",
18
18
  "@rollup/plugin-node-resolve": "^15.2.3",
19
19
  "@types/node": "^18.17.4",
20
- "babel-preset-solid": "^1.8.9",
21
- "bumpp": "^9.2.1",
22
- "rollup": "^4.9.5",
20
+ "babel-preset-solid": "^1.8.12",
21
+ "bumpp": "^9.3.0",
22
+ "rollup": "^4.9.6",
23
23
  "rollup-plugin-dts": "^6.1.0",
24
- "solid-js": "^1.8.11",
24
+ "solid-js": "^1.8.12",
25
25
  "tslib": "^2.6.2",
26
26
  "typescript": "^5.3.3",
27
- "vite": "^5.0.11",
28
- "vike": "^0.4.156"
27
+ "vite": "^5.0.12",
28
+ "vike": "^0.4.160"
29
29
  },
30
30
  "exports": {
31
31
  ".": "./dist/+config.js",