next-page-map
Get a mapping of files to page paths from your Next.js pages directory.
Installation
npm i next-page-map
Usage
This can be used to build navigation trees and construct links to edit the current page on GitHub. It walks the pages
directory synchronously, so it's best placed in your next.config.js
and the result passed via publicRuntimeConfig
:
const getPageMap = const pageMap = moduleexports = publicRuntimeConfig: pageMap // the rest of your config
Options
The getPageMap()
default export takes an optional object of options:
Key | Description | Default |
---|---|---|
dir |
the directory from which to resolve pages |
the current working directory (process.cwd() ) |
pageExtensions |
an optional array of filename extensions to match | ['js', 'jsx'] |
nested |
a boolean to enable the nested object format | false |
Map format
The default return format is an object mapping URIs (keys) to filenames (values). Both values have a leading slash, e.g.
/* given the following file structure: pages ├── about │ ├── index.js │ ├── mission.js │ └── team.js ├── index.js └── news.js*/ console /* outputs:{ "/": "/index.js", "/about": "/about/index.js", "/about/mission": "/about/mission.js", "/about/team": "/about/team.js", "/news": "/news.js"}*/
Nested format
If you'd like to build nested navigation from the page map, you can pass nested: true
in the options object, which causes getPageMap()
to return a recursive structure with the form:
file: '/path/to/foo/index.js' // the file name relative to <cwd>/pages path: '/path/to/foo' // the URI (path minus page extension and trailing "/index") isIndex: true // whether the file w/o extention ends in "/index" parent: '/path/to' // the path of the "parent" page children: <pages> // an array of objects whose `.parent` === this.path
Examples
Edit links
The map format can be used to look up the filename from any component that uses Next's router, including App components:
// pages/_app.jsimport App Container from 'next/app'import getConfig from 'next/config'const pageMap = publicRuntimeConfig // TODO: replace "<owner>" and "<repo>" with your repo's slugs,// and replace "master" if that's not your default branchconst editBaseURL = 'https://github.com/<owner>/<repo>/edit/master/pages'const editURL = `` { const pathname = thispropsrouter const filename = pageMappathname return <Container> /* render your stuff */ filename && <p> <a =>Edit this page on GitHub</a> </p> </Container> }
Nested navigation
This example uses nested format with webpack's require.context to get a handle on the actual components that each page renders, then tries to get the text for the link from its displayName
:
// next.config.jsconst getPageMap = const pageExtensions = 'js' 'mdx' moduleexports = pageExtensions publicRuntimeConfig: pageExtensions pageMap: // ...
// src/Nav.jsimport getConfig from 'next/config'import NextLink from 'next/link'import withRouter from 'next/router' const pageExtensions pageMap = publicRuntimeConfig const pattern = `\.($`const requirePage = require { return <nav > <NavList = /> </nav> } const NavList = links ...rest <ul > links </ul> // Note: the withRouter() HOC gives this component a `router` prop,// which memorializes the `pathname` of the current pageconst NavLink =