pathpida

TypeScript friendly internal link client for Next.js, Nuxt.js and Sapper.

README

pathpida



pathpida
npm version npm download Node.js CI Codecov Language grade: JavaScript

TypeScript friendly internal link client for Next.js and Nuxt.js.




Breaking change :warning:


2022/11/25


Since pathpida >= 0.20.0 , removed Sapper support.

2022/02/24


Since pathpida >= 0.18.0 , requires TypeSciprt 3.8 or higher for Type-Only Imports.

Features


- Type safety. Automatically generate type definition files for manipulating internal links in Next.js/Nuxt.js.
- Zero configuration. No configuration required can be used immediately after installation.
- Zero runtime. Lightweight because runtime code is not included in the bundle.
- Support for static files. Static files in public/ are also supported, so static assets can be safely referenced.
- Support for appDir of Next.js 13 Layout.

Table of Contents



Install


- Using npm:

  sh
  $ npm install pathpida npm-run-all --save-dev
  

- Using Yarn:

  sh
  $ yarn add pathpida npm-run-all --dev
  


Command Line Interface Options


Option Type Description
--enableStatic
-s
Generate static files path in $path.ts.
--ignorePath
-p
string Specify the ignore pattern file path.
--output
-o
string Specify the output directory for $path.ts.
--watch
-w
Enable watch mode.
Regenerate $path.ts.
--version
-v
Print pathpida version.


Setup - Next.js


package.json

  1. ```json
  2. {
  3.   "scripts": {
  4.     "dev": "run-p dev:*",
  5.     "dev:next": "next dev",
  6.     "dev:path": "pathpida --ignorePath .gitignore --watch",
  7.     "build": "pathpida --ignorePath .gitignore && next build"
  8.   }
  9. }
  10. ```


Usage - Next.js


  1. ```
  2. pages/index.tsx
  3. pages/post/create.tsx
  4. pages/post/[pid].tsx
  5. pages/post/[...slug].tsx

  6. lib/$path.ts or utils/$path.ts // Generated automatically by pathpida
  7. ```

or

  1. ```
  2. src/pages/index.tsx
  3. src/pages/post/create.tsx
  4. src/pages/post/[pid].tsx
  5. src/pages/post/[...slug].tsx

  6. src/lib/$path.ts or src/utils/$path.ts // Generated automatically by pathpida
  7. ```

pages/index.tsx

  1. ```tsx
  2. import Link from "next/link"
  3. import { pagesPath } from "../lib/$path"

  4. console.log(pagesPath.post.create.$url()) // { pathname: '/post/create' }
  5. console.log(pagesPath.post._pid(1).$url()) // { pathname: '/post/[pid]', query: { pid: 1 }}
  6. console.log(pagesPath.post._slug(["a", "b", "c"]).$url()) // { pathname: '/post//[...slug]', query: { slug: ['a', 'b', 'c'] }}

  7. export default () => {
  8.   const onClick = useCallback(() => {
  9.     router.push(pagesPath.post._pid(1).$url())
  10.   }, [])

  11.   return (
  12.     <>
  13.       <Link href={pagesPath.post._slug(["a", "b", "c"]).$url()} />
  14.       <div onClick={onClick} />
  15.     </>
  16.   )
  17. }
  18. ```


Define query - Next.js


pages/post/create.tsx

  1. ```tsx
  2. export type Query = {
  3.   userId: number
  4.   name?: string
  5. }

  6. export default () => <div />
  7. ```

pages/post/[pid].tsx

  1. ```tsx
  2. export type OptionalQuery = {
  3.   limit: number
  4.   label?: string
  5. }

  6. export default () => <div />
  7. ```

pages/index.tsx

  1. ```tsx
  2. import Link from "next/link"
  3. import { pagesPath } from "../lib/$path"

  4. console.log(pagesPath.post.create.$url({ query: { userId: 1 } })) // { pathname: '/post/create', query: { userId: 1 }}
  5. console.log(pagesPath.post.create.$url()) // type error
  6. console.log(pagesPath.post._pid(1).$url()) // { pathname: '/post/[pid]', query: { pid: 1 }}
  7. console.log(pagesPath.post._pid(1).$url({ query: { limit: 10 }, hash: "sample" })) // { pathname: '/post/[pid]', query: { pid: 1, limit: 10 }, hash: 'sample' }

  8. export default () => {
  9.   const onClick = useCallback(() => {
  10.     router.push(pagesPath.post._pid(1).$url())
  11.   }, [])

  12.   return (
  13.     <>
  14.       <Link href={pagesPath.post._slug(["a", "b", "c"]).$url()} />
  15.       <div onClick={onClick} />
  16.     </>
  17.   )
  18. }
  19. ```


Generate static files path - Next.js


package.json

  1. ```json
  2. {
  3.   "scripts": {
  4.     "dev": "run-p dev:*",
  5.     "dev:next": "next dev",
  6.     "dev:path": "pathpida --enableStatic --watch",
  7.     "build": "pathpida --enableStatic && next build"
  8.   }
  9. }
  10. ```

  1. ```
  2. pages/index.tsx
  3. pages/post/create.tsx
  4. pages/post/[pid].tsx
  5. pages/post/[...slug].tsx

  6. public/aa.json
  7. public/bb/cc.png

  8. lib/$path.ts or utils/$path.ts // Generated automatically by pathpida
  9. ```

or

  1. ```
  2. src/pages/index.tsx
  3. src/pages/post/create.tsx
  4. src/pages/post/[pid].tsx
  5. src/pages/post/[...slug].tsx

  6. public/aa.json
  7. public/bb/cc.png

  8. src/lib/$path.ts or src/utils/$path.ts // Generated automatically by pathpida
  9. ```

pages/index.tsx

  1. ```tsx
  2. import Link from "next/link"
  3. import { pagesPath, staticPath } from "../lib/$path"

  4. console.log(staticPath.aa_json) // /aa.json

  5. export default () => {
  6.   return (
  7.     <>
  8.       <Link href={pagesPath.post._slug(["a", "b", "c"]).$url()} />
  9.       <img src={staticPath.bb.cc_png} />
  10.     </>
  11.   )
  12. }
  13. ```


Setup - Nuxt.js


package.json

  1. ```json
  2. {
  3.   "scripts": {
  4.     "dev": "run-p dev:*",
  5.     "dev:nuxt": "nuxt-ts",
  6.     "dev:path": "pathpida --ignorePath .gitignore --watch",
  7.     "build": "pathpida --ignorePath .gitignore && nuxt-ts build"
  8.   }
  9. }
  10. ```

nuxt.config.js or nuxt.config.ts

  1. ```js
  2. {
  3.   plugins: ['~/plugins/$path'],
  4.   srcDir: 'client', // optional
  5.   router: {
  6.     trailingSlash: true // optional
  7.   }
  8. }
  9. ```


Usage - Nuxt.js


  1. ```
  2. pages/index.vue
  3. pages/post/create.vue
  4. pages/post/_pid.tsx

  5. plugins/$path.ts // Generated automatically by pathpida
  6. ```

pages/index.vue

  1. ```vue
  2. <template>
  3.   <div>
  4.     <nuxt-link :to="$pagesPath.post._pid(1).$url()" />
  5.     <div @click="onClick" />
  6.   </div>
  7. </template>

  8. <script lang="ts">
  9. import Vue from "vue"

  10. export default Vue.extend({
  11.   methods: {
  12.     onClick() {
  13.       this.$router.push(this.$pagesPath.post._pid(1).$url())
  14.     }
  15.   }
  16. })
  17. </script>
  18. ```


Define query - Nuxt.js


pages/post/create.vue

  1. ```vue
  2. <script lang="ts">
  3. import Vue from "vue"

  4. export type Query = {
  5.   userId: number
  6.   name?: string
  7. }

  8. export default Vue.extend({})
  9. </script>
  10. ```

pages/post/_pid.vue

  1. ```vue
  2. <script lang="ts">
  3. import Vue from "vue"

  4. export type OptionalQuery = {
  5.   limit: number
  6.   label?: string
  7. }

  8. export default Vue.extend({})
  9. </script>
  10. ```

pages/index.vue

  1. ```vue
  2. <template>
  3.   <div>
  4.     <nuxt-link :to="$pagesPath.post.create.$url({ query: { userId: 1 } })" />
  5.     <div @click="onClick" />
  6.   </div>
  7. </template>

  8. <script lang="ts">
  9. import Vue from "vue"

  10. export default Vue.extend({
  11.   methods: {
  12.     onClick() {
  13.       this.$router.push(this.$pagesPath.post._pid(1).$url())
  14.       this.$router.push(this.$pagesPath.post._pid(1).$url({ query: { limit: 10 }, hash: "sample" }))
  15.     }
  16.   }
  17. })
  18. </script>
  19. ```

:warning: In the case of .vue file, Query/OptionalQuery type must not contain any reference types.


This is because due to typescript restrictions, types exported from .vue files cannot be imported in plugins/$path.ts.
If you want to import types from other files, please use import types with absolute paths.

types/users.ts

  1. ```ts
  2. export type UserId = number
  3. ```

pages/post/create.vue

  1. ```vue
  2. <script lang="ts">
  3. import Vue from "vue"

  4. export type Query = {
  5.   userId: import("~/types/users").UserId
  6.   name?: string
  7. }

  8. export default Vue.extend({})
  9. </script>
  10. ```


Generate static files path - Nuxt.js


package.json

  1. ```json
  2. {
  3.   "scripts": {
  4.     "dev": "run-p dev:*",
  5.     "dev:nuxt": "nuxt-ts",
  6.     "dev:path": "pathpida --enableStatic --watch",
  7.     "build": "pathpida --enableStatic && nuxt-ts build"
  8.   }
  9. }
  10. ```

  1. ```
  2. pages/index.vue
  3. pages/post/create.vue
  4. pages/post/_pid.vue

  5. static/aa.json
  6. static/bb/cc.png

  7. plugins/$path.ts // Generated automatically by pathpida
  8. ```

pages/index.vue

  1. ```vue
  2. <template>
  3.   <div>
  4.     <nuxt-link :to="$pagesPath.post.create.$url({ query: { userId: 1 } })" />
  5.     <img :src="$staticPath.bb.cc_png" />
  6.   </div>
  7. </template>

  8. <script lang="ts">
  9. import Vue from "vue"

  10. export default Vue.extend({})
  11. </script>
  12. ```

License


pathpida is licensed under a MIT License.