mavoweb / treecle

WIP. A toolbox for hierarchical JS objects.
https://treecle.mavo.io
MIT License
6 stars 0 forks source link

How to allow different configurations to co-exist? #1

Closed LeaVerou closed 6 months ago

LeaVerou commented 6 months ago

Currently, which properties are child properties and what values are nodes are functions that live in src/config.js. The workflow being that authors would import that and override its properties.

The issue with this workflow is that currently you can only have one configuration. Given how generic Treecle is, it makes sense to allow different configurations to co-exist.

There are several solutions to this, each with its own pros and cons:

  1. A Treecle class. This is the most obvious option for facilitating different configurations, however it will be a pain to facilitate tree-shaking with it (we'd need to support both the separate functions and the class, and write the function code in such a way that it works for both (e.g. let myConfig = this.config ?? config).
  2. Add an optional config argument or option to functions that allows overriding the global config (either entirely or for specific properties). The downside is inconsistency, since functions have different signatures and we cannot have this in the same place for every single one.
  3. A combination of 1 and 2, where people can use an object with a config property as the context of a function to provide a custom config. I.e.
    let c = { context: {...}};
    walk.call(c, tree, callback);

    This allows us to essentially accept it as an argument without it affecting the function signatures. And bonus, if we decide to do 1, the code is already there. The downside is verbosity (4 extra characters per call) and …weirdness.

adamjanicki2 commented 6 months ago
  1. A Treecle class. This is the most obvious option for facilitating different configurations, however it will be a pain to facilitate tree-shaking with it (we'd need to support both the separate functions and the class, and write the function code in such a way that it works for both (e.g. let myConfig = this.config ?? config).

Can you explain a little more on tree shaking? If there's a way to make this work, I think this is the best option by far. We can have a Treecle class, and it has a bunch of static methods (implementing all of the tree functionality), and it can have instance variables for the config, which it tries to use if they're set and otherwise falls back to the default ones, that way you could do either Treecle.transform(...) // uses default settings or

const treecle = new Treecle(....some custom settings);
treecle.transform(...); // uses custom settings
LeaVerou commented 6 months ago

Can you explain a little more on tree shaking?

Authors import individual functions, and when they create a bundle, the bundle only creates the parts of treecle they are actually using. If all functions hang on a class, then it's a monolith: either you import the whole class or none of it.

What we did in Color.js is we define each function in its own module, and it can be used independently, then we also define a Color class that transforms these functions into instance methods.

adamjanicki2 commented 6 months ago

Ah makes sense, can we just use the same hybrid approach?

LeaVerou commented 6 months ago

Ah makes sense, can we just use the same hybrid approach?

Sure. In fact, I think it would actually be more convenient to do 3 + 1, and then people could even use custom configs and tree-shaking.

adamjanicki2 commented 6 months ago

Doing 3 seems pretty annoying to have to check the context in every function; what if we went with the same approach as color.js for now and expand to adding option 3 if sufficient use cases require it?

LeaVerou commented 6 months ago

We'd have to do something to get the config. We can't just use this.config in the individual functions, and we can't use config either. Color.js does not really have this problem.

It could be as simple as

let config = this?.config ?? defaultConfig;

We could even specify these as direct properties of the class, in which case it would be:

let config = this ?? defaultConfig;
adamjanicki2 commented 6 months ago

We'd have to do something to get the config. We can't just use this.config in the individual functions, and we can't use config either. Color.js does not really have this problem.

It could be as simple as

let config = this?.config ?? defaultConfig;

We could even specify these as direct properties of the class, in which case it would be:

let config = this ?? defaultConfig;

Yeah sorry I think I misspoke, I think having something like let config = this ?? defaultConfig; is not a big deal, I was referring to it being annoying to have to have context as an argument of every single function

LeaVerou commented 6 months ago

Closed via https://github.com/mavoweb/treecle/commit/b9deb2f594695604ebea19c000095a1ef4c0359b (forgot to mention this issue)