sveltejs/sapper

Produce valid URLs for client assets pertaining to routes with dynamic params

Opened this issue · 5 comments

Network requests for assets such as /client/[slug].c6e3f42d.js should be URI-encoded since square brackets are reserved characters under RFC 3986. AWS API Gateway, for example, does not allow requests for such URLs, hence where an AWS stack is used to proxy requests Sapper is thus not supported.

Propose that encodeURIComponent() wraps the href of client assets.

(I've been able to locate what I believe would be the relevant points in code to correct URLs to stylesheets, but JS assets appear to be a lot trickier to track down.)

--- a/runtime/src/app/app.ts
+++ b/runtime/src/app/app.ts
@@ -359,7 +359,7 @@ export async function hydrate_target(target: Target): Promise<{
 }

 function load_css(chunk: string) {
-       const href = `client/${chunk}`;
+       const href = `client/${encodeURIComponent(chunk)}`;
        if (document.querySelector(`link[href="${href}"]`)) return;

        return new Promise((fulfil, reject) => {
diff --git a/runtime/src/server/middleware/get_page_handler.ts b/runtime/src/server/middleware/get_page_handler.ts
index c7c88e4..7708296 100644
--- a/runtime/src/server/middleware/get_page_handler.ts
+++ b/runtime/src/server/middleware/get_page_handler.ts
@@ -308,7 +308,7 @@ export function get_page_handler(
                                });

                                styles = Array.from(css_chunks)
-                                       .map(href => `<link rel="stylesheet" href="client/${href}">`)
+                                       .map(href => `<link rel="stylesheet" href="client/${encodeURIComponent(href)}">`)
                                        .join('')
                        } else {
                                styles = (css && css.code ? `<style>${css.code}</style>` : '');

Looked up some documentation. It appears that square brackets aren't included in the supported characters list:

https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html

Path segments can only contain alphanumeric characters, hyphens, periods, commas, and curly braces. Path parameters must be separate path segments. For example, "resource/{path_parameter_name}" is valid; "resource{path_parameter_name}" is not.
Model names can only contain alphanumeric characters.

Which is confusing, because the following is currently working for me on Lambda/Gateway in production: /cm/[profile]/[modal]/index.svelte

I'm using Up for deploy, so maybe something in there is auto-magically fixing it? I haven't taken the time to explore all the possibilities, but it appears square brackets are a no-go in general and we should either consider encoding as mentioned above, or perhaps switch to curly braces, which would be a breaking change. (I suppose we could support both...🤷‍♂️)

As discussed in #819, a workaround is to define dynamic routes with subfolders and utilise an implicit index file.

e.g. routes/[slug].svelte becomes routes/[slug]/index.svelte.

This circumvents the problem because Sapper will bundle a client asset named something akin to client/index.c6e3f42d.js (i.e. without square brackets).

This may hence beg the question as to why a route file such as blogs/[slug].svelte isn't [also] just bundled by contenthash, e.g. client/slug.0820cdd2.js instead of client/[slug].0820cdd2.js.

^ Yeah this last bit could solve the problem apparently.

It looks like sapper does not create filenames with [] if the route is an index.svelte file in the [slug] directory. src/routes/[slug]/index.svelte

It would be good to fix this issue, but this is a workaround for now.