next-pages
v0.2.2
Published
Get all the pages in your Next app as a list or tree
Downloads
10
Readme
next-pages
Usage
Due to the... complicated nature of Next.js's server/client compilation split, it's currently necessary to inject the list of available pages via publicRuntimeConfig.pages
in your Next config. There's a configuration plugin available, which respects your pageExtension
config option:
// next.config.js
const pages = require('next-pages/plugin')
module.exports = withPages({
pageExtensions: ['js', 'jsx'],
})
The plugin also works nicely with next-compose-plugins:
// next.config.js
const withPlugins = require('next-compose-plugins')
const mdx = require('@zeit/next-mdx')
const pages = require('next-pages/plugin')
module.exports = withPlugins([
mdx({extension: /\.mdx?$/}),
pages
], {
pageExtensions: ['js', 'md', 'mdx']
})
Note: If you don't use custom page extensions (.md
, .mdx
, etc.) you can omit any of the references to pageExtensions
. The most minimal installation looks like:
// next.config.js
module.exports = require('next-pages/plugin')()
Then, in pages/_app.js
, you can import the pages
and root
variables from next-pages
:
// pages/_app.js
import React from 'react'
import App, {Container} from 'next/app'
import {pages, root} from 'next-pages'
export default class extends App {
render() {
const {Component, router} = this.props
// pages.find() works here, too:
const current = root.first(page => page.path === router.pathname)
return (
<Container>
<h1>{router.pathname}</h1>
<p>Current page: {JSON.stringify(current)}</p>
<Component />
</Container>
)
}
}
Page objects
Page objects are modified [tree-model] nodes with the shape:
{
path: '/absolute/uri',
file: './absolute/uri.js',
isIndex: Boolean,
parent: Node,
children: [Node]
}
Nodes have some useful methods, including:
getPath()
returns an array of nodes representing the "path" from the root node to this one, and is useful for building breadcrumb navigationhasChildren()
is a couple of characters shorter thanchildren.length > 0
isRoot()
should be self-explanatory
A node's path
should correspond to next/router
's Router.pathname
or props.router.pathname
when you wrap a component in [withRouter]. See the page tree methods for some examples.
Pages list
The pages
export is an array of page objects sorted alphabetically by their path
.
Page tree
The root
export is the top-most page object, and likely represents the /
URL of your app. You can access the children
Array of this object to get the list of top-level pages, or you can walk the tree with the following methods:
root.first(func)
returns the first node for whichfunc(node)
returnstrue
. For instance, to get the current page inside a component decorated with [withRouter]:import {root} from 'next-pages' import {withRouter} from 'next/router' export default withRouter(({router}) => { const page = root.first(node => node.path === router.pathname) // do something with the page object })
root.all(func)
returns all nodes for whichfunc(node)
returnstrue
. This is useful for finding all of the descendents of a path, e.g.import {root} from 'next-pages' import {withRouter} from 'next/router' export default withRouter(({router}) => { const pages = root.all(node => node.path.startsWith(router.pathname)) // do something with the pages array })
root.walk(func)
executesfunc(node)
for each node in the tree, and takes some additional options. You can use this torequire()
the files and metadata exported by your page components:// pages/_app.js import {root} from 'next-pages' const context = require.context('.', true, /\.(js|md)x?$/) root.walk(node => node.component = context(node.file))
Note: you will need to call
require.context('.', ...)
from thepages
directory for this to work properly!
Higher-order components
There are two higher-order components (decorators) that you can use to inject the pages list and tree values as props into components. Both of these also inject the router
prop via [withRouter] for convenience:
withPages(Component)
Injects the page list as the pages
prop:
import {withPages} from 'next-pages'
export default withPages(({pages, router, ...rest}) => {
// ...
})
withPageTree(Component)
Injects the root page object as the pageTree
prop:
import {withPageTree} from 'next-pages'
export default withPageTree({pageTree, router, ...rest}) => {
// ...
})
[tree-model]: https://www.npmjs.com/package/tree-model
[withRouter]: https://github.com/zeit/next.js/#using-a-higher-order-component