Major update goal is to reduce foot-print and remove HOCs in favor of getStatic*
functions.
- Remove HOCs
withPosts*
,withPost
. - Support
[slug]
routing. - Support
[...entry]
routing. - Support
[[...entry]]
routing. - No bin required. Use
next
- Remove generated .json files in static export.
- Update README.md
- Remove
page
and default page from plugin config. - Remove
url
generation and permalink props. Update tests. - Add common sorters (?)
The Plugin System will be revamped to split current source
into 2 stages: source and create.
We should be able to create remark content based on md files or even plain txt or json files. We could also provide a creator-render perspective that might allow to process and render MDX files or any other formats that does not requires a HAST processing rendering.
We will have these stages/plugin-types:
- config
- source
- build
- transform
- cleanup
- filter
- sort
- render
The stages or plugin-types will be executed in the order listed here.
This stage allows plugin developers to inject configuration into the next.config.js
module. It MUST return the nextConfig
or the modified version of it.
config(options, nextConfig): {Object}
- options
- nextConfig
This stage compiles an entries list. It should call action.build
on any entry to be processed. The action.build
will execute build plugins.
source(options, action: { build, remove })
.- options
- action
- build(buildOptions)
- remove(removeOptions)
buildOptions
{Object}- filePath: Absolute path
- path: Relative to
options.path
. e.g.'/blog/first-post.md'
- name: e.g.
'firts-post.md'
- mimeType: e.g.
'text/markdown'
- createdOn {Date}
- extra {Object} default data to be passed for each entry metadata
- load() {Promise} return file content
removeOptions
{Object}- filePath: Absolute path
Create an entry. It should call action.create
to generate an Entry
in the _entries array.
build(options, buildOptions, action: { create })
.- options
- buildOptions
- action
- create(createOptions): {Entry}
createOptions
{Object}- meta
- filePath
- path
- name
- mimeType
- createdOn
- raw
- extra: (any user defined data e.g. in frontmatter)
- content
- meta
Entry
{Object}- data
- __id: MD5(meta.filePath)
- mimeType: meta.mimeType,
- name: meta.name
- category: meta.extra.category || meta.path
- date: meta.extra.date || meta.created
- day: {String} 2 digit padded day from date
- month: {String} 2 digit padded month from date
- year: {String} 4 digit year from date
- {...user defined data}
- content
- raw
- data
This stage receive the _entries array as posts
. Here we can modify one or many items.
transform(options, posts): {Array<Entry>}
- options
- posts
Same as transform stage but useful to remove / clean up data.
cleanup(options, posts): {Array<Entry>}
- options
- posts
Filter posts. Same as transform stage plugins but guaranteed to run after cleanup.
filter(options, posts): {Array<Entry>}
- options
- posts
Sort posts. Same as transform stage plugins but guaranteed to run after filter.
sort(options, posts): {Array<Entry>}
- options
- posts
This stage runs inside the Content
component.
render(options, post): {Component}
: It MUST be defined as a named export in arender.js
file on the plugin root folder. This method should return a React Component.
The plugin configuration should allow to:
- Configure multiple instances of a plugin.
- Override a defined configuration.
- Resolve fullname plugin with configured name as:
- simplified:
source-fs
. - fullname:
nextein-plugin-source-fs
.
- simplified:
Configuration resolves to an Object with the form:
{
name: {String},
id?: {String},
options: {Object}
}
Accepted forms:
- Object:
{ name, id?, options }
- String:
name-of-plugin
-> { name: 'name-of-plugin' }, - Array: [name, options] -> { name, options }
A plugin configuration will be identified by an internal id
. This id will be set by default to the plugin name if no id
property is provided.
This allows to generate multiple instances of the same plugin if anid
is provided or it can override a pre-configured plugin if not id provided.
{
name: 'nextein-plugin-x',
options: {
position: true,
raw: false
}
},
// override previous definition
['nextein-plugin-x', { position: true, raw: true }],
// Multiple instances
{
name: 'source-fs',
id: 'posts',
options: {
path: 'posts',
includes: '**/*.md'
}
},
{
name: 'source-fs', // resolve to nextein-plugin-source-fs
id: 'images',
options: {
path: 'images'
}
}
source-fs
- source
markdown
- build
- cleanup (remove position, raw, etc.)
filter-unpublished
- filter
TBD.
The Content
component will run the appropriate render based on the post
data.
Dynamic Routes and static generator functions (getStaticProps and getStaticPaths) can be used with this new experimental feature.
Example for a [name].js
dynamic route
import fetcher from 'nextein/fetcher'
const { getData, getPost } = fetcher(/* filter */)
export async function getStaticPaths () {
const data = await getData()
return {
paths: data.map(({ name }) => ({ params: { name } })),
fallback: false
}
}
export async function getStaticProps ({ params }) {
const post = await getPost(params)
return { props: { post } }
}
export default function Post ({ post }) {
//...
}
Example for a [[...name]].js
dynamic route:
import fetcher from 'nextein/fetcher'
import { inCategory } from 'nextein/filters'
const { getData, getPosts, getPost } = fetcher(inCategory('guides'))
export async function getStaticPaths () {
const data = await getData()
return {
paths: [{ params: { name: [] } },
...data.map(({ name }) => ({ params: { name: [name] } }))
],
fallback: false
}
}
export async function getStaticProps ({ params }) {
const posts = await getPosts()
const post = await getPost(params) // This can be null if not matching `...name`
return { props: { posts, post } }
}
export default function Guides ({ posts, post }) {
//...
}