Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove side-effects from spaces #184

Merged
merged 18 commits into from
Jul 5, 2022

Conversation

sgomes
Copy link
Collaborator

@sgomes sgomes commented Jun 30, 2022

Following the discussion in #163 and #183, this (starts to) implement an approach laid out by @LeaVerou to remove the usage of side-effects in spaces, and make them available externally in a tree-shakeable way:

I think probably the best way forwards is:

  • Color spaces drop side effects
  • spaces/index-fn.js imports and re-exports all of them
  • index-fn.js imports and re-exports spaces/index-fn
  • spaces/index.js imports everything from spaces/index-fn.js and registers it calling ColorSpace.register()

Please let me know what you think!

Aside: my editor seems to be adding newlines at the end of files. Please let me know whether I should change my config to stop that from happening!

@sgomes sgomes requested a review from LeaVerou June 30, 2022 12:00
src/spaces/index.js Outdated Show resolved Hide resolved
@LeaVerou
Copy link
Member

Aside: my editor seems to be adding newlines at the end of files. Please let me know whether I should change my config to stop that from happening!

I'm fine with that!

package.json Outdated Show resolved Hide resolved
src/spaces/index.js Outdated Show resolved Hide resolved
@LeaVerou
Copy link
Member

Looking good so far!

src/space.js Outdated

if (this.aliases) {
for (let alias of this.aliases) {
this.registry[alias] = space;
Copy link
Member

@LeaVerou LeaVerou Jun 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The id for the color() function should be decoupled from aliases. In the case of XYZ it happens that the alias is also an id for color(), but not sure this should be enforced by the API

(ignore any previous comments, I had misread)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, that's a good point, thank you! Sounds like space aliases need to be separate from color ID aliases 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what should be the expected behavior if one registers two spaces with the same id or alias? Right now each one will overwrite the previous one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing a runtime error seems like the best bet to me. Having a unit test that checks to make sure there aren't any such errors on the full lib should then be enough to make sure the build doesn't break.

How does that sound?

Copy link
Collaborator Author

@sgomes sgomes Jun 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a proposed runtime validation mechanism to 2a6176b, please let me know what you think!

Oh, and please feel free to bikeshed things like idAliases, as I'm not sure that's the best name 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about a runtime error, users should be able to call register() multiple times from different parts of the code to register the same color space. Though perhaps we could only throw the error if the color space object is different.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I totally agree that it shouldn't error out if registering the same space multiple times. The code should be doing that already, but do let me know if I missed something!

@sgomes sgomes force-pushed the sgomes/remove-side-effects-from-spaces branch from 466027b to 05bdd32 Compare June 30, 2022 16:21
package.json Outdated Show resolved Hide resolved
src/space.js Outdated Show resolved Hide resolved
src/space.js Outdated
}
}

this.validateIds();
Copy link
Member

@LeaVerou LeaVerou Jun 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like detailed errors as much as the next person, but checking that deeply seems a little too much. I'd skip this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean we should forgo the ID check altogether? I think that's okay. As far as I can tell, if there is a collision, it'll simply use the first match, which is probably an acceptable behaviour?

src/space.js Outdated
this.registry[id] = space;
return space;
}
this.addToRegistry(id, space);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a separate method? When somebody is using the register(id, space) signature, we should not be registering any additional things like aliases. So all we need to do is preserve what signature was used. Then we can recursively call it to register a color space with each alias, and still only have the checking code in one place.

Copy link
Collaborator Author

@sgomes sgomes Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm not entirely sure I understand 😕

Do you mean that we should't have the aliases as part of the color space definition (space.aliases), and we should instead delegate the responsibility of registering the alias to the consumer? Or do you mean that we should simply call register recursively from within itself, and keep the responsibility of registering aliases within the ColorSpace class?

Copy link
Member

@LeaVerou LeaVerou Jul 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, there is a semantic difference between the two signatures. If someone calls ColorSpace.register("foobar", mySpace) they intend to register mySpace under the "foobar" alias, and not do any other registration. E.g. someone may import a color space and want to register it with a different id altogether. If they do ColorSpace.register(mySpace), then it makes sense to register it with its id and aliases.

This also means that we can use it that way internally: When ColorSpace.register() is used with a single argument, we can internally call ColorSpace.register(id, space) as well as ColorSpace.register(alias, space) for every alias, thus not needing a separate function for this.

Does it make sense now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, thank you for clarifying that! Yes, that sounds like a good approach 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

@@ -10,8 +10,9 @@ export default new ColorSpace({
},
white: "D65",
formats: {
color: {}
color: {
ids: ['xyz'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably add both, for clarity

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

package.json Outdated Show resolved Hide resolved
src/spaces/index.js Outdated Show resolved Hide resolved
@sgomes
Copy link
Collaborator Author

sgomes commented Jul 4, 2022

Do you think this is ready to move forward to full implementation across all color spaces, @LeaVerou?

}

// ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to re-export!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, do we want to re-export from this file as well? No problem, can do 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, as people who want side effects might still need a reference to one of the color spaces (and it costs nothing to re-export so why not).

@LeaVerou
Copy link
Member

LeaVerou commented Jul 4, 2022

Yes! 😄

@sgomes sgomes force-pushed the sgomes/remove-side-effects-from-spaces branch from 8eb9353 to 48662b2 Compare July 4, 2022 13:24
@sgomes
Copy link
Collaborator Author

sgomes commented Jul 4, 2022

I've applied this to all color spaces, and rebased on main. I think this is ready for review!

@sgomes sgomes marked this pull request as ready for review July 4, 2022 13:39
@sgomes
Copy link
Collaborator Author

sgomes commented Jul 4, 2022

Also, please let me know if there's anything missing with regards to documentation, testing, and the like!

@LeaVerou
Copy link
Member

LeaVerou commented Jul 4, 2022

Thank you! The testsuite is in a state of disarray right now, but have you checked that all passing tests still pass? (I just pushed some fixes so you'd need to rebase first)

@sgomes sgomes force-pushed the sgomes/remove-side-effects-from-spaces branch from 48662b2 to e7ccf12 Compare July 4, 2022 14:02
@sgomes
Copy link
Collaborator Author

sgomes commented Jul 4, 2022

Thank you! The testsuite is in a state of disarray right now, but have you checked that all passing tests still pass? (I just pushed some fixes so you'd need to rebase first)

I did try to run the tests, but even after rebasing from main again I'm still getting 404s on resources from raw.githubusercontent.com. Perhaps I'm missing something? I'm not entirely sure how to actually go about running the tests; all I tried was to open tests/index.html locally.

@sgomes sgomes changed the title Draft: remove side-effects from spaces Remove side-effects from spaces Jul 4, 2022
@LeaVerou
Copy link
Member

LeaVerou commented Jul 4, 2022

Thank you! The testsuite is in a state of disarray right now, but have you checked that all passing tests still pass? (I just pushed some fixes so you'd need to rebase first)

I did try to run the tests, but even after rebasing from main again I'm still getting 404s on resources from raw.githubusercontent.com. Perhaps I'm missing something? I'm not entirely sure how to actually go about running the tests; all I tried was to open tests/index.html locally.

Oh shit, you're right, the test harness is broken for users who are not logged in to GitHub. I'm on it, but it will take a while. Meanwhile you can try loading the different HTML pages individually (or log in). Sorry this is such a PITA. 😢

@sgomes
Copy link
Collaborator Author

sgomes commented Jul 4, 2022

Oh shit, you're right, the test harness is broken for users who are not logged in to GitHub. I'm on it, but it will take a while. Meanwhile you can try loading the different HTML pages individually (or log in). Sorry this is such a PITA. 😢

No worries at all 🙂

Looks like there are some issues to figure out on my end, namely with ordering; registering xyz-abs-d65 before xyz-d65 results in an error, because the former depends on the latter. We may have to go back to explicitly listing them (instead of naively looping over them) to maintain ordering, or instead being smarter about it and reordering at registration time.

@LeaVerou
Copy link
Member

LeaVerou commented Jul 4, 2022

Wait, does xyz-abs-d65 refer to xyz-d65 by id? It should import the color space and use that reference.

@sgomes
Copy link
Collaborator Author

sgomes commented Jul 5, 2022

Wait, does xyz-abs-d65 refer to xyz-d65 by id? It should import the color space and use that reference.

The issue isn't something that xyz-abs-d65 specifically is doing, but rather the ColorSpace constructor:

this.base = options.base ? ColorSpace.get(options.base) : null;

Since base is provided through an ID, and since ColorSpace.get relies on the color space registry, this fails during construction of the xyz-abs-d65 space.

One way of solving this would be by having base provide not the ID but the ColorSpace instance itself. What do you think, @LeaVerou?

@LeaVerou
Copy link
Member

LeaVerou commented Jul 5, 2022

Hi Sergio, yay! Also, the testsuite should be working now. Could you please check that the same number of tests passes before and after your changes?

@sgomes sgomes force-pushed the sgomes/remove-side-effects-from-spaces branch from 1538d00 to 337d4e2 Compare July 5, 2022 11:51
@sgomes
Copy link
Collaborator Author

sgomes commented Jul 5, 2022

I rebased and tested main vs this branch, and I get the exact same number of passes/failures for all tests 👍

Some of the tests still fail with 404s, this time from projects.verou.me, but everything seems to be the same before and after these changes.

@LeaVerou
Copy link
Member

LeaVerou commented Jul 5, 2022

I just fixed the tests to eliminate the 404, but the failing requests were for cosmetic things, so I don't think this affects anything here. I think I'm gonna go ahead and merge this! Thanks again!

@sgomes
Copy link
Collaborator Author

sgomes commented Jul 5, 2022

Woohoo, thank you @LeaVerou! 🎉

After these changes, the procedural API is looking quite good. To give you an example, here is a map for what gets included on a simple test case that just makes use of parse, serialize, ColorSpace (for registration), and the sRGB color space:

image

21 KB uncompressed / 8.4KB compressed is quite good, especially considering all the keywords are in there 🙂

@LeaVerou LeaVerou merged commit fdff000 into color-js:main Jul 5, 2022
@LeaVerou
Copy link
Member

LeaVerou commented Jul 5, 2022

This should be in the upcoming v0.3.0 release, hopefully later today, but failing that tomorrow.

@sgomes sgomes deleted the sgomes/remove-side-effects-from-spaces branch July 5, 2022 13:11
@LeaVerou
Copy link
Member

LeaVerou commented Jul 5, 2022

Btw what did you use to generate the graphic above? It's really cool!

@sgomes
Copy link
Collaborator Author

sgomes commented Jul 5, 2022

Btw what did you use to generate the graphic above? It's really cool!

It's the webpack-bundle-analyzer plugin. It's really handy, I use it all the time! 🙂

I created a little test project, set up webpack on it, and added the plugin to the webpack config. The only thing to note is making sure to disable module concatenation, otherwise it'll all be mangled up into one giant index.js.

Here's the full webpack config, if that helps!

const path = require('path');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new BundleAnalyzerPlugin()
  ],
  optimization: {
    concatenateModules: false
  }
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants