/pathpida

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

Primary LanguageTypeScriptMIT LicenseMIT

pathpida


pathpida

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

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



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.

Table of Contents

Install

  • Using npm:

    $ npm install pathpida npm-run-all --save-dev
  • Using Yarn:

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

Setup - Next.js

package.json

{
  "scripts": {
    "dev": "run-p dev:*",
    "dev:next": "next dev",
    "dev:path": "pathpida --watch",
    "build": "pathpida && next build"
  }
}

Usage - Next.js

pages/index.tsx
pages/post/create.tsx
pages/post/[pid].tsx
pages/post/[...slug].tsx

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

or

src/pages/index.tsx
src/pages/post/create.tsx
src/pages/post/[pid].tsx
src/pages/post/[...slug].tsx

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

pages/index.tsx

import Link from 'next/link'
import { pagesPath } from '../lib/$path'

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

export default () => {
  const onclick = useCallback(() => {
    router.push(pagesPath.post._pid(1).$url())
  }, [])

  return <>
    <Link href={pagesPath.post._slug(['a', 'b', 'c']).$url()} />
    <div onclick={onclick} />
  </>
}

Define query - Next.js

pages/post/create.tsx

export type Query = {
  userId: number
  name?: string
}

export default () => <div />

pages/post/[pid].tsx

export type OptionalQuery = {
  limit: number
  label?: string
}

export default () => <div />

pages/index.tsx

import Link from 'next/link'
import { pagesPath } from '../lib/$path'

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

export default () => {
  const onclick = useCallback(() => {
    router.push(pagesPath.post._pid(1).$url())
  }, [])

  return <>
    <Link href={pagesPath.post._slug(['a', 'b', 'c']).$url()} />
    <div onclick={onclick} />
  </>
}

Generate static files path - Next.js

package.json

{
  "scripts": {
    "dev": "run-p dev:*",
    "dev:next": "next dev",
    "dev:path": "pathpida --enableStatic --watch",
    "build": "pathpida --enableStatic && next build"
  }
}
pages/index.tsx
pages/post/create.tsx
pages/post/[pid].tsx
pages/post/[...slug].tsx

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

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

or

src/pages/index.tsx
src/pages/post/create.tsx
src/pages/post/[pid].tsx
src/pages/post/[...slug].tsx

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

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

pages/index.tsx

import Link from 'next/link'
import { pagesPath, staticPath } from '../lib/$path'

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

export default () => {
  return <>
    <Link href={pagesPath.post._slug(['a', 'b', 'c']).$url()} />
    <img src={staticPath.bb.cc_png} />
  </>
}

Setup - Nuxt.js

package.json

{
  "scripts": {
    "dev": "run-p dev:*",
    "dev:nuxt": "nuxt-ts",
    "dev:path": "pathpida --watch",
    "build": "pathpida && nuxt-ts build"
  }
}

nuxt.config.js or nuxt.config.ts

{
  plugins: ['~/plugins/$path'],
  srcDir: 'client', // optional
  router: {
    trailingSlash: true // optional
  }
}

Usage - Nuxt.js

pages/index.vue
pages/post/create.vue
pages/post/_pid.tsx

plugins/$path.ts // Generated automatically by pathpida

pages/index.vue

<template>
  <div>
    <nuxt-link :to="$pagesPath.post._pid(1).$url()" />
    <div @click="onclick" />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  methods: {
    onclick() {
      this.$router.push(this.$pagesPath.post._pid(1).$url())
    }
  }
})
</script>

Define query - Nuxt.js

pages/post/create.vue

<script lang="ts">
import Vue from 'vue'

export type Query = {
  userId: number
  name?: string
}

export default Vue.extend({
})
</script>

pages/post/_pid.vue

<script lang="ts">
import Vue from 'vue'

export type OptionalQuery = {
  limit: number
  label?: string
}

export default Vue.extend({
})
</script>

pages/index.vue

<template>
  <div>
    <nuxt-link :to="$pagesPath.post.create.$url({ query: { userId: 1 }})" />
    <div @click="onclick" />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  methods: {
    onclick() {
      this.$router.push(this.$pagesPath.post._pid(1).$url())
      this.$router.push(this.$pagesPath.post._pid(1).$url({ query: { limit: 10 }, hash: 'sample' }))
    }
  }
})
</script>

⚠️ In the case of Nuxt.js, 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

export type UserId = number

pages/post/create.vue

<script lang="ts">
import Vue from 'vue'

export type Query = {
  userId: import('~/types/users').UserId
  name?: string
}

export default Vue.extend({
})
</script>

Generate static files path - Nuxt.js

package.json

{
  "scripts": {
    "dev": "run-p dev:*",
    "dev:nuxt": "nuxt-ts",
    "dev:path": "pathpida --enableStatic --watch",
    "build": "pathpida --enableStatic && nuxt-ts build"
  }
}
pages/index.vue
pages/post/create.vue
pages/post/_pid.vue

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

plugins/$path.ts // Generated automatically by pathpida

pages/index.vue

<template>
  <div>
    <nuxt-link :to="$pagesPath.post.create.$url({ query: { userId: 1 }})" />
    <img :src="$staticPath.bb.cc_png" />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'

export default Vue.extend({})
</script>

License

pathpida is licensed under a MIT License.