Plugins are shipped as separate packages and can extend or modify gluestick or webpack behaviour.
- Install plugin:
npm install --save gluestick-plugin-aphrodite
- Add plugin to
src/gluestick.plugins.js
:
export default [
'gluestick-plugin-aphrodite'
];
You can pass additional configuration options to plugin. To do so,
in the src/gluestick.plugins.js
file, instead of providing just the plugin name,
provide an object matching the following schema:
{
plugin: string; // plugin name
options: { // configuration for plugin
...
}
}
for example:
{
plugin: 'gluestick-env-expose-ast',
options: {
parse: 'file.js',
},
}
When running a command that uses plugins eg. start
, start-client
, start-server
, build
you should see logs stating which plugins were compiled.
If the compilation of a plugin fails, an appropriate error message will be show, however other plugins will still be compiled, and execution of the command will continue.
First of all, there are 3 types of plugins:
config
- modifies gluestick and webpack configs,for both server and clientruntime
- bundled into JavaScript bundles and executed when final output is being renderedserver
- bundled into renderer (server) bundle and executed when renderer starts
A plugin must implement at least one type, but can have multiple types specified.
To implement a type, you must create a file in the top level of the plugin directory and name
it: <type>.js
so it can be: config.js
, runtime.js
, server.js
.
IMPORTANT: GlueStick won't transpile your plugin, thus it's up to you to transpile it using, for instance, babel
or typescript
.
Must export a function that returns an object with postOverwrites
.
module.exports = (options, { logger }) => {
return {
postOverwrites: {
gluestickConfig: config => config,
clientWebpackConfig: config => config,
serverWebpackConfig: config => config,
},
};
};
The postOverwrites
factory function accepts options that are defined in the plugins declaration file inside the project,
by default src/gluestick.plugins.js
. The second argument is an object with utilities provided by
gluestick:
logger
- logger instancelogger.debug(...args)
logger.info(...args)
logger.success(...args)
logger.warn(...args)
logger.error(...args)
requireModule
- safe require function, which will transform the module with babel (es2015
,stage-0
,transform-flow-strip-types
) then noralizes module withgetDefaultExport
requireWithInterop
- require and normalize module usinggetDefaultExport
getDefaultExport
- normalize CJS and ESM exported value
postOverwrites
are executed after every config is prepared, so modifications to configs will
go directly to webpack compiler. Modification done here won't be taken into considiration by
uniwersal-webpack. This is the place for isomorphic-like things.
gluestickConfig: config => config
- accepts gluestick config and must return the same valid gluestick config with modified valuesclientWebpackConfig: config => config
- accepts the client webpack config and must return a valid webpack config for client bundleserverWebpackConfig: config => config
- accepts the server webpack config and must return a valid webpack config for the renderer (server) bundle
Server plugins, similarly to config plugins, must export a factory function, that accept options and gluestick utils.
module.exports = (options, { logger }) => ({
renderMethod: (root) => ({
body: '...',
head: [],
additionalScript: []
}),
hooks: {}
});
module.exports.meta = { name: 'gluestick-plugin-myplugin' };
This factory function must return object with implementation of renderMethod
or with a hooks
object that contains any of these hooks.
By default, gluestick will try to get name of the plugin from the meta
property set on the exported factory
function, then from the factory function name property. If it does not find any name, it will use
unknown
. It's recommended to set the name
of the plugin in the meta
property, so when
calling gluestick start
or gluestick start-server
it will print your plugin name,
along with other compiled plugins. The name
property will also be used when there is an
error in plugin implementation to create a helpful, user friendly message.
renderMethod
is useful for supplying a custom function to use when rendering the app on the server.
It only accepts one argument with the react root component to render and must return an object
with a body
property with the actual string that will be sent to the browser, head
array with React
elements that will be injected into the <head>
of the document and optionally additionalScript
,
which also is an array of React <script>
elements to inject into the document.
Runtime plugins are a little bit different, since they don't export factory a function, but must return an object with 2 properties:
meta
- an object with meta information, you must specifiy if the plugin is arootWrapper
or ahook
. You must provida exactly one flag in themeta
object:
const meta = { rootWrapper: true };
or
const meta = { hook: true };
plugin
- a function with plugin implementation
Depending on what flag is set, the plugin
function will look slightly different:
- if
rootWrapper
istrue
:
const plugin = (component, rootWrapperOptions) => component;
where component
is a root app component, rootWrapperOptions
is an object, which currently
has only one property - userAgent
which is equivalent of window.navigator.userAgent
(client) or
user-agent
header from request (server). In this case the plugin
function must return a valid
React component. Typically the component
argument will be wrapped with some other component.
- if
hook
istrue
,plugin
will be an argument-less function of which the returned value will be discarded.
Example:
import React from 'react';
import SomeRoot from 'some-lib';
export default {
meta: { rootWrapper: true },
plugin: (component, rootWrapperOptions) => {
return (
<SomeRoot userAgent={rootWrapperOptions.userAgent}>
{component}
</SomeRoot>
);
},
};