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 withgetDefaultExportrequireWithInterop- require and normalize module usinggetDefaultExportgetDefaultExport- 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 arootWrapperor ahook. You must provida exactly one flag in themetaobject:
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
rootWrapperistrue:
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
hookistrue,pluginwill 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>
);
},
};