Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
sourcebit-target-next
Advanced tools
This plugin leverages Next.js SSG capabilities to provide content from any Sourcebit data source, such as a headless CMS, into React page components as properties using getStaticProps and getStaticPaths methods
Install Sourcebit and the plugin:
npm install sourcebit sourcebit-target-next
Import sourcebit
and sourcebit.js
configuration file into your
next.config.js
file (the next section will explain how to configure
sourcebit.js
file):
const sourcebit = require('sourcebit');
const sourcebitConfig = require('./sourcebit.js');
sourcebit.fetch(sourcebitConfig);
To provide data fetched by Sourcebit to pages, update getStaticPaths
and
getStaticProps
methods of your page components:
If a page does not use dynamic routes,
then it should only have the getStaticProps
method. To pass the data
fetched by Sourcebit to a page, update its getStaticProps
by calling
sourcebitDataClient.getStaticPropsForPageAtPath(path)
and
returning the props returned from it. The path
parameter should be the
URL path of the rendered page.
For example, if the page component is index.js
, then the path would be
/
, and if the page component is about.js
, then the path would be /about
.
For instance, given a page component at pages/index.js
, the code would
look like this:
import { sourcebitDataClient } from 'sourcebit-target-next';
export async function getStaticProps() {
const props = await sourcebitDataClient.getStaticPropsForPageAtPath('/');
return { props };
}
If a page does use dynamic routes
then it should have both getStaticProps
and getStaticPaths
methods.
Similar to the previous example, use getStaticPropsForPageAtPath(path)
to get the static props. But in this case, the path
parameter cannot be
constant. Instead it should be computed by applying params
provided by
the getStaticProps
to the pattern of the dynamic route.
For example, given a page component at pages/[...slug].js
, the code
would look like this:
import { sourcebitDataClient } from 'sourcebit-target-next';
export async function getStaticProps({ params }) {
const pagePath = '/' + params.slug.join('/');
const props = await sourcebitDataClient.getStaticPropsForPageAtPath(pagePath);
return { props };
}
Use sourcebitDataClient.getStaticPaths()
to get the static paths of
pages and return them from getStaticPaths
. Note that sourcebitDataClient.getStaticPaths()
returns paths for all pages, therefore you will need to filter them to
return only those that are supported by the dynamic route of the given page.
For example, if you have two pages with dynamic routes, each will have to filter its own static paths:
pages/post/[pid].js
import { sourcebitDataClient } from 'sourcebit-target-next';
export async function getStaticProps() {
...
}
export async function getStaticPaths() {
const paths = await sourcebitDataClient.getStaticPaths();
return {
paths: paths.filter(path => path.startsWith('/post/')),
fallback: false
};
}
pages/[...slug].js
import { sourcebitDataClient } from 'sourcebit-target-next';
export async function getStaticProps() {
...
}
export async function getStaticPaths() {
const paths = await sourcebitDataClient.getStaticPaths();
return {
// do not include paths for /post/[pid].js and for /index.js
paths: paths.filter(path => path !== '/' && !path.startsWith('/post/')),
fallback: false
};
}
To update the browser with live content changes while running next dev
, wrap
your pages with following higher order component (HOC):
import { withRemoteDataUpdates } from 'sourcebit-target-next/with-remote-data-updates';
class Page extends React.Component {
render() {
// ...
}
}
export default withRemoteDataUpdates(Page);
The plugin is configured with two options - pages
and commonProps
:
sourcebit.js
:
module.exports = {
plugins: [
...otherPlugins,
{
module: require('sourcebit-target-next'),
options: {
// Define which source objects represent pages
// and under which paths they should be available.
pages: [
{ path: '/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'page') },
{ path: '/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'special_page') },
{ path: '/blog/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'post') }
],
// Define common props that will be provided to all pages
commonProps: {
config: { single: true, predicate: _.matchesProperty('__metadata.modelName', 'site_config') },
posts: { predicate: _.matchesProperty('__metadata.modelName', 'post') }
}
}
}
]
};
pages
(array) An array of objects mapping entries fetched by one of the
source plugins to props that will be provided to a specific page identified
by its path via getStaticProps
.
Every object should define two fields path
and predicate
. The predicate
is used to filter entries fetched by source plugins. While the path
is used
to generate the URL path of the page. The path
parameter can use tokens in
form of {token_name}
where each token_name
is a field of an entry from the source plugin.
When calling sourcebitDataClient.getStaticPropsForPageAtPath(pagePath)
from within getStaticProps
, the returned value will be an object with two
properties: page
holding the actual page entry; and path
matching the
pagePath
passed to getStaticPropsForPageAtPath
.
For example:
// lodash's matchesProperty(path, value) creates a function that compares
// between the value at "path" of a given object to the provided "value"
[
{ path: '/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'page') },
{ path: '/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'custom_page') },
{ path: '/blog/{slug}', predicate: _.matchesProperty('__metadata.modelName', 'post') }
];
Assuming a Headless CMS returned a page of type custom_page
having slug: "about"
,
calling sourcebitDataClient.getStaticPropsForPageAtPath('/about')
from within
getStaticProps
will return a following object:
{
path: '/about',
page: {
slug: "about",
...otherEntryFields
}
}
commonProps
(object) An object mapping entries fetched by one of the source
plugins to props that will be provided to all page components via
getStaticProps
.
The keys of the object specify the propery names that will be provided to
page components, and their values specify what data should go into these
properties. Every value should be an object with a predicate
field.
The predicate
is used to filter entries fetched by source plugins.
Additionally, a boolean field single
can be used to specify a property that
should reference a single entry rather list of entries. If single: true
is applied
to multiple entries, only the first one will be selected.
When calling sourcebitDataClient.getStaticPropsForPageAtPath(pagePath)
from within getStaticProps
, the returned value will be an object with two
predefined properties page
and path
as described above, plus all the
properties defined by this map.
For example:
{
config: { single: true, predicate: _.matchesProperty('_type', 'site_config') },
posts: { predicate: _.matchesProperty('_type', 'post') }
}
When calling sourcebitDataClient.getStaticPropsForPageAtPath(pagePath)
, in
addition to page
and path
properties, the returned object will have
config
and posts
:
{
path: '/about',
page: { ... },
config: { ... },
posts: [ ... ]
}
liveUpdate
(boolean) A flag indicating if page should reload its data when remote
data changed. Defaults to true when NODE_ENV
is set to development
.
You can check out an example project
that uses sourcebit-source-sanity
and sourcebit-target-next
plugins to fetch
the data from Sanity.io and feed it into
Next.js page components.
Add following to your .gitignore
:
.sourcebit-cache.json
.sourcebit-nextjs-cache.json
To simplify the dynamic routing architecture and to allow greater flexibility when creating pages in Headless CMS, we advise using following pattern:
pages/[...slug].js
import React from 'react';
import { sourcebitDataClient } from 'sourcebit-target-next';
import withRemoteDataUpdates from 'sourcebit-target-next/withRemoteDataUpdates';
import pageLayouts from '../layouts';
class Page extends React.Component {
render() {
// every page can have different layout, pick the layout based
// on the modelName of the page
const PageLayout = pageLayouts[_.get(this.props, 'page.__metadata.modelName')];
return <PageLayout {...this.props} />;
}
}
export async function getStaticPaths() {
const paths = await sourcebitDataClient.getStaticPaths();
return { paths: paths.filter((path) => path !== '/'), fallback: false };
}
export async function getStaticProps({ params }) {
const pagePath = '/' + params.slug.join('/');
const props = await sourcebitDataClient.getStaticPropsForPageAtPath(pagePath);
return { props };
}
export default withRemoteDataUpdates(Page);
pages/index.js
import Page from './[...slug]';
import { sourcebitDataClient } from 'sourcebit-target-next';
export async function getStaticProps({ params }) {
console.log('Page [index] getStaticProps, params: ', params);
const props = await sourcebitDataClient.getStaticPropsForPageAtPath('/');
return { props };
}
export default Page;
Note: we are using additional index.js
page because [...slug].js
page does
not catch root page /
;
FAQs
A Sourcebit target plugin for Next.js
We found that sourcebit-target-next demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 15 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.