Skip to content

Commit eb0d8c3

Browse files
committed
CR fixes
1 parent 5418fcb commit eb0d8c3

File tree

12 files changed

+118
-101
lines changed

12 files changed

+118
-101
lines changed

.changeset/dirty-dolls-heal.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
'@builder.io/qwik-city': minor
33
---
44

5-
FEAT: Support rewrite feature. should work like redirect, but without modifying the address bar url
5+
FEAT: Added rewrite() to the RequestEvent object. It works like redirect but does not change the URL,
6+
think of it as an internal redirect.
67

78
Example usage:
8-
```
9+
```ts
910
export const onRequest: RequestHandler = async ({ url, rewrite }) => {
1011
if (url.pathname.includes("/articles/the-best-article-in-the-world")) {
1112
const artistId = db.getArticleByName("the-best-article-in-the-world");

packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.mdx

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -929,29 +929,6 @@ See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control and
929929
</td></tr>
930930
<tr><td>
931931
932-
[canonicalUrl](#)
933-
934-
</td><td>
935-
936-
`readonly`
937-
938-
</td><td>
939-
940-
URL
941-
942-
</td><td>
943-
944-
HTTP request Canonical URL.
945-
946-
This property was introduced to support the rewrite feature.
947-
948-
If rewrite is called, the canonicalUrl will remain as the original url, and the url property will be changed to the rewritten url.
949-
950-
If rewrite is never called as part of the request, the url property and the canonicalUrl are considered equal.
951-
952-
</td></tr>
953-
<tr><td>
954-
955932
[clientConn](#)
956933
957934
</td><td>
@@ -1043,6 +1020,29 @@ https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
10431020
</td></tr>
10441021
<tr><td>
10451022
1023+
[originalUrl](#)
1024+
1025+
</td><td>
1026+
1027+
`readonly`
1028+
1029+
</td><td>
1030+
1031+
URL
1032+
1033+
</td><td>
1034+
1035+
HTTP request Canonical URL.
1036+
1037+
This property was introduced to support the rewrite feature.
1038+
1039+
If rewrite is called, the url property will be changed to the rewritten url. while originalUrl will stay the same(e.g the url inserted to the address bar).
1040+
1041+
If rewrite is never called as part of the request, the url property and the originalUrl are equal.
1042+
1043+
</td></tr>
1044+
<tr><td>
1045+
10461046
[params](#)
10471047
10481048
</td><td>
@@ -1343,15 +1343,13 @@ https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
13431343
13441344
</td><td>
13451345
1346-
(url: string \| URL) =&gt; [RewriteMessage](#rewritemessage)
1346+
(pathname: string) =&gt; [RewriteMessage](#rewritemessage)
13471347
13481348
</td><td>
13491349
1350-
URL to rewrite to. When called, the flow will reset to display the given url route.
1351-
1352-
URL will remain unchanged in the browser history.
1350+
When called, qwik-city will execute the path's matching route flow.
13531351
1354-
Note that if the url is a string without a protocol, the rewritten url will inherit the search params from the canonical url.
1352+
The url in the browser will remain unchanged.
13551353
13561354
</td></tr>
13571355
<tr><td>

packages/qwik-city/src/middleware/request-handler/middleware.request-handler.api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@ export interface RequestEventBase<PLATFORM = QwikCityPlatform> {
107107
readonly basePathname: string;
108108
// Warning: (ae-forgotten-export) The symbol "CacheControlTarget" needs to be exported by the entry point index.d.ts
109109
readonly cacheControl: (cacheControl: CacheControl, target?: CacheControlTarget) => void;
110-
readonly canonicalUrl: URL;
111110
readonly clientConn: ClientConn;
112111
readonly cookie: Cookie;
113112
readonly env: EnvGetter;
114113
readonly headers: Headers;
115114
readonly method: string;
115+
readonly originalUrl: URL;
116116
readonly params: Readonly<Record<string, string>>;
117117
readonly parseBody: () => Promise<unknown>;
118118
readonly pathname: string;
@@ -135,7 +135,7 @@ export interface RequestEventCommon<PLATFORM = QwikCityPlatform> extends Request
135135
readonly locale: (local?: string) => string;
136136
// Warning: (ae-forgotten-export) The symbol "RedirectCode" needs to be exported by the entry point index.d.ts
137137
readonly redirect: (statusCode: RedirectCode, url: string) => RedirectMessage;
138-
readonly rewrite: (url: string | URL) => RewriteMessage;
138+
readonly rewrite: (pathname: string) => RewriteMessage;
139139
// Warning: (ae-forgotten-export) The symbol "SendMethod" needs to be exported by the entry point index.d.ts
140140
readonly send: SendMethod;
141141
// Warning: (ae-forgotten-export) The symbol "StatusCodes" needs to be exported by the entry point index.d.ts

packages/qwik-city/src/middleware/request-handler/request-event.ts

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,16 @@ export function createRequestEvent(
8383
}
8484
};
8585

86-
const replay = (
86+
const resetRoute = (
8787
_loadedRoute: LoadedRoute | null,
8888
_requestHandlers: RequestHandler<any>[],
89-
_url = url,
90-
_routeModuleIndex = -1
89+
_url = url
9190
) => {
9291
loadedRoute = _loadedRoute;
9392
requestHandlers = _requestHandlers;
9493
url.pathname = _url.pathname;
9594
url.search = _url.search;
96-
routeModuleIndex = _routeModuleIndex;
95+
routeModuleIndex = -1;
9796
};
9897

9998
const check = () => {
@@ -156,7 +155,7 @@ export function createRequestEvent(
156155
env,
157156
method: request.method,
158157
signal: request.signal,
159-
canonicalUrl: new URL(url),
158+
originalUrl: new URL(url),
160159
get params() {
161160
return loadedRoute?.[1] ?? {};
162161
},
@@ -183,7 +182,7 @@ export function createRequestEvent(
183182

184183
next,
185184

186-
replay,
185+
resetRoute,
187186

188187
exit,
189188

@@ -245,34 +244,22 @@ export function createRequestEvent(
245244
return new RedirectMessage();
246245
},
247246

248-
rewrite: (_rewriteUrl: string | URL) => {
247+
rewrite: (pathname: string) => {
249248
check();
250-
let rewriteUrl: URL;
251-
if (typeof _rewriteUrl === 'string') {
252-
rewriteUrl = new URL(_rewriteUrl, _rewriteUrl.startsWith('http') ? undefined : url);
253-
} else {
254-
rewriteUrl = _rewriteUrl;
249+
if (pathname.startsWith('http')) {
250+
throw new Error('Rewrite does not support absolute urls');
255251
}
256252

253+
const rewriteUrl = new URL(url);
254+
rewriteUrl.pathname = pathname;
255+
257256
// Fix consecutive slashes - e.g //path//to//page -> /path/to/page
258257
const fixedPathname = rewriteUrl.pathname.replace(/(^|[^:])\/{2,}/g, '$1/');
259258
if (rewriteUrl.pathname !== fixedPathname) {
260259
console.warn(`Rewrite URL ${rewriteUrl.pathname} is invalid, fixing to ${fixedPathname}`);
261260
rewriteUrl.pathname = fixedPathname;
262261
}
263262

264-
// Assume that if Devs passed a string without a protocol, they want to keep the current search
265-
const keepCurrentSearchParams =
266-
typeof _rewriteUrl === 'string' && !_rewriteUrl.startsWith('http');
267-
if (keepCurrentSearchParams) {
268-
url.searchParams.forEach((value, key) => {
269-
// rewriteUrl values should take precedence over current url values
270-
if (!rewriteUrl.searchParams.has(key)) {
271-
rewriteUrl.searchParams.set(key, value);
272-
}
273-
});
274-
}
275-
276263
headers.set('Rewrite-Location', rewriteUrl.toString());
277264
return new RewriteMessage();
278265
},
@@ -355,18 +342,16 @@ export interface RequestEventInternal extends RequestEvent, RequestEventLoader {
355342
isDirty(): boolean;
356343

357344
/**
358-
* Replay the request handlers chain with new loadedRoute and requestHandlers.
345+
* Reset the request event to the given route data.
359346
*
360347
* @param loadedRoute - The new loaded route.
361348
* @param requestHandlers - The new request handlers.
362-
* @param url - The new URL (defaults to the current URL).
363-
* @param routeModuleIndex - The new route module index (defaults to -1, full replay).
349+
* @param url - The new URL of the route.
364350
*/
365-
replay(
351+
resetRoute(
366352
loadedRoute: LoadedRoute | null,
367353
requestHandlers: RequestHandler<any>[],
368-
url?: URL,
369-
routeModuleIndex?: number
354+
url: URL
370355
): void;
371356
}
372357

packages/qwik-city/src/middleware/request-handler/resolve-request-handlers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,8 @@ async function pureServerFunction(ev: RequestEvent) {
360360

361361
function fixTrailingSlash(ev: RequestEvent) {
362362
const trailingSlash = getRequestTrailingSlash(ev);
363-
const { basePathname, canonicalUrl, sharedMap } = ev;
364-
const { pathname, search } = canonicalUrl;
363+
const { basePathname, originalUrl, sharedMap } = ev;
364+
const { pathname, search } = originalUrl;
365365
const isQData = sharedMap.has(IsQData);
366366
if (!isQData && pathname !== basePathname && !pathname.endsWith('.html')) {
367367
// only check for slash redirect on pages

packages/qwik-city/src/middleware/request-handler/response-page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
} from './request-event';
1111

1212
export function getQwikCityServerData(requestEv: RequestEvent) {
13-
const { params, request, status, locale, canonicalUrl } = requestEv;
13+
const { params, request, status, locale, originalUrl } = requestEv;
1414
const requestHeaders: Record<string, string> = {};
1515
request.headers.forEach((value, key) => (requestHeaders[key] = value));
1616

@@ -19,7 +19,7 @@ export function getQwikCityServerData(requestEv: RequestEvent) {
1919
const routeName = requestEv.sharedMap.get(RequestRouteName) as string;
2020
const nonce = requestEv.sharedMap.get(RequestEvSharedNonce);
2121
const headers = requestEv.request.headers;
22-
const reconstructedUrl = new URL(canonicalUrl.pathname + canonicalUrl.search, canonicalUrl);
22+
const reconstructedUrl = new URL(originalUrl.pathname + originalUrl.search, originalUrl);
2323
const host = headers.get('X-Forwarded-Host')!;
2424
const protocol = headers.get('X-Forwarded-Proto')!;
2525
if (host) {

packages/qwik-city/src/middleware/request-handler/types.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,13 @@ export interface RequestEventCommon<PLATFORM = QwikCityPlatform>
203203
readonly redirect: (statusCode: RedirectCode, url: string) => RedirectMessage;
204204

205205
/**
206-
* URL to rewrite to. When called, the flow will reset to display the given url route.
206+
* When called, qwik-city will execute the path's matching route flow.
207207
*
208-
* URL will remain unchanged in the browser history.
208+
* The url in the browser will remain unchanged.
209209
*
210-
* Note that if the url is a string without a protocol, the rewritten url will inherit the search
211-
* params from the canonical url.
212-
*
213-
* @param url - The url to rewrite to.
210+
* @param pathname - The pathname to rewrite to.
214211
*/
215-
readonly rewrite: (url: string | URL) => RewriteMessage;
212+
readonly rewrite: (pathname: string) => RewriteMessage;
216213

217214
/**
218215
* When called, the response will immediately end with the given status code. This could be useful
@@ -305,13 +302,13 @@ export interface RequestEventBase<PLATFORM = QwikCityPlatform> {
305302
*
306303
* This property was introduced to support the rewrite feature.
307304
*
308-
* If rewrite is called, the canonicalUrl will remain as the original url, and the url property
309-
* will be changed to the rewritten url.
305+
* If rewrite is called, the url property will be changed to the rewritten url. while originalUrl
306+
* will stay the same(e.g the url inserted to the address bar).
310307
*
311-
* If rewrite is never called as part of the request, the url property and the canonicalUrl are
312-
* considered equal.
308+
* If rewrite is never called as part of the request, the url property and the originalUrl are
309+
* equal.
313310
*/
314-
readonly canonicalUrl: URL;
311+
readonly originalUrl: URL;
315312

316313
/** The base pathname of the request, which can be configured at build time. Defaults to `/`. */
317314
readonly basePathname: string;

packages/qwik-city/src/middleware/request-handler/user-response.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ async function runNext(
130130
rewriteAttempt += 1;
131131
const url = new URL(requestEv.headers.get('Rewrite-Location')!);
132132
const { loadedRoute, requestHandlers } = await rebuildRouteInfo(url);
133-
requestEv.replay(loadedRoute, requestHandlers, url);
133+
requestEv.resetRoute(loadedRoute, requestHandlers, url);
134134
runResult = await _runNext();
135135
}
136136

starters/apps/qwikcity-test/src/routes/(common)/products/[id]/index.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,33 @@ export default component$(() => {
7070
</li>
7171
<li>
7272
<Link
73-
href="/qwikcity-test/products/shirt-rewrite-plain_string/"
74-
data-test-link="products-shirt-rewrite-plain_string"
73+
href="/qwikcity-test/products/shirt-rewrite/"
74+
data-test-link="products-shirt-rewrite"
7575
>
7676
T-Shirt (Rewrite to /products/tshirt)
7777
</Link>
7878
</li>
7979
<li>
8080
<Link
81-
href="/qwikcity-test/products/shirt-rewrite-url_object/"
82-
data-test-link="products-shirt-rewrite-url_object"
81+
href="/qwikcity-test/products/shirt-rewrite/?search=true"
82+
data-test-link="products-shirt-rewrite-with-search"
8383
>
8484
T-Shirt (Rewrite to /products/tshirt)
8585
</Link>
8686
</li>
8787
<li>
8888
<Link
89-
href="/qwikcity-test/products/shirt-rewrite-plain_string"
90-
data-test-link="products-shirt-rewrite-plain_string_no_trailing_slash"
89+
href="/qwikcity-test/products/shirt-rewrite"
90+
data-test-link="products-shirt-rewrite-no-trailing-slash"
91+
>
92+
T-Shirt (Rewrite to /products/tshirt) Also trailing slash should be
93+
added.
94+
</Link>
95+
</li>
96+
<li>
97+
<Link
98+
href="/qwikcity-test/products/shirt-rewrite-absolute-url/"
99+
data-test-link="products-shirt-rewrite-absolute-url"
91100
>
92101
T-Shirt (Rewrite to /products/tshirt) Also trailing slash should be
93102
added.
@@ -163,13 +172,13 @@ export const useProductLoader = routeLoader$(
163172
throw redirect(301, "/qwikcity-test/products/tshirt/");
164173
}
165174

166-
if (id === "shirt-rewrite-plain_string") {
175+
if (id === "shirt-rewrite") {
167176
throw rewrite("/qwikcity-test/products/tshirt/");
168177
}
169178

170-
if (id === "shirt-rewrite-url_object") {
171-
// Rewrite with a URL object.
172-
throw rewrite(new URL("/qwikcity-test/products/tshirt/", url.origin));
179+
// Should throw an error
180+
if (id === "shirt-rewrite-absolute-url") {
181+
throw rewrite(`${url.origin}/qwikcity-test/products/tshirt/`);
173182
}
174183

175184
if (id === "error") {

0 commit comments

Comments
 (0)