nuxt-typed-router 2.0.0-beta.0 โ 2.0.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/README.md +35 -190
- package/dist/module.json +1 -1
- package/dist/module.mjs +31 -14
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img
|
|
4
|
+
<img src="https://raw.githubusercontent.com/victorgarciaesgi/nuxt-typed-router/master/.github/images/cover.png" alt="nuxt-typed-router cover">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
|
|
@@ -18,26 +18,40 @@
|
|
|
18
18
|
|
|
19
19
|
## Provide a type safe router to Nuxt with auto-generated typed definitions for route names and autocompletion for route params
|
|
20
20
|
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
21
|
+
- Automaticaly provides types check and autocomplete to `NuxtLink`
|
|
22
|
+
- Exports a `useTypedRouter` and `useTypedRoute` composable
|
|
23
|
+
- Supports routes defined in `config.extendRoutes`
|
|
24
|
+
- Infer route params based on route name
|
|
25
|
+
- Provide global `$typedRouter` util
|
|
26
|
+
|
|
27
|
+
<br/>
|
|
24
28
|
|
|
25
29
|
<br/>
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="https://github.com/victorgarciaesgi/nuxt-typed-router/blob/master/.github/images/nuxt-router.gif?raw=true"/>
|
|
32
|
+
</p>
|
|
33
|
+
<br/>
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Documentation
|
|
37
|
+
|
|
38
|
+
[](https://nuxt-typed-router.vercel.app/)
|
|
26
39
|
|
|
27
|
-
|
|
40
|
+
# Play with it
|
|
41
|
+
[](https://stackblitz.com/edit/github-7e4xvw?file=store/testRouter.ts)
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
Demo repo ๐งช : [nuxt-typed-router-demo](https://github.com/victorgarciaesgi/nuxt-typed-router-demo)
|
|
44
|
+
|
|
45
|
+
<br/>
|
|
46
|
+
|
|
47
|
+
# Compatibility:
|
|
30
48
|
|
|
31
49
|
- Nuxt 3
|
|
32
50
|
- Nuxt 2 (via [`nuxt2` branch](https://github.com/victorgarciaesgi/nuxt-typed-router/tree/nuxt2))
|
|
33
51
|
|
|
34
|
-
<br/>
|
|
35
|
-
<p align="center">
|
|
36
|
-
<img src="https://github.com/victorgarciaesgi/nuxt-typed-router/blob/master/.github/images/in-action.gif?raw=true"/>
|
|
37
|
-
</p>
|
|
38
|
-
<br/>
|
|
39
52
|
|
|
40
|
-
|
|
53
|
+
|
|
54
|
+
# Quick start
|
|
41
55
|
|
|
42
56
|
### For Nuxt 3
|
|
43
57
|
|
|
@@ -47,9 +61,10 @@ yarn add -D nuxt-typed-router
|
|
|
47
61
|
npm install -D nuxt-typed-router
|
|
48
62
|
```
|
|
49
63
|
|
|
50
|
-
###
|
|
64
|
+
### Nuxt 2 legacy
|
|
51
65
|
|
|
52
|
-
|
|
66
|
+
Nuxt 2 version is no longer maintained, but still available in [`nuxt2` branch](https://github.com/victorgarciaesgi/nuxt-typed-router/tree/nuxt2)
|
|
67
|
+
It only has route name autocomplete functionnality
|
|
53
68
|
|
|
54
69
|
```bash
|
|
55
70
|
yarn add -D nuxt-typed-router@legacy
|
|
@@ -58,192 +73,22 @@ npm install -D nuxt-typed-router@legacy
|
|
|
58
73
|
```
|
|
59
74
|
|
|
60
75
|
# Configuration
|
|
61
|
-
|
|
62
|
-
First, register the module in the `nuxt.config.ts`
|
|
76
|
+
Register the module in the `nuxt.config.ts`, done!
|
|
63
77
|
|
|
64
78
|
```ts
|
|
65
79
|
export default defineNuxtConfig({
|
|
66
80
|
modules: ['nuxt-typed-router'],
|
|
67
|
-
nuxtTypedRouter: {
|
|
68
|
-
// options
|
|
69
|
-
},
|
|
70
81
|
});
|
|
71
82
|
```
|
|
72
83
|
|
|
73
|
-
## Options:
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
interface ModuleOptions {
|
|
77
|
-
/** Output directory where you cant the files to be saved
|
|
78
|
-
* (ex: "./models")
|
|
79
|
-
* @default "<srcDir>/generated"
|
|
80
|
-
*/
|
|
81
|
-
outDir?: string;
|
|
82
|
-
/** Name of the routesNames object (ex: "routesTree")
|
|
83
|
-
* @default "routerPagesNames"
|
|
84
|
-
* */
|
|
85
|
-
routesObjectName?: string;
|
|
86
|
-
/**
|
|
87
|
-
* Set to false if you don't want a plugin generated
|
|
88
|
-
* @default false
|
|
89
|
-
*/
|
|
90
|
-
plugin?: boolean;
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
# Generated files
|
|
95
|
-
|
|
96
|
-
The module will generate 4 files each time you modify the `pages` folder :
|
|
97
|
-
|
|
98
|
-
- `~/<outDir>/__routes.ts` with the global object of the route names inside.
|
|
99
|
-
- `~/<outDir>/__useTypedRouter.ts` Composable to simply access your typed routes
|
|
100
|
-
- `~/<outDir>/typed-router.d.ts` containing the global typecript definitions and exports
|
|
101
|
-
- `~/plugins/__typed_router.ts` Plugin that will inject `$typedRouter` and `$routesList` (`@nuxt/kit` has problems registering plugin templates so this is a workaround)
|
|
102
|
-
|
|
103
|
-
# Usage in Vue/Nuxt
|
|
104
|
-
|
|
105
|
-
<br/>
|
|
106
|
-
|
|
107
|
-
### **_Requirements_**
|
|
108
|
-
|
|
109
|
-
You can specify the output dir of the generated files in your configuration. It defaults to `<srcDir>/generated`
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
export default defineNuxtConfig({
|
|
113
|
-
modules: ['nuxt-typed-router'],
|
|
114
|
-
nuxtTypedRouter: {
|
|
115
|
-
outDir: './generated',
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
# How it works
|
|
121
|
-
|
|
122
|
-
Given this structure
|
|
123
|
-
|
|
124
|
-
โโโ pages
|
|
125
|
-
โโโ index
|
|
126
|
-
โโโ content
|
|
127
|
-
โโโ [id].vue
|
|
128
|
-
โโโ content.vue
|
|
129
|
-
โโโ index.vue
|
|
130
|
-
โโโ communication.vue
|
|
131
|
-
โโโ statistics.vue
|
|
132
|
-
โโโ [user].vue
|
|
133
|
-
โโโ index.vue
|
|
134
|
-
โโโ forgotpassword.vue
|
|
135
|
-
โโโ reset-password.vue
|
|
136
|
-
โ โโโ login.vue
|
|
137
|
-
โโโ ...
|
|
138
|
-
|
|
139
|
-
The generated route list will look like this
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
export const routerPagesNames = {
|
|
143
|
-
forgotpassword: 'forgotpassword' as const,
|
|
144
|
-
login: 'login' as const,
|
|
145
|
-
resetPassword: 'reset-password' as const,
|
|
146
|
-
index: {
|
|
147
|
-
index: 'index' as const,
|
|
148
|
-
communication: 'index-communication' as const,
|
|
149
|
-
content: {
|
|
150
|
-
id: 'index-content-id' as const,
|
|
151
|
-
},
|
|
152
|
-
statistics: 'index-statistics' as const,
|
|
153
|
-
user: 'index-user' as const,
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
export type TypedRouteList =
|
|
157
|
-
| 'forgotpassword'
|
|
158
|
-
| 'login'
|
|
159
|
-
| 'reset-password'
|
|
160
|
-
| 'index'
|
|
161
|
-
| 'index-communication'
|
|
162
|
-
| 'index-content-id'
|
|
163
|
-
| 'index-statistics'
|
|
164
|
-
| 'index-user';
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
> nuxt-typed-router will also create a plugin in your `<srcDir>/plugins` folder with the injected `$typedRouter` and `$routesList` helpers
|
|
168
|
-
|
|
169
|
-
# Usage with `useTypedRouter` hook
|
|
170
|
-
|
|
171
|
-
`useTypedRouter` is an exported composable from nuxt-typed-router. It contains a clone of `vue-router` but with strictly typed route names and params type-check
|
|
172
|
-
|
|
173
|
-
```vue
|
|
174
|
-
<script lang="ts">
|
|
175
|
-
// The path here is `~/generated` because I set `outDir: './generated'` in my module options
|
|
176
|
-
import { useTypedRouter } from '~/generated';
|
|
177
|
-
|
|
178
|
-
export default defineComponent({
|
|
179
|
-
setup() {
|
|
180
|
-
// Fully typed
|
|
181
|
-
const { router, routes } = useTypedRouter();
|
|
182
|
-
|
|
183
|
-
function navigate() {
|
|
184
|
-
// Autocompletes the name and infer the params
|
|
185
|
-
router.push({ name: routes.index.user, params: { user: 1 } }); // โ
valid
|
|
186
|
-
router.push({ name: routes.index.user, params: { foo: 1 } }); // โ invalid
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return { navigate };
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
</script>
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
# Usage with `$typedRouter` and `$routesList` injected helpers
|
|
196
|
-
|
|
197
|
-
`$typedRouter` is an injected clone of vue-router `$router`, but fully typed with all your routes.
|
|
198
|
-
It's available anywhere you have access to Nuxt context
|
|
199
|
-
|
|
200
|
-
```vue
|
|
201
|
-
<script lang="ts">
|
|
202
|
-
import { defineComponent } from 'vue';
|
|
203
|
-
|
|
204
|
-
export default defineComponent({
|
|
205
|
-
name: 'Index',
|
|
206
|
-
setup() {
|
|
207
|
-
const { $typedRouter, $routesList } = useNuxtApp();
|
|
208
|
-
|
|
209
|
-
function navigate() {
|
|
210
|
-
$typedRouter.push({ name: $routesList.activate });
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
navigate,
|
|
215
|
-
};
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
</script>
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
# Usage outside Vue component
|
|
222
|
-
|
|
223
|
-
You can import the `useTypedRouter` composable from where it's generated.
|
|
224
|
-
Exemple with `pinia` store here
|
|
225
|
-
|
|
226
|
-
```ts
|
|
227
|
-
import pinia from 'pinia';
|
|
228
|
-
import { useTypedRouter } from '~/generated';
|
|
229
|
-
|
|
230
|
-
export const useFooStore = defineStore('foo', {
|
|
231
|
-
actions: {
|
|
232
|
-
bar() {
|
|
233
|
-
const { router, routes } = useTypedRouter();
|
|
234
|
-
router.push({ name: routes.index.user, params: { user: 2 } });
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
```
|
|
239
84
|
|
|
240
85
|
## Development
|
|
241
86
|
|
|
242
87
|
1. Clone this repository
|
|
243
|
-
2. Install dependencies using `
|
|
244
|
-
3. Build project for local tests `
|
|
245
|
-
4. Start dev playground `
|
|
246
|
-
5. Build project for deploy `
|
|
88
|
+
2. Install dependencies using `pnpm`
|
|
89
|
+
3. Build project for local tests `pnpm build:local`
|
|
90
|
+
4. Start dev playground `pnpm play`
|
|
91
|
+
5. Build project for deploy `pnpm prepack`
|
|
247
92
|
|
|
248
93
|
## ๐ License
|
|
249
94
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -120,7 +120,7 @@ declare global {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
type TypedNuxtLinkProps = Omit<NuxtLinkProps, 'to'> & {
|
|
123
|
-
to: Omit<Exclude<RouteLocationRaw, string>, 'name'> & TypedRouteNamedMapper;
|
|
123
|
+
to: string | Omit<Exclude<RouteLocationRaw, string>, 'name'> & TypedRouteNamedMapper;
|
|
124
124
|
};
|
|
125
125
|
|
|
126
126
|
type _NuxtLink = DefineComponent<
|
|
@@ -171,7 +171,7 @@ function createDeclarationRoutesFile() {
|
|
|
171
171
|
function createRuntimeIndexFile() {
|
|
172
172
|
return `
|
|
173
173
|
${watermarkTemplate}
|
|
174
|
-
export
|
|
174
|
+
export {routesNames, TypedRouteList} from './__routes';
|
|
175
175
|
export * from './__useTypedRouter';
|
|
176
176
|
export * from './__useTypedRoute';
|
|
177
177
|
`;
|
|
@@ -227,7 +227,9 @@ function createResolvedTypedRouteNamedMapperExport(routesParams) {
|
|
|
227
227
|
} & (
|
|
228
228
|
${routesParams.map(
|
|
229
229
|
({ name, params }) => `{name: "${name}" ${params.length ? `, params: {
|
|
230
|
-
|
|
230
|
+
${params.map(
|
|
231
|
+
({ key, notRequiredOnPage, type }) => `"${key}"${notRequiredOnPage ? "?" : ""}: ${type}`
|
|
232
|
+
).join(",\n")}
|
|
231
233
|
}` : ""}}`
|
|
232
234
|
).join("|\n")}
|
|
233
235
|
)
|
|
@@ -307,7 +309,6 @@ function createRuntimeUseTypedRouterFile(routesDeclTemplate) {
|
|
|
307
309
|
${watermarkTemplate}
|
|
308
310
|
import { useRouter } from '#app';
|
|
309
311
|
import { TypedRouter } from './typed-router';
|
|
310
|
-
import { RouteListDecl } from './__routes';
|
|
311
312
|
|
|
312
313
|
/** Returns instances of $typedRouter and $routesList fully typed to use in your components or your Vuex/Pinia store
|
|
313
314
|
*
|
|
@@ -357,11 +358,12 @@ dirname(fileURLToPath(import.meta.url));
|
|
|
357
358
|
async function processPathAndWriteFile({
|
|
358
359
|
content,
|
|
359
360
|
fileName,
|
|
360
|
-
srcDir
|
|
361
|
+
srcDir,
|
|
362
|
+
outDir
|
|
361
363
|
}) {
|
|
362
364
|
try {
|
|
363
|
-
const
|
|
364
|
-
const processedOutDir = resolve(srcDir,
|
|
365
|
+
const finalOutDir = outDir ?? `.nuxt/typed-router`;
|
|
366
|
+
const processedOutDir = resolve(srcDir, finalOutDir);
|
|
365
367
|
const outputFile = resolve(process.cwd(), `${processedOutDir}/${fileName}`);
|
|
366
368
|
const formatedContent = await formatOutputWithPrettier(content);
|
|
367
369
|
if (fs.existsSync(outputFile)) {
|
|
@@ -403,6 +405,7 @@ function handlePluginFileSave({
|
|
|
403
405
|
});
|
|
404
406
|
}
|
|
405
407
|
|
|
408
|
+
let previousGeneratedRoutes = "";
|
|
406
409
|
async function saveGeneratedFiles({
|
|
407
410
|
srcDir,
|
|
408
411
|
outputData: { routesDeclTemplate, routesList, routesObjectTemplate, routesParams }
|
|
@@ -437,22 +440,35 @@ async function saveGeneratedFiles({
|
|
|
437
440
|
await Promise.all(
|
|
438
441
|
filesMap.map(({ content, fileName }) => processPathAndWriteFile({ srcDir, content, fileName }))
|
|
439
442
|
);
|
|
440
|
-
|
|
443
|
+
if (previousGeneratedRoutes !== routesList.join(",")) {
|
|
444
|
+
previousGeneratedRoutes = routesList.join(",");
|
|
445
|
+
console.log(logSymbols.success, `[typed-router] Routes definitions generated`);
|
|
446
|
+
}
|
|
441
447
|
}
|
|
442
448
|
|
|
443
449
|
function isItemLast(array, index) {
|
|
444
450
|
return array ? index === array.length - 1 : false;
|
|
445
451
|
}
|
|
446
452
|
|
|
447
|
-
const routeParamExtractRegxp =
|
|
453
|
+
const routeParamExtractRegxp = /(:(\w+)(\?)?)+/g;
|
|
448
454
|
function extractRouteParamsFromPath(path, isIndexFileForRouting, previousParams) {
|
|
449
|
-
|
|
450
|
-
|
|
455
|
+
let params = [];
|
|
456
|
+
let matches;
|
|
457
|
+
do {
|
|
458
|
+
matches = routeParamExtractRegxp.exec(path);
|
|
459
|
+
if (matches) {
|
|
460
|
+
const [_, mtch, key, optional] = matches;
|
|
461
|
+
if (mtch) {
|
|
462
|
+
params.push({ name: key, optional: !!optional });
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} while (matches);
|
|
451
466
|
let allMergedParams = params.map(
|
|
452
|
-
(
|
|
453
|
-
key:
|
|
467
|
+
({ name, optional }) => ({
|
|
468
|
+
key: name,
|
|
454
469
|
type: "string | number",
|
|
455
|
-
required:
|
|
470
|
+
required: !optional,
|
|
471
|
+
notRequiredOnPage: optional
|
|
456
472
|
})
|
|
457
473
|
);
|
|
458
474
|
if (previousParams?.length) {
|
|
@@ -633,6 +649,7 @@ const module = defineNuxtModule({
|
|
|
633
649
|
)
|
|
634
650
|
};
|
|
635
651
|
nuxt.hook("pages:extend", () => createTypedRouter({ srcDir, nuxt, plugin }));
|
|
652
|
+
createTypedRouter({ srcDir, nuxt, plugin });
|
|
636
653
|
}
|
|
637
654
|
});
|
|
638
655
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-typed-router",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Provide autocompletion for pages route names generated by Nuxt router",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/module.cjs",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test": "pnpm run dev:prepare && pnpm run build:test && vitest run",
|
|
25
25
|
"test:watch": "pnpm run build:test && vitest",
|
|
26
26
|
"docs:dev": "cd docs && pnpm run dev",
|
|
27
|
-
"docs:
|
|
27
|
+
"docs:build": "npm run dev:prepare && cd docs && nuxi generate"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"nuxt 3",
|
|
40
40
|
"nuxt 3 router"
|
|
41
41
|
],
|
|
42
|
+
"homepage": "https://nuxt-typed-router.vercel.app/",
|
|
42
43
|
"repository": {
|
|
43
44
|
"type": "git",
|
|
44
45
|
"url": "git+https://victorgarciaesgi@github.com/victorgarciaesgi/nuxt-typed-router.git"
|