vike-lite 1.15.7 → 1.15.9

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.
@@ -0,0 +1,6 @@
1
+ //#region src/__internal/client.d.ts
2
+ declare function createLinkClickHandler(onNavigate: (url: URL) => void): (e: MouseEvent) => void;
3
+ declare function createLinkPrefetchHandler(onPrefetch: (url: URL) => void): (e: Event) => void;
4
+ declare function finalizeNavigation(shouldScrollToTop: boolean): void;
5
+ //#endregion
6
+ export { createLinkClickHandler, createLinkPrefetchHandler, finalizeNavigation };
@@ -0,0 +1,43 @@
1
+ //#region src/__internal/client.ts
2
+ function getClientSideUrl(target) {
3
+ if (!target?.href || target.target && target.target !== "_self" || target.hasAttribute("download") || target.hasAttribute("data-native") || target.getAttribute("rel")?.includes("external")) return null;
4
+ try {
5
+ const url = new URL(target.href, globalThis.location.href);
6
+ if (url.protocol !== "http:" && url.protocol !== "https:" || url.origin !== globalThis.location.origin) return null;
7
+ return url;
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+ function isSamePage(url) {
13
+ return url.pathname === globalThis.location.pathname && url.search === globalThis.location.search;
14
+ }
15
+ function createLinkClickHandler(onNavigate) {
16
+ return (e) => {
17
+ if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
18
+ const url = getClientSideUrl(e.target.closest("a"));
19
+ if (!url || isSamePage(url)) return;
20
+ e.preventDefault();
21
+ globalThis.history.pushState({ triggeredBy: "vike-lite" }, "", url.href);
22
+ onNavigate(url);
23
+ };
24
+ }
25
+ function createLinkPrefetchHandler(onPrefetch) {
26
+ return (e) => {
27
+ const url = getClientSideUrl(e.target.closest("a"));
28
+ if (!url || isSamePage(url)) return;
29
+ onPrefetch(url);
30
+ };
31
+ }
32
+ function finalizeNavigation(shouldScrollToTop) {
33
+ if (shouldScrollToTop) {
34
+ globalThis.scrollTo(0, 0);
35
+ shouldScrollToTop = false;
36
+ } else if (globalThis.location.hash) requestAnimationFrame(() => {
37
+ try {
38
+ document.querySelector(decodeURIComponent(globalThis.location.hash))?.scrollIntoView();
39
+ } catch {}
40
+ });
41
+ }
42
+ //#endregion
43
+ export { createLinkClickHandler, createLinkPrefetchHandler, finalizeNavigation };
@@ -1,6 +1,6 @@
1
1
  //#region src/server/store.d.ts
2
2
  interface VikeState {
3
- routes: typeof import('virtual:vike-lite/routes')['routes'];
3
+ routes: typeof import('virtual:vike-lite/routes')['routes'] | [];
4
4
  errorRoute: typeof import('virtual:vike-lite/routes')['errorRoute'] | null;
5
5
  config: typeof import('virtual:vike-lite/routes')['config'] | null;
6
6
  manifest: typeof import('virtual:vike-lite/client-manifest')['default'] | null;
@@ -1,2 +1,2 @@
1
- import { n as store, t as setVikeState } from "../store-DPJQje-K.mjs";
1
+ import { n as store, t as setVikeState } from "../store-BCs8gL_o.mjs";
2
2
  export { setVikeState, store };
@@ -1,10 +1,4 @@
1
- //#region src/__internal/shared/matchRoute.d.ts
2
- declare function matchRoute(urlPathname: string, routes: typeof import('virtual:vike-lite/routes').routes): {
3
- route: any;
4
- routeParams: Record<string, string>;
5
- } | null;
6
- //#endregion
7
- //#region src/__internal/shared/index.d.ts
1
+ //#region src/__internal/shared.d.ts
8
2
  interface RenderContext {
9
3
  pageContext: any;
10
4
  Page: unknown;
@@ -19,5 +13,11 @@ interface RenderContext {
19
13
  };
20
14
  nonce?: string;
21
15
  }
16
+ declare function matchRoute(urlPathname: string, routes: typeof import('virtual:vike-lite/routes').routes): {
17
+ route: any;
18
+ routeParams: Record<string, string>;
19
+ } | null;
20
+ declare const BASE_URL: string;
21
+ declare function stripBase(pathname: string): string;
22
22
  //#endregion
23
- export { RenderContext, matchRoute };
23
+ export { BASE_URL, RenderContext, matchRoute, stripBase };
@@ -1,2 +1,54 @@
1
- import { t as matchRoute } from "../matchRoute-nTNPxoMq.mjs";
2
- export { matchRoute };
1
+ //#region src/__internal/shared.ts
2
+ const regexCache = /* @__PURE__ */ new Map();
3
+ function escapeRegex(str) {
4
+ return str.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
5
+ }
6
+ function matchRoute(urlPathname, routes) {
7
+ for (const route of routes) {
8
+ if (!route.path.includes(":")) {
9
+ if (route.path === urlPathname || route.path + "/" === urlPathname) return {
10
+ route,
11
+ routeParams: {}
12
+ };
13
+ continue;
14
+ }
15
+ let compiled = regexCache.get(route.path);
16
+ if (!compiled) {
17
+ const paramNames = [];
18
+ const regexPath = route.path.split("/").map((segment) => {
19
+ if (segment.startsWith(":")) {
20
+ paramNames.push(segment.slice(1));
21
+ return "([^/]+)";
22
+ }
23
+ return escapeRegex(segment);
24
+ }).join("/");
25
+ compiled = {
26
+ regex: new RegExp(`^${regexPath}/?$`),
27
+ paramNames
28
+ };
29
+ regexCache.set(route.path, compiled);
30
+ }
31
+ const match = urlPathname.match(compiled.regex);
32
+ if (match) {
33
+ const routeParams = {};
34
+ for (let i = 0; i < compiled.paramNames.length; i++) routeParams[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);
35
+ return {
36
+ route,
37
+ routeParams
38
+ };
39
+ }
40
+ }
41
+ return null;
42
+ }
43
+ const BASE_URL = (() => {
44
+ const { BASE_URL } = import.meta.env;
45
+ return BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL;
46
+ })();
47
+ function stripBase(pathname) {
48
+ if (BASE_URL === "") return pathname;
49
+ if (pathname === BASE_URL) return "/";
50
+ if (pathname.startsWith(BASE_URL + "/")) return pathname.slice(BASE_URL.length);
51
+ return pathname;
52
+ }
53
+ //#endregion
54
+ export { BASE_URL, matchRoute, stripBase };
@@ -1,3 +1,4 @@
1
+ import { BASE_URL } from "../__internal/shared.mjs";
1
2
  //#region src/client/router.ts
2
3
  /**
3
4
  * Change page programmatically on the client without reloading the browser.
@@ -7,10 +8,7 @@
7
8
  function navigate(url, options) {
8
9
  if (typeof globalThis === "undefined") throw new Error("navigate() can only be called on the client side.");
9
10
  let finalUrl = url;
10
- if (finalUrl.startsWith("/")) {
11
- const { BASE_URL } = import.meta.env;
12
- finalUrl = (BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL) + (finalUrl === "/" ? "" : finalUrl);
13
- }
11
+ if (finalUrl.startsWith("/")) finalUrl = BASE_URL + (finalUrl === "/" ? "" : finalUrl);
14
12
  globalThis.history.pushState({ triggeredBy: "vike-lite" }, "", finalUrl);
15
13
  globalThis.dispatchEvent(new CustomEvent("vike-navigate", { detail: {
16
14
  keepScrollPosition: options?.keepScrollPosition,
@@ -1,6 +1,6 @@
1
- import { t as matchRoute } from "./matchRoute-nTNPxoMq.mjs";
1
+ import { BASE_URL, matchRoute, stripBase } from "./__internal/shared.mjs";
2
2
  import { AbortRedirect, AbortRender } from "./server/abort.mjs";
3
- import { n as store } from "./store-DPJQje-K.mjs";
3
+ import { n as store } from "./store-BCs8gL_o.mjs";
4
4
  //#region src/utils/serializeContext.ts
5
5
  const ESCAPE_LOOKUP = {
6
6
  "&": String.raw`\u0026`,
@@ -17,8 +17,7 @@ function serializeContext(data) {
17
17
  //#region src/server/renderPage.ts
18
18
  const isProd = process.env.NODE_ENV === "production";
19
19
  function withBase(file) {
20
- const { BASE_URL } = import.meta.env;
21
- return `${BASE_URL === "/" ? "" : BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL}${file.startsWith("/") ? file : `/${file}`}`;
20
+ return `${BASE_URL === "" ? "" : BASE_URL}${file.startsWith("/") ? file : `/${file}`}`;
22
21
  }
23
22
  const assetsCache = /* @__PURE__ */ new WeakMap();
24
23
  function computeAssetFiles(route) {
@@ -160,12 +159,7 @@ async function renderErrorPage(req, status, urlPathname, error, nonce) {
160
159
  }
161
160
  async function renderPage(req, { nonce } = {}) {
162
161
  let { pathname } = new URL(req.url);
163
- const { BASE_URL } = import.meta.env;
164
- if (BASE_URL !== "/") {
165
- const baseSlashed = BASE_URL.endsWith("/") ? BASE_URL : BASE_URL + "/";
166
- const baseNoSlash = baseSlashed.slice(0, -1);
167
- pathname = pathname === baseNoSlash ? "/" : pathname.slice(baseSlashed.length - 1);
168
- }
162
+ pathname = stripBase(pathname);
169
163
  const isJsonRequest = pathname.endsWith(".pageContext.json");
170
164
  let targetPathname = pathname;
171
165
  if (isJsonRequest) {
@@ -197,7 +191,7 @@ async function renderPage(req, { nonce } = {}) {
197
191
  } catch (error) {
198
192
  if (error instanceof AbortRedirect) {
199
193
  let redirectUrl = error.url;
200
- if (redirectUrl.startsWith("/")) redirectUrl = (BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL) + (redirectUrl === "/" ? "" : redirectUrl);
194
+ if (redirectUrl.startsWith("/")) redirectUrl = BASE_URL + (redirectUrl === "/" ? "" : redirectUrl);
201
195
  if (isJsonRequest) return Response.json({ _redirect: redirectUrl }, { status: 200 });
202
196
  return new Response(null, {
203
197
  status: error.statusCode,
package/dist/server.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { t as renderPage } from "./server-BITt1YvS.mjs";
1
+ import { t as renderPage } from "./server-CRcgzWMc.mjs";
2
2
  export { renderPage };
@@ -0,0 +1,13 @@
1
+ //#region src/server/store.ts
2
+ const KEY = Symbol.for("vike-lite:store");
3
+ const store = globalThis[KEY] ??= {
4
+ routes: [],
5
+ errorRoute: null,
6
+ config: null,
7
+ manifest: null
8
+ };
9
+ function setVikeState(newState) {
10
+ Object.assign(store, newState);
11
+ }
12
+ //#endregion
13
+ export { store as n, setVikeState as t };
package/dist/vite.mjs CHANGED
@@ -1,12 +1,13 @@
1
- import { t as renderPage } from "./server-BITt1YvS.mjs";
1
+ import { BASE_URL } from "./__internal/shared.mjs";
2
+ import { t as renderPage } from "./server-CRcgzWMc.mjs";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import { Readable } from "node:stream";
5
6
  import { pipeline } from "node:stream/promises";
6
7
  import { loadEnv } from "vite";
7
8
  //#region src/utils/generateRoutes.ts
8
- const pageExtensions = [".ts", ".js"];
9
- const pageExtensionsX = [
9
+ const nonPageExtensions = [".ts", ".js"];
10
+ const pageExtensions = [
10
11
  ".tsx",
11
12
  ".jsx",
12
13
  ".vue"
@@ -22,19 +23,19 @@ function generateRoutes(viteRoot, pagesDir) {
22
23
  function walk(dir, routePath, parentLayout, parentHead) {
23
24
  const files = fs.readdirSync(dir);
24
25
  const importPath = path.relative(viteRoot, dir).replaceAll("\\", "/");
25
- const layoutFile = findFile(files, "+Layout", pageExtensionsX);
26
+ const layoutFile = findFile(files, "+Layout", pageExtensions);
26
27
  const currentLayout = layoutFile ? `${importPath}/${layoutFile}` : parentLayout;
27
- const headFile = findFile(files, "+Head", pageExtensionsX);
28
+ const headFile = findFile(files, "+Head", pageExtensions);
28
29
  const currentHead = headFile ? `${importPath}/${headFile}` : parentHead;
29
- const pageFile = findFile(files, "+Page", pageExtensionsX);
30
+ const pageFile = findFile(files, "+Page", pageExtensions);
30
31
  if (pageFile) {
31
32
  const route = {
32
33
  path: routePath || "/",
33
34
  page: `${importPath}/${pageFile}`
34
35
  };
35
- const dataFile = findFile(files, "+data", pageExtensions);
36
- const titleFile = findFile(files, "+title", pageExtensions);
37
- const prerenderFile = findFile(files, "+prerender", pageExtensions);
36
+ const dataFile = findFile(files, "+data", nonPageExtensions);
37
+ const titleFile = findFile(files, "+title", nonPageExtensions);
38
+ const prerenderFile = findFile(files, "+prerender", nonPageExtensions);
38
39
  if (dataFile) route.data = `${importPath}/${dataFile}`;
39
40
  if (titleFile) route.title = `${importPath}/${titleFile}`;
40
41
  if (prerenderFile) route.prerender = `${importPath}/${prerenderFile}`;
@@ -46,7 +47,7 @@ function generateRoutes(viteRoot, pagesDir) {
46
47
  const fullPath = path.join(dir, file);
47
48
  if (!fs.statSync(fullPath).isDirectory()) continue;
48
49
  if (file === "_error") {
49
- const errorPageFile = findFile(fs.readdirSync(fullPath), "+Page", pageExtensionsX);
50
+ const errorPageFile = findFile(fs.readdirSync(fullPath), "+Page", pageExtensions);
50
51
  if (errorPageFile) errorRoute = {
51
52
  path: "_error",
52
53
  page: `${importPath}/_error/${errorPageFile}`,
@@ -322,19 +323,17 @@ function vikeLite({ pagesDir = "pages", apiPrefix = "/api", prerender = false, s
322
323
  }
323
324
  if (urlsToPrerender.size === 0) return;
324
325
  console.log("[vike-lite] 📦 Starting Static Site Generation (SSG)…");
325
- const { BASE_URL } = import.meta.env;
326
- const baseNoSlash = BASE_URL.endsWith("/") ? BASE_URL.slice(0, -1) : BASE_URL;
327
326
  let generatedCount = 0;
328
327
  const clientDir = path.join(viteConfigRoot, outDir, "client");
329
328
  for (const urlPath of urlsToPrerender) {
330
- const htmlRes = await renderPage(new Request(`http://localhost${baseNoSlash}${urlPath}`));
329
+ const htmlRes = await renderPage(new Request(`http://localhost${BASE_URL}${urlPath}`));
331
330
  if (htmlRes?.ok && htmlRes.headers.get("content-type")?.includes("text/html")) {
332
331
  const outDirRoute = path.join(clientDir, urlPath === "/" ? "" : urlPath);
333
332
  fs.mkdirSync(outDirRoute, { recursive: true });
334
333
  fs.writeFileSync(path.join(outDirRoute, "index.html"), await htmlRes.text());
335
334
  } else throw new Error(`[vike-lite] ❌ SSG HTML Error for "${urlPath}"`);
336
335
  const jsonTarget = urlPath === "/" ? "/index" : urlPath;
337
- const jsonRes = await renderPage(new Request(`http://localhost${baseNoSlash}${jsonTarget}.pageContext.json`));
336
+ const jsonRes = await renderPage(new Request(`http://localhost${BASE_URL}${jsonTarget}.pageContext.json`));
338
337
  if (jsonRes?.ok) {
339
338
  const jsonOutPath = path.join(clientDir, `${jsonTarget}.pageContext.json`);
340
339
  fs.mkdirSync(path.dirname(jsonOutPath), { recursive: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike-lite",
3
- "version": "1.15.7",
3
+ "version": "1.15.9",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -60,6 +60,10 @@
60
60
  "types": "./dist/__internal/shared.d.mts",
61
61
  "import": "./dist/__internal/shared.mjs"
62
62
  },
63
+ "./__internal/client": {
64
+ "types": "./dist/__internal/client.d.mts",
65
+ "import": "./dist/__internal/client.mjs"
66
+ },
63
67
  "./__internal/server": {
64
68
  "types": "./dist/__internal/server.d.mts",
65
69
  "import": "./dist/__internal/server.mjs"
@@ -74,7 +78,7 @@
74
78
  },
75
79
  "devDependencies": {
76
80
  "@types/node": "^26.1.1",
77
- "tsdown": "^0.22.8",
81
+ "tsdown": "^0.22.9",
78
82
  "vite": "^8.1.5"
79
83
  },
80
84
  "peerDependencies": {
@@ -1,44 +0,0 @@
1
- //#region src/__internal/shared/matchRoute.ts
2
- const regexCache = /* @__PURE__ */ new Map();
3
- function escapeRegex(str) {
4
- return str.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
5
- }
6
- function matchRoute(urlPathname, routes) {
7
- for (const route of routes) {
8
- if (!route.path.includes(":")) {
9
- if (route.path === urlPathname || route.path + "/" === urlPathname) return {
10
- route,
11
- routeParams: {}
12
- };
13
- continue;
14
- }
15
- let compiled = regexCache.get(route.path);
16
- if (!compiled) {
17
- const paramNames = [];
18
- const regexPath = route.path.split("/").map((segment) => {
19
- if (segment.startsWith(":")) {
20
- paramNames.push(segment.slice(1));
21
- return "([^/]+)";
22
- }
23
- return escapeRegex(segment);
24
- }).join("/");
25
- compiled = {
26
- regex: new RegExp(`^${regexPath}/?$`),
27
- paramNames
28
- };
29
- regexCache.set(route.path, compiled);
30
- }
31
- const match = urlPathname.match(compiled.regex);
32
- if (match) {
33
- const routeParams = {};
34
- for (let i = 0; i < compiled.paramNames.length; i++) routeParams[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);
35
- return {
36
- route,
37
- routeParams
38
- };
39
- }
40
- }
41
- return null;
42
- }
43
- //#endregion
44
- export { matchRoute as t };
@@ -1,20 +0,0 @@
1
- //#region src/server/store.ts
2
- const STORE_KEY = "_vike_lite";
3
- if (!Object.hasOwn(globalThis, STORE_KEY)) globalThis[STORE_KEY] = {
4
- routes: [],
5
- errorRoute: null,
6
- config: null,
7
- manifest: null
8
- };
9
- const store = new Proxy({}, {
10
- get: (_, prop) => globalThis[STORE_KEY][prop],
11
- set: (_, prop, value) => {
12
- globalThis[STORE_KEY][prop] = value;
13
- return true;
14
- }
15
- });
16
- function setVikeState(newState) {
17
- Object.assign(globalThis[STORE_KEY], newState);
18
- }
19
- //#endregion
20
- export { store as n, setVikeState as t };