Plugins functions are executed throughout the lifecycle of a react-static build in the order below:
A synchronous function to modify the resolved config object during build or export.
- Arguments:
config
- Thestatic.config.js
state
- The current state of the cli
- Returns a new or modified
config
object
afterGetConfig: (previousConfig, state) => {
// Return a new config
return newConfig
}
An async function to modify the CLI state before browser plugins are prepared.
- Arguments:
state
- The current state of the cli
- Returns the new CLI
state
beforePrepareBrowserPlugins: async state => {
// Use or modify the CLI state
return newState
}
An async function to modify the CLI state after preparing browser plugins.
- Arguments:
state
- The current state of the cli
- Returns the new CLI
state
afterPrepareBrowserPlugins: async state => {
// Use or modify the CLI state
return newState
}
An async function to modify the CLI state before preparing routes.
- Arguments:
state
- The current state of the cli
- Returns the new CLI
state
beforePrepareRoutes: async state => {
// Use or modify the CLI state
return newState
}
A synchronous function to modify the route after it has been normalized.
- Arguments:
info{}
route
- The normalized route after it has been normalizedparent
- The parent route
state
- The current state of the cli
- Returns the new
normalizedRoute
normalizeRoute: ({ route, parent }, state) => {
// Modify the route
return route
}
An async function to modify the CLI state before preparing routes.
- Arguments:
state
- The current state of the cli
- Returns the new CLI
state
afterPrepareRoutes: async state => {
// Use or modify the CLI state
return newState
}
A synchronous function to modify the webpack config.
- Arguments:
currentWebpackConfig
- The current webpack configuration objectstate
- The current state of the CLI
- Returns a new webpack configuration object
webpack: (currentWebpackConfig, state) => {
// Return a new config
return newConfig
}
Loaders
The default loaders for React Static are available as a convenience object at state.defaultLoaders
:
jsLoader
- The default loader for all.js
files located in your project'ssrc
directoryjsLoaderExt
- The default loader for all other.js
files not located in your project'ssrc
directory.cssLoader
- The default style loader that supports importing.css
files and usage of css modules.fileLoader
- The default catch-all loader for any other file that isn't a.js
.json
or.html
file. Usesurl-loader
andfile-loader
Our default loaders are organized like so:
const webpackConfig = {
...
module: {
rules: [{
oneOf: [
jsLoader, // Compiles all project javascript files with babel
jsLoaderExt, // Compiles all external (node_modules) javascript files with babel
cssLoader, // Supports basic css imports and css modules
fileLoader // Catch-all url-loader/file-loader for anything else
}]
}
...
}
The source for all default loaders can be found in webpack/rules/ directory.
Note: Usage of the oneOf
rule is recommended. This ensures each file is only handled by the first loader it matches, and not any loader. This also makes it easier to reutilize the default loaders, without having to fuss with excludes
. Here are some examples of how to replace and modify the default loaders:
Replacing all rules
// node.api.js
export default pluginOptions => ({
webpack: config => {
config.module.rules = [
// Your own rules here...
]
return config
},
})
Replacing a default loader for a different one
// node.api.js
export default pluginOptions => ({
webpack: (config, { defaultLoaders }) => {
config.module.rules = [{
oneOf: [
defaultLoaders.jsLoader,
defaultLoaders.jsLoaderExt,
{
// Use this special loader
// instead of the cssLoader
}
defaultLoaders.fileLoader,
]
}]
return config
}
})
Adding a plugin
// node.api.js
import AwesomeWebpackPlugin from 'awesome-webpack-plugin'
export default pluginOptions => ({
webpack: config => {
config.plugins.push(new AwesomeWebpackPlugin())
return config
},
})
Using multiple transformers
// node.api.js
export default pluginOptions => ({
webpack: [
(config, { defaultLoaders }) => {
config.module.rules = [
{
oneOf: [
defaultLoaders.jsLoader,
defaultLoaders.jsLoaderExt,
defaultLoaders.cssLoader,
{
loader: 'file-loader',
test: /\.(fancyFileExtension)$/,
query: {
limit: 10000,
name: 'static/[name].[hash:8].[ext]',
},
},
defaultLoaders.fileLoader,
],
},
]
return config
},
config => {
console.log(config.module.rules) // Log out the final set of rules
},
],
})
After a completed bundle, run any asynchronous function.
- Arguments:
state
- The current state of the CLI
- Returns a new
state
object
// node.api.js
export default pluginOptions => ({
afterBundle: async state => {
// Use or alter the state of the CLI
return state
},
})
Modify the App
component before it is rendered to an element via <App />
.
- Arguments:
App
- TheApp
component (not yet rendered to an element via<App />
)state
- The current state of the CLI
- Returns a new
App
component (not yet rendered to an element)
// node.api.js
export default pluginOptions => ({
afterDevServerStart: async state => {
// Use or modify the CLI state
return newState
},
})
An async function to modify the CLI state after starting the development server.
- Arguments:
App
- TheApp
component (not yet rendered to an element via<App />
)state
- The current state of the CLI
- Returns a new
App
component (not yet rendered to an element)
// node.api.js
export default pluginOptions => ({
beforeRenderToElement: async (App, state) => {
const NewApp => props => {
return <App {...props} />
}
// You must return the component, not the rendered element!
return NewApp
},
})
Modify the rendered <App />
element before it is rendered to HTML.
- Arguments:
app
- Theapp
element (has already been rendered via<App />
)state
- The current state of the CLI
- Returns a new react element for the App
// node.api.js
export default pluginOptions => ({
beforeRenderToHtml: async (element, state) => {
// You must return an element (already rendered), not a component
const newApp = <div>{element}</div>
return newApp
},
})
Modify the props that will passed to the Document's <html>
element.
- Arguments:
props
- The current props objectstate
- The current state of the CLI
- Returns a new props object
// node.api.js
export default pluginOptions => ({
htmlProps: async (props, state) => {
return {
...props,
myProp: 'hello',
}
},
})
Add elements to the <head>
of the statically generated page.
- Arguments:
elements
- The current array of elements that will be rendered into the head of the document.state
- The current state of the CLI
- Returns a new array of elements
// node.api.js
export default pluginOptions => ({
headElements: async (elements, state) => {
return [
...elements,
<link rel="stylesheet" href="..." />,
<link rel="stylesheet" href="..." />,
]
},
})
Modify the app html
string before it is injected into the Document
component.
- Arguments:
html
- The apphtml
string to be injected into the Document componentstate
- The current state of the CLI
- Returns a new
html
string to be injected into theDocument
component
// node.api.js
export default pluginOptions => ({
beforeHtmlToDocument: async (html, state) => {
// html is a string here. You can do whatever you like with it!
return html
},
})
Modify the final html
string before it is written to disk.
- Arguments:
html
- The finalhtml
string before it is written to diskstate
- The current state of the CLI
- Returns a new final
html
string to be written to disk.
// node.api.js
export default pluginOptions => ({
beforeDocumentToFile: async (html, state) => {
// html is a string here. You can do whatever you like with it!
return html
},
})
After a completed build and export, run any asynchronous function.
- Arguments:
state
- The current state of the CLI
- Returns a new
state
object
// node.api.js
export default pluginOptions => ({
afterExport: async state => {
// Use or alter the state of the CLI
return state
},
})
An array of plugins that this plugin depends on. Follows the same format as static.config.js
does for importing plugins and options.
// node.api.js
export default pluginOptions => ({
plugins: [
'another-plugin',
[
'another-plugin-with-options',
{
anOption: true,
},
],
],
})