Skip to content

Commit

Permalink
Update for current status / SvelteKit
Browse files Browse the repository at this point in the history
  • Loading branch information
benmccann committed Jan 24, 2021
1 parent cfd7670 commit e2277b1
Showing 1 changed file with 61 additions and 55 deletions.
116 changes: 61 additions & 55 deletions text/0000-sapper-routing.md → text/0000-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
- RFC PR: (leave this empty)
- Svelte Issue: (leave this empty)

# Refactoring out Sapper's Routing
# Refactoring out SvelteKit's Routing

## Summary

Split Sapper's routing functionality into a standalone library and make it possible to use Sapper's routing outside of Sapper.
Split SvelteKit's routing functionality into a standalone library and make it possible to use SvelteKit's routing outside of SvelteKit.

## Motivation

Benefits include:

* Making it possible to use Sapper's routing outside of Sapper. The routing component should be able to be used in a client-side only application
* Making Sapper's routing more configurable. E.g. the user may wish to set a custom header on a certain route. We could expose the router component in the application and allow the user to set configuration on a per-route basis along the lines of `router.header('/[list]/[page]', {'Cache-Control': max-age=600'})`
* Making it possible to use SvelteKit's routing outside of SvelteKit. The routing component should be able to be used in a client-side only application
* Making SvelteKit's routing more configurable. E.g. the user may wish to set a custom header on a certain route. We could expose the router component in the application and allow the user to set configuration on a per-route basis along the lines of `router.header('/[list]/[page]', {'Cache-Control': max-age=600'})`
* Other requests users have for configuring the router include [routes aliases](https://github.com/sveltejs/sapper/issues/1450) and [configuring trailing slashes](https://github.com/sveltejs/sapper/issues/519), which we could expose APIs for as well
* Improved testability. Right now to test routing functionality you need a sample application and all tests are integration tests
* I believe it would become possible to make it such that Sapper's routing can be used with or without generating it from the file system though this is perhaps not a primary goal.
* Finally, Sapper's routing and Routify are quite similar. It may be possible to combine these two systems if everyone involved were open to such a possibility. I think it'd be good for the Svelte community to have a single solution because it means that solution would get more developer support than two individual solutions. Right now [there are many Svelte routing solutions](https://twitter.com/lihautan/status/1315482668440580096?s=19).
* I believe it would become possible to make it such that SvelteKit's routing can be used with or without generating it from the file system though this is perhaps not a primary goal.
* Finally, SvelteKit's routing and Routify are quite similar. It may be possible to combine these two systems if everyone involved were open to such a possibility. I think it'd be good for the Svelte community to have a single solution because it means that solution would get more developer support than two individual solutions. Right now [there are many Svelte routing solutions](https://twitter.com/lihautan/status/1315482668440580096?s=19).

## Detailed design

Expand All @@ -29,78 +29,91 @@ This could be split up into multiple PRs that are smaller and easier to review.

Remove need to specify CSS files in routing components.

Update: this has been completed in [#1508](https://github.com/sveltejs/sapper/pull/1508)
Update: this was completed in [#1508](https://github.com/sveltejs/sapper/pull/1508).


#### Step 2

Put all routing information in a single routing component. Historically it has been split between `start` and `app`.
Put all routing information in a single routing component. Historically, in Sapper, it has been split between `start` and `app`.

Update: this has been largely completed in [#1434](https://github.com/sveltejs/sapper/pull/1434). We can probably still clean up the prefetching code, etc.
Update: this has basically been completed with the router now living `packages/kit/runtime/internal/router`


#### Step 3

Add an API to register routes and make the generated code call the router rather than the router calling the generated code.
Parse routes at runtime to simplify API.

Right now, the generated `manifest-client.mjs` contains something like:
Right now, the generated `manifest.js` contains something like:

```
export const components = [
{
js: () => import("../../../routes/index.svelte")
},
{
js: () => import("../../../routes/[list]/[page].svelte")
}
const components = [
() => import("/_app/routes/index.svelte.js"),
() => import("/_app/routes/about.svelte.js"),
() => import("/_app/routes/item/[id].svelte.js"),
() => import("/_app/routes/user/[name].svelte.js")
];
export const routes = (d => [
const d = decodeURIComponent;
const empty = () => ({});
export const pages = [
{
// index.svelte
pattern: /^\/$/,
parts: [
{ i: 0 }
]
params: empty,
parts: [components[0]]
},
{
// about.svelte
pattern: /^\/about\/?$/,
params: empty,
parts: [components[1]]
},
{
// [list]/[page].svelte
pattern: /^\/([^/]+?)\/([^/]+?)\/?$/,
parts: [
null,
{ i: 1, params: match => ({ list: d(match[1]), page: d(match[2]) }) }
]
// item/[id].svelte
pattern: /^\/item\/([^/]+?)\/?$/,
params: (m) => ({ id: d(m[1])}),
parts: [components[2]]
},
{
// user/[name].svelte
pattern: /^\/user\/([^/]+?)\/?$/,
params: (m) => ({ name: d(m[1])}),
parts: [components[3]]
}
])(decodeURIComponent);
];
```


It would be nice to invert this such that the generated code calls the router instead of the router importing the generated code:
This API is a bit complex. However, it could be greatly simplified by making the route parsing be part of the router runtime instead of happening at compile time:

```
import router from 'router';
router.register({
route: /^\/$/,
component: () => import("../../../routes/index.svelte")
});
router.register({
route: /^\/([^/]+?)\/([^/]+?)\/?$/,
params: match => ({ list: d(match[1]), page: d(match[2]) }),
component: () => import("../../../routes/[list]/[page].svelte")
const pages = {
'/': () => import("../../../routes/index.svelte"
'/[list]/[page]': () => import("../../../routes/[list]/[page].svelte"
}
const router = new Router({
base: paths.base,
host,
pages,
ignore
});
```

This API is a bit complex. However, it could be greatly simplified by making the route parsing be part of the router runtime instead of happening at compile time:
The `pattern` is needed on the server-side too, so we will still have to include it in the manifest.

```
import router from 'router';
#### Step 4

router.register('/', () => import("../../../routes/index.svelte"));
router.register('/[list]/[page]', () => import("../../../routes/[list]/[page].svelte"));
```
Refactor out routes generation into separate plugin. Publish components separately.

#### Step 4
Review the API and make sure we like it. There's probably some minor cleanup to do before exposing the routing API more broadly

We could potentially have a library for the core routing functionality. And then a second for the file-system-based routes generator.

#### Step 5 - Optional

Unify the client and server routing APIs.

Expand All @@ -113,13 +126,6 @@ The server manifest also differs in a number of unnecessary ways:

We can remove the unnecessary differences. We will still need different client-side and server-side router instantiations registering their respective components, but they can utilize the same `router.register` API. On the client-side we can call `router.navigate`. On the server-side, we can just ask the router to return the registered component for a given route and let `get_page_handler` continue to handle it as it does today.

#### Step 5

Refactor out routes generation into separate plugin. Publish components separately.

Review the API and make sure we like it. There's probably some minor cleanup to do before exposing the routing API more broadly

We could potentially have a library for the core routing functionality. And then a second for the file-system-based routes generator.

## How we teach this

Expand Down

0 comments on commit e2277b1

Please sign in to comment.