next-pages v0.2.2
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