sv-router 0.2.0 → 0.4.0
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.
- package/package.json +1 -1
- package/src/cli/index.js +5 -2
- package/src/create-router.svelte.js +28 -4
- package/src/gen/config.js +4 -2
- package/src/gen/generate-router-code.js +6 -4
- package/src/gen/write-router-code.js +1 -1
- package/src/helpers/match-route.js +2 -0
- package/src/index.d.ts +2 -1
- package/src/vite-plugin/index.d.ts +9 -3
- package/src/vite-plugin/plugin.js +3 -2
package/package.json
CHANGED
package/src/cli/index.js
CHANGED
|
@@ -18,10 +18,13 @@ function arg(option) {
|
|
|
18
18
|
return args[pathArgIndex];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
21
|
+
const allLazyArg = arg('allLazy');
|
|
22
|
+
if (allLazyArg) genConfig.allLazy = true;
|
|
23
23
|
|
|
24
24
|
const jsArg = arg('js');
|
|
25
25
|
if (jsArg) genConfig.routesInJs = true;
|
|
26
26
|
|
|
27
|
+
const pathArg = arg('path');
|
|
28
|
+
if (pathArg) genConfig.routesPath = pathArg;
|
|
29
|
+
|
|
27
30
|
writeRouterCode();
|
|
@@ -16,6 +16,9 @@ export let params = $state({ value: {} });
|
|
|
16
16
|
|
|
17
17
|
export let location = $state(updatedLocation());
|
|
18
18
|
|
|
19
|
+
let navigationIndex = 0;
|
|
20
|
+
let pendingNavigationIndex = 0;
|
|
21
|
+
|
|
19
22
|
/** @type {{ name?: string }} */
|
|
20
23
|
export const base = {
|
|
21
24
|
name: undefined,
|
|
@@ -46,7 +49,7 @@ export function createRouter(r) {
|
|
|
46
49
|
return params.value;
|
|
47
50
|
},
|
|
48
51
|
get pathname() {
|
|
49
|
-
return location.pathname;
|
|
52
|
+
return /** @type {import('./index.d.ts').Path<T>} */ (location.pathname);
|
|
50
53
|
},
|
|
51
54
|
get search() {
|
|
52
55
|
return location.search;
|
|
@@ -90,6 +93,10 @@ export async function onNavigate(path, options = {}) {
|
|
|
90
93
|
if (!routes) {
|
|
91
94
|
throw new Error('Router not initialized: `createRouter` was not called.');
|
|
92
95
|
}
|
|
96
|
+
|
|
97
|
+
navigationIndex++;
|
|
98
|
+
const currentNavigationIndex = navigationIndex;
|
|
99
|
+
|
|
93
100
|
let matchPath = path || globalThis.location.pathname;
|
|
94
101
|
if (base.name && matchPath.startsWith(base.name)) {
|
|
95
102
|
matchPath = matchPath.slice(base.name.length) || '/';
|
|
@@ -98,14 +105,22 @@ export async function onNavigate(path, options = {}) {
|
|
|
98
105
|
|
|
99
106
|
for (const { beforeLoad } of hooks) {
|
|
100
107
|
try {
|
|
108
|
+
pendingNavigationIndex = currentNavigationIndex;
|
|
101
109
|
await beforeLoad?.();
|
|
102
110
|
} catch {
|
|
103
111
|
return;
|
|
104
112
|
}
|
|
105
113
|
}
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
const fromBeforeLoadHook = new Error().stack?.includes('beforeLoad');
|
|
116
|
+
|
|
117
|
+
const routeComponents = await resolveRouteComponents(match ? [...layouts, match] : layouts);
|
|
118
|
+
if (
|
|
119
|
+
navigationIndex !== currentNavigationIndex ||
|
|
120
|
+
(fromBeforeLoadHook && pendingNavigationIndex + 1 !== currentNavigationIndex)
|
|
121
|
+
) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
109
124
|
|
|
110
125
|
if (path) {
|
|
111
126
|
if (options.search) path += options.search;
|
|
@@ -115,6 +130,14 @@ export async function onNavigate(path, options = {}) {
|
|
|
115
130
|
globalThis.history[historyMethod](options.state || {}, '', to);
|
|
116
131
|
}
|
|
117
132
|
|
|
133
|
+
if (options.viewTransition && document.startViewTransition !== undefined) {
|
|
134
|
+
document.startViewTransition(() => {
|
|
135
|
+
componentTree.value = routeComponents;
|
|
136
|
+
});
|
|
137
|
+
} else {
|
|
138
|
+
componentTree.value = routeComponents;
|
|
139
|
+
}
|
|
140
|
+
params.value = newParams || {};
|
|
118
141
|
syncSearchParams();
|
|
119
142
|
Object.assign(location, updatedLocation());
|
|
120
143
|
|
|
@@ -139,13 +162,14 @@ export function onGlobalClick(event) {
|
|
|
139
162
|
if (url.origin !== currentOrigin) return;
|
|
140
163
|
|
|
141
164
|
event.preventDefault();
|
|
142
|
-
const { replace, state, scrollToTop } = anchor.dataset;
|
|
165
|
+
const { replace, state, scrollToTop, viewTransition } = anchor.dataset;
|
|
143
166
|
onNavigate(url.pathname, {
|
|
144
167
|
replace: replace === '' || replace === 'true',
|
|
145
168
|
search: url.search,
|
|
146
169
|
state,
|
|
147
170
|
hash: url.hash,
|
|
148
171
|
scrollToTop: scrollToTop === 'false' ? false : /** @type ScrollBehavior */ (scrollToTop),
|
|
172
|
+
viewTransition: viewTransition === '' || viewTransition === 'true',
|
|
149
173
|
});
|
|
150
174
|
}
|
|
151
175
|
|
package/src/gen/config.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @type {{
|
|
3
|
-
*
|
|
3
|
+
* allLazy: boolean;
|
|
4
4
|
* routesInJs: boolean;
|
|
5
|
+
* routesPath: string;
|
|
5
6
|
* readonly genCodeDirPath: string;
|
|
6
7
|
* readonly routerPath: string;
|
|
7
8
|
* readonly tsconfigPath: string;
|
|
@@ -9,8 +10,9 @@
|
|
|
9
10
|
* }}
|
|
10
11
|
*/
|
|
11
12
|
export const genConfig = {
|
|
12
|
-
|
|
13
|
+
allLazy: false,
|
|
13
14
|
routesInJs: false,
|
|
15
|
+
routesPath: 'src/routes',
|
|
14
16
|
genCodeDirPath: '.router',
|
|
15
17
|
get routerPath() {
|
|
16
18
|
return '.router/router.' + (this.routesInJs ? 'js' : 'ts');
|
|
@@ -17,16 +17,17 @@ const HOOKS_FILENAME_REGEX = /(?<=[/.]|^)(hooks)(\.svelte)?\.(js|ts)$/; // hooks
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @param {string} routesPath
|
|
20
|
+
* @param {{ allLazy?: boolean }} [options]
|
|
20
21
|
* @returns {string}
|
|
21
22
|
*/
|
|
22
|
-
export function generateRouterCode(routesPath) {
|
|
23
|
+
export function generateRouterCode(routesPath, options) {
|
|
23
24
|
const absoluteRoutesPath = path.join(process.cwd(), routesPath);
|
|
24
25
|
if (!fs.existsSync(absoluteRoutesPath)) {
|
|
25
26
|
throw new Error(`Routes directory not found at \`${routesPath}\``);
|
|
26
27
|
}
|
|
27
28
|
const fileTree = buildFileTree(absoluteRoutesPath);
|
|
28
29
|
const routeMap = createRouteMap(fileTree);
|
|
29
|
-
return createRouterCode(routeMap, path.posix.join('..', routesPath));
|
|
30
|
+
return createRouterCode(routeMap, path.posix.join('..', routesPath), options);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -119,9 +120,10 @@ function filePathToRoute(filename) {
|
|
|
119
120
|
/**
|
|
120
121
|
* @param {GeneratedRoutes} routes
|
|
121
122
|
* @param {string} routesPath
|
|
123
|
+
* @param {{ allLazy?: boolean }} [options]
|
|
122
124
|
* @returns {string}
|
|
123
125
|
*/
|
|
124
|
-
export function createRouterCode(routes, routesPath) {
|
|
126
|
+
export function createRouterCode(routes, routesPath, { allLazy = false } = {}) {
|
|
125
127
|
if (!routesPath.endsWith('/')) {
|
|
126
128
|
routesPath += '/';
|
|
127
129
|
}
|
|
@@ -135,7 +137,7 @@ export function createRouterCode(routes, routesPath) {
|
|
|
135
137
|
for (const [key, value] of Object.entries(routes)) {
|
|
136
138
|
if (typeof value === 'object') {
|
|
137
139
|
result[key] = handleImports(value, routesPath);
|
|
138
|
-
} else if (key === 'hooks' || !value.endsWith('.lazy.svelte')) {
|
|
140
|
+
} else if (key === 'hooks' || (!value.endsWith('.lazy.svelte') && !allLazy)) {
|
|
139
141
|
const variableName = pathToCorrectCasing(value);
|
|
140
142
|
importsMap.set(variableName, routesPath + value);
|
|
141
143
|
result[key] = variableName;
|
|
@@ -32,7 +32,7 @@ export function writeRouterCode() {
|
|
|
32
32
|
writeFileIfDifferent(genConfig.tsconfigPath, JSON.stringify(tsConfig, undefined, 2));
|
|
33
33
|
|
|
34
34
|
// Write `.router/router.ts` file
|
|
35
|
-
const routerCode = generateRouterCode(genConfig.routesPath);
|
|
35
|
+
const routerCode = generateRouterCode(genConfig.routesPath, { allLazy: genConfig.allLazy });
|
|
36
36
|
const written = writeFileIfDifferent(genConfig.routerPath, routerCode);
|
|
37
37
|
|
|
38
38
|
if (written) {
|
|
@@ -61,6 +61,8 @@ export function matchRoute(pathname, routes) {
|
|
|
61
61
|
}
|
|
62
62
|
if (breakFromLayouts) {
|
|
63
63
|
routePart = `(${routePart})`;
|
|
64
|
+
} else if ('layout' in routes && routes.layout) {
|
|
65
|
+
layouts.push(routes.layout);
|
|
64
66
|
}
|
|
65
67
|
const resolvedPath = /** @type {keyof Routes} */ (
|
|
66
68
|
(index ? '/' : '') + routeParts.join('/')
|
package/src/index.d.ts
CHANGED
|
@@ -134,7 +134,7 @@ export type RouterApi<T extends Routes> = {
|
|
|
134
134
|
*/
|
|
135
135
|
params: AllParams<T>;
|
|
136
136
|
/** The reactive pathname of the URL. */
|
|
137
|
-
pathname:
|
|
137
|
+
pathname: Path<T>;
|
|
138
138
|
/** The reactive query string part of the URL. */
|
|
139
139
|
search: string;
|
|
140
140
|
/** The reactive history state that can be passed to the `navigate` function. */
|
|
@@ -166,6 +166,7 @@ export type NavigateOptions =
|
|
|
166
166
|
state?: string;
|
|
167
167
|
hash?: string;
|
|
168
168
|
scrollToTop?: ScrollBehavior | false;
|
|
169
|
+
viewTransition?: boolean;
|
|
169
170
|
}
|
|
170
171
|
| undefined;
|
|
171
172
|
|
|
@@ -2,17 +2,23 @@ import type { Plugin } from 'vite';
|
|
|
2
2
|
|
|
3
3
|
export type RouterOptions = {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* If true, all routes will be lazy loaded by default.
|
|
6
6
|
*
|
|
7
|
-
* @default
|
|
7
|
+
* @default false
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
allLazy?: boolean;
|
|
10
10
|
/**
|
|
11
11
|
* If true, generates the routes in a .js file instead of a .ts file.
|
|
12
12
|
*
|
|
13
13
|
* @default false
|
|
14
14
|
*/
|
|
15
15
|
js?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The path to the routes folder.
|
|
18
|
+
*
|
|
19
|
+
* @default 'src/routes'
|
|
20
|
+
*/
|
|
21
|
+
path?: string;
|
|
16
22
|
};
|
|
17
23
|
|
|
18
24
|
export const router: (options?: RouterOptions) => Plugin;
|
|
@@ -7,8 +7,9 @@ import { writeRouterCode } from '../gen/write-router-code.js';
|
|
|
7
7
|
* @returns {import('vite').Plugin}
|
|
8
8
|
*/
|
|
9
9
|
export function router(options) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
genConfig.allLazy = options?.allLazy || false;
|
|
11
|
+
genConfig.routesInJs = options?.js || false;
|
|
12
|
+
genConfig.routesPath = options?.path || 'src/routes';
|
|
12
13
|
|
|
13
14
|
return {
|
|
14
15
|
name: 'sv-router',
|