Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d8cab78
fix: ssg build windows error
Varixo Oct 18, 2025
e696be1
chore: reenable windows e2e tests on CI
Varixo Oct 18, 2025
0ceb396
chore: reenable react e2e tests on windows
Varixo Oct 18, 2025
cc6ae9d
chore(router): better error handling for SSG
wmertens Oct 22, 2025
f1e501a
fix: ssg on windows
Varixo Oct 23, 2025
a9b5678
chore: increment timeout for adapters e2e
Varixo Oct 23, 2025
8b3c7d3
fix: worker exit code, force terminate only after timeout
Varixo Oct 25, 2025
47a3b9f
chore: fixup
Varixo Oct 25, 2025
6e866a0
Merge pull request #8072 from QwikDev/fix-ssg-windows
wmertens Oct 25, 2025
5ac92f4
Revert "fix: ssg on windows"
Varixo Oct 25, 2025
cf894dc
Merge pull request #8088 from QwikDev/revert-8072-fix-ssg-windows
wmertens Oct 25, 2025
04907a9
chore: trigger docs build
Varixo Oct 25, 2025
6cc1d22
Merge pull request #8089 from QwikDev/trigger-docs-build
wmertens Oct 25, 2025
9a44958
fix: SPA routing is broken unless origin matches value in in vite.config
termermc Oct 28, 2025
b1b63f1
chore: add changeset
termermc Oct 28, 2025
f263433
Merge pull request #8097 from termermc/fix-spa-routing
wmertens Oct 29, 2025
2a587f8
Merge remote-tracking branch 'origin/main' into v2-merge-main
wmertens Oct 29, 2025
e0f764c
fix(router): properly init state browser-side
wmertens Oct 30, 2025
2807b3b
fix(docs): make Root non-reactive
wmertens Oct 31, 2025
c052a4c
refactor(router): make spa-init more compressible
wmertens Oct 31, 2025
e3cbdd7
fix(serdes): inflate store target, not store
wmertens Oct 31, 2025
3eb3ca5
fix(docs): move reactive head to own component
wmertens Oct 31, 2025
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
44 changes: 12 additions & 32 deletions packages/docs/src/components/router-head/router-head.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { component$ } from '@qwik.dev/core';
import { useDocumentHead, useLocation } from '@qwik.dev/router';
import { component$, untrack } from '@qwik.dev/core';
import { DocumentHeadTags, useDocumentHead, useLocation } from '@qwik.dev/router';
import { Social } from './social';
import { InjectThemeScript } from '../theme-toggle';
import { Vendor } from './vendor';

/** The dynamic head content */
export const RouterHead = component$(() => {
const { url } = useLocation();
const head = useDocumentHead();
const { url } = useLocation();
const href = head.frontmatter?.canonical || untrack(() => url.href);

const title = head.title
? `${head.title} 📚 Qwik Documentation`
: `Qwik - Framework reimagined for the edge`;
Expand Down Expand Up @@ -47,45 +49,23 @@ export const RouterHead = component$(() => {
}
},
};

return (
<>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={head.frontmatter?.canonical || url.href} />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-title" content="Qwik" />
<meta name="application-name" content="Qwik" />
<meta name="apple-mobile-web-app-title" content="Qwik" />
<meta name="theme-color" content="#006ce9" />
<meta name="color-scheme" content="dark light" />

<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="icon" href="/favicons/favicon.svg" type="image/svg+xml" />
<link rel="canonical" href={href} />

{import.meta.env.PROD && (
<>
<Social title={title} description={description} href={url.href} ogImage={OGImage.URL} />
<Social title={title} description={description} href={href} ogImage={OGImage.URL} />
<Vendor />
</>
)}

{head.meta
<DocumentHeadTags
title={title}
// Skip description because that was already added at the top
.filter((s) => s.name !== 'description')
.map((m, key) => (
<meta key={key} {...m} />
))}

{head.links.map((l, key) => (
<link key={key} {...l} />
))}

{head.styles.map((s, key) => (
<style key={key} {...s.props} dangerouslySetInnerHTML={s.style} />
))}

<InjectThemeScript />
meta={head.meta.filter((s) => s.name !== 'description')}
/>
</>
);
});
6 changes: 1 addition & 5 deletions packages/docs/src/repl/ui/repl-commands.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { createPlaygroundShareUrl } from './repl-share-url';
import type { ReplAppInput } from '../types';

export const ReplCommands = ({
input,
enableCopyToPlayground,
enableDownload,
}: ReplCommandProps) => {
export const ReplCommands = ({ input, enableCopyToPlayground }: ReplCommandProps) => {
return (
<div class="repl-commands">
{enableCopyToPlayground ? (
Expand Down
90 changes: 4 additions & 86 deletions packages/docs/src/root.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import { component$, useContextProvider, useStore } from '@qwik.dev/core';
import { Insights } from '@qwik.dev/core/insights';
import {
RouterOutlet,
ServiceWorkerRegister,
useDocumentHead,
useLocation,
useQwikRouter,
} from '@qwik.dev/router';
import RealMetricsOptimization from './components/real-metrics-optimization/real-metrics-optimization';
import { Social } from './components/router-head/social';
import { Vendor } from './components/router-head/vendor';
import { RouterOutlet, useQwikRouter } from '@qwik.dev/router';
import { RouterHead } from './components/router-head/router-head';
import { InjectThemeScript } from './components/theme-toggle';
import { BUILDER_PUBLIC_API_KEY } from './constants';
import { GlobalStore, type SiteStore } from './context';

import './global.css';

export const uwu = /*javascript*/ `
Expand Down Expand Up @@ -50,8 +42,6 @@ export const uwu = /*javascript*/ `

export default component$(() => {
useQwikRouter();
const head = useDocumentHead();
const { url } = useLocation();

const store = useStore<SiteStore>({
headerMenuOpen: false,
Expand All @@ -62,55 +52,11 @@ export default component$(() => {

useContextProvider(GlobalStore, store);

const title = head.title
? `${head.title} 📚 Qwik Documentation`
: `Qwik - Framework reimagined for the edge`;
const description =
head.meta.find((m) => m.name === 'description')?.content ||
`No hydration, auto lazy-loading, edge-optimized, and fun 🎉!`;

const OGImage = {
imageURL: '',
ogImgTitle: '',
ogImgSubTitle: '' as string | undefined,

get URL() {
//turn the title into array with [0] -> Title [1] -> subTitle
const arrayedTitle = title.split(' | ');
const ogImageUrl = new URL('https://opengraphqwik.vercel.app/api/og?level=1');

// biggerTitle
this.ogImgTitle = arrayedTitle[0];
//smallerTitle
this.ogImgSubTitle = arrayedTitle[1]
? arrayedTitle[1].replace(' 📚 Qwik Documentation', '')
: undefined;

//decide whether or not to show dynamic OGimage or use docs default social card
if (this.ogImgSubTitle == undefined || this.ogImgTitle == undefined) {
this.imageURL = new URL(`/logos/social-card.jpg`, url).href;

return this.imageURL;
} else {
ogImageUrl.searchParams.set('title', this.ogImgTitle);
ogImageUrl.searchParams.set('subtitle', this.ogImgSubTitle);
// ogImageUrl.searchParams.set('level', this.routeLevel.toString());

this.imageURL = ogImageUrl.toString();

return this.imageURL;
}
},
};

return (
<>
<head>
<meta charset="utf-8" />

<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={head.frontmatter?.canonical || url.href} />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="apple-mobile-web-app-title" content="Qwik" />
<meta name="application-name" content="Qwik" />
Expand All @@ -121,38 +67,11 @@ export default component$(() => {
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
<link rel="icon" href="/favicons/favicon.svg" type="image/svg+xml" />

{import.meta.env.PROD && (
<>
<Social title={title} description={description} href={url.href} ogImage={OGImage.URL} />
<Vendor />
</>
)}

{/* The below are tags that were collected from all the `head` exports in the current route. */}
{head.meta
// Skip description because that was already added at the top
.filter((s) => s.name !== 'description')
.map((m, key) => (
<meta key={key} {...m} />
))}

{head.links.map((l, key) => (
<link key={key} {...l} />
))}

{head.styles.map((s, key) => (
<style key={key} {...s.props} dangerouslySetInnerHTML={s.style} />
))}

{head.scripts.map((s, key) => (
<script key={key} {...s.props} dangerouslySetInnerHTML={s.script} />
))}
<RouterHead />

<InjectThemeScript />
<script dangerouslySetInnerHTML={uwu} />

<ServiceWorkerRegister />

<script dangerouslySetInnerHTML={`(${collectSymbols})()`} />
<Insights />
</head>
Expand All @@ -164,7 +83,6 @@ export default component$(() => {
>
{/* This renders the current route, including all Layout components. */}
<RouterOutlet />
<RealMetricsOptimization builderApiKey={BUILDER_PUBLIC_API_KEY} />
</body>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/routes/api/qwik-router/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@
}
],
"kind": "Variable",
"content": "This is a wrapper around the `useQwikRouter()` hook. We recommend using the hook instead of this component.\n\n\n```typescript\nQwikRouterProvider: import(\"@qwik.dev/core\").Component<QwikRouterProps>\n```",
"content": "This is a wrapper around the `useQwikRouter()` hook. We recommend using the hook instead of this component, unless you have a good reason to make your root component reactive.\n\n\n```typescript\nQwikRouterProvider: import(\"@qwik.dev/core\").Component<QwikRouterProps>\n```",
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik-router/src/runtime/src/qwik-router-component.tsx",
"mdFile": "router.qwikrouterprovider.md"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/routes/api/qwik-router/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1796,7 +1796,7 @@ Default: `true`

## QwikRouterProvider

This is a wrapper around the `useQwikRouter()` hook. We recommend using the hook instead of this component.
This is a wrapper around the `useQwikRouter()` hook. We recommend using the hook instead of this component, unless you have a good reason to make your root component reactive.

```typescript
QwikRouterProvider: import("@qwik.dev/core").Component<QwikRouterProps>;
Expand Down
19 changes: 17 additions & 2 deletions packages/docs/src/routes/docs/(qwikrouter)/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,26 @@ export default component$(() => {
});
```

> `useQwikRouter()` should only be called once, in the root of your application.
> `useQwikRouter()` should only be called once, in the root of your application. If your root component is reactive, you should move the reactive part into a child component, or you can use the `<QwikRouterProvider>` component instead.

## `<QwikRouterProvider>`

The `QwikRouterProvider` component is a wrapper around the `useQwikRouter()` hook. It does not render any DOM element, not even the matched route. We recommend using the hook instead of this component.
The `QwikRouterProvider` component is a wrapper around the `useQwikRouter()` hook. It does not render any DOM element, not even the matched route. We recommend using the hook instead of this component, except when your root component is reactive.

```tsx title="src/root.tsx"
import { QwikRouterProvider, RouterOutlet } from '@qwik.dev/router';

export default component$(() => (
<QwikRouterProvider>
<head>
{/* ... */}
</head>
<body>
<RouterOutlet />
</body>
</QwikRouterProvider>
));
```

## `<QwikRouterMockProvider>`

Expand Down
4 changes: 0 additions & 4 deletions packages/qwik-router/src/runtime/src/contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type {
RouteLocation,
RouteNavigate,
RoutePreventNavigate,
RouteStateInternal,
} from './types';

export const RouteStateContext =
Expand All @@ -25,8 +24,5 @@ export const RouteNavigateContext = /*#__PURE__*/ createContextId<RouteNavigate>

export const RouteActionContext = /*#__PURE__*/ createContextId<RouteAction>('qc-a');

export const RouteInternalContext =
/*#__PURE__*/ createContextId<Signal<RouteStateInternal>>('qc-ir');

export const RoutePreventNavigateContext =
/*#__PURE__*/ createContextId<RoutePreventNavigate>('qc-p');
Loading