--- title: Plugin guide --- Plugins allow you to extend FreeSewing with new features and functionality. A FreeSewing plugin can extend FreeSewing in 3 different ways: - It can [provide macros](#macro-methods), which are a way to automate a number of steps into a single command. - It can [hook into the pattern](#lifecycle-hook-methods), which allows you to manipulate the pattern or interact with it at various stages of it's lifecycle. - It can [provide store methods](#store-methods), which allows you to add new ways to handle data in the pattern, including providing a custom logger. We have [a list of plugins](/reference/plugins/) that we maintain, but if you can't find what you're looking for, you can write your own plugin. If you plan on doing that or if you would like to understand how plugins work, this guide is for you. ## Plugin structure A FreeSewing plugin is a plain object with the following structure: ```mjs Object plugin = { String name, String version, Object hooks, Object macros, Array store, } ``` A plugin **must** have the `name` and `version` properties. The other properties are optional, and they map to the three different functionalities macros can provide: - [`hooks`](#lifecycle-hook-methods): Holds an object with lifecycle hooks the plugin wants to hook into - [`macros`](#macro-methods): Holds and object with macros the plugin provides - [`store`](#store-methods): Holds and Array with store methods the plugin provides. Click on the links above for more details on the structure of these properties. ## Lifecycle hook methods FreeSewing plugins can provide hooks, which is a way to hook into the pattern's lifecycle. ### Signature To provide one or more hooks, your plugin should have a `hooks` property that is an object where the keys are the lifecycle hook name and the value holds a method. When the lifecycle hook is triggered, your method will be called. ```mjs const myPlugin = { name: 'example', version: '0.0.1', hooks: { hookName: function (obj, data = {}) { } } } ``` If you want to attach multiple methods to the same lifecycle hook, you can pass them as an array: ```mjs const myPlugin = { name: 'example', version: '0.0.1', hooks: { hookName: [ function one (obj, data = {}) { }, function two (obj, data = {}) { } ] } } ``` ### Arguments All lifecycle methods will receive two parameters: - An object relevant to the lifecycle hook. See the [hooks API reference](/reference/hooks/) for details. - Data passed when the hook was registered (optional) ### Notes Refer to the [hooks API reference](/reference/hooks/) for a list of all available lifecycle hooks. ## Macro methods FreeSewing plugins can provide macros, which is a way to automate multiple steps into a single command. ### Signature To provide one or more macros, your plugin should have a `macros` property that is an object where the keys are the macro name, and the value holds a method to run when the macro is executed. ```mjs const myPlugin = { name: 'example', version: '0.0.1', macros: { example: function(so, { log }) { log.info('Running the example macro') } } } ``` ### Arguments All macros receive two arguments: - `so`: A plain object holding configuration object passed to the macro - `props`: The same object as passed to the [`Part.draft()`](/reference/api/part/draft) method that you can destructure :::note Macros take only 1 argument When writing a macro, keep in mind that all information that needs to be passed to a macro needs to be contained in a single argument. Typically, you use a single plain object to configure the macro. ::: ### Return value Macros do not need to return anything. If they do, it will be ignored. ## Store methods FreeSewing plugins can provide store methods, which facilitate data handling within a pattern. ### Signature To provide one or more store methods, your plugin should have a `store` property that is an array where each member is itself an array with two members: - The first member holds the key to attach the method to (in dot notation) - The second member holds the method to attach ```mjs const myPlugin = { name: 'example', version: '0.0.1', store: [ [ 'log.panic', function(store, ...params) { store.setIfUnset('logs.panic', new Array()) store.push(...params) } ] } } ``` ### Arguments All store methods receive at least two arguments: - `store`: The store object itself - `...params`: All additional plugins that were passed to the store method ### Overwriting store methods You are allowed to overwrite existing store methods. As it happens, this is how you should implement a custom logging solution, by overwriting the logging methods under the store's `log` key, However, the following store methods cannot be overwritten: - `extend()` - `get()` - `push()` - `set()` - `setIfUnset()` - `unset()` ### Return value Store methods do not need to return anything. If they do, it will be ignored. ## Loading plugins Plugins can be loaded at build time and added to the design. Or, they can be added at run time and added to an instantiated pattern. To load a plugin at build time, it should be added to [the `plugins` key of the part configuration](/reference/api/part/config/plugins). To load a plugin at run time, it should be loaded with a call to [`Pattern.use()`](/reference/api/pattern/use). Please refer to the relevant documentation for more details.