Style-dictionary: [RFC] Plugin Architecture

Created on 10 Jul 2019  Â·  3Comments  Â·  Source: amzn/style-dictionary

✨ Request for comments ✨

This is something we have been talking about informally and in some issues (#262, #266, #268). We don't want to try to build in so many transforms, formats, and actions into the core library that it becomes hard to maintain and bloated. Also, we want others to be able to share their solutions so others can use them in an easy way. Some transforms, formats, actions can be useful to some, but might not be general enough to build into the core library. Also, all the built-in transforms and formats assume the 'CTI' structure, which not everyone uses. This will give an opportunity to share transforms and formats that work with other organizational structures. @elliotdickison had some great comments on this in #102 as well.

Imagining Webpack and Gatsby plugins. There are many that the core library vends, but also plenty of ones the community builds and maintains. So it is easy to get started, but we don't have to try to do everything to make everyone happy.

Also, "plugin" is just the first word that came to mind, they don't necessarily have to be called "plugins".

It would work like this:

const StyleDictionary = require('style-dictionary');
const StyleDictionaryPlugin = require('style-dictionary-plugin');

StyleDictionary
  .extend( StyleDictionaryPlugin )
  .extend({
    // config
  })
  .buildAllPlatforms();

You could also export an object and use the style-dictionary build CLI:

// config.js
const StyleDictionary = require('style-dictionary');
const StyleDictionaryPlugin = require('style-dictionary-plugin');

StyleDictionary.extend( StyleDictionaryPlugin );
module.exports = {
  // config
}

$ style-dictionary build --config ./config.js

Where the 'style-dictionary-plugin' module exports an object of this form:

module.exports = {
  transform: {
    myCustomTransform: {
      type: 'value',
      matcher: () => {},
      transformer: () => {}
    }
  },
  transformGroup: {
    myCustomTransformGroup: ['myCustomTransform']
  },
  format: {
    myCustomFormat: () => {}
  },
  action: {
    myCustomAction: {
      do: () => {},
      undo: () => {}
    }
  }
}

Technically, this ability exists today, but we don't document or promote this ability yet. So if we wanted to we could start using this architecture today, or if we want to change how it works it would not be that much work.

Good idea, bad idea, unnecessary idea, crazy idea?

Core Architecture discuss

Most helpful comment

Love this idea, for our implementation of SD we've done a lot of custom stuff on top and would be great to be able to package this up.

All 3 comments

I like this drop in capability a lot!

My only thought is that extend really gives access to the entire system - so it provides a lot more functionality than you have shared here. I'm okay with this, but we need to make it clear that plugins can basically take over the entire system, and that this could cause conflicts if multiple plugins are loaded.

Alternatively, we could create a different .loadPlugin() function as a wrapper with some hygiene capability to ensure that we only import the specific properties specified. I'm not sure this has value, but it is one method to avoid contamination. Not sure if this is "thinking ahead" or "unnecessary concern that removes valuable functionality".

Love this idea, for our implementation of SD we've done a lot of custom stuff on top and would be great to be able to package this up.

To build on @chazzmoney's comment, technically right now you can override core Style Dictionary behavior. For example you can change the internal .buildPlatform method:

const StyleDictionary = require('style-dictionary');

StyleDictionary.extend({
  buildPlatform: () => { /* mess up this internal function */ }
});

This could serve a good purpose if you want to say log metrics or do something extra in addition to what Style Dictionary is doing. So maybe this is a good thing if you know what you are doing? Anything exported in this file is fair game to override or extend: https://github.com/amzn/style-dictionary/blob/master/index.js and it does a deep extend so for nested objects you are safe.

One potentially good thing, is upon inspection the internal methods that are not exposed on the module like .buildFile for example are not overridable right now because they are imported directly in the places they are used.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tlouisse picture tlouisse  Â·  4Comments

gael-boyenval picture gael-boyenval  Â·  3Comments

valiksb picture valiksb  Â·  4Comments

johnny353535 picture johnny353535  Â·  3Comments

chazzmoney picture chazzmoney  Â·  5Comments