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

[p5.js 2.0 RFC Proposal]: Minimize bundle sizes #6776

Open
3 of 21 tasks
nickmcintyre opened this issue Jan 28, 2024 · 14 comments
Open
3 of 21 tasks

[p5.js 2.0 RFC Proposal]: Minimize bundle sizes #6776

nickmcintyre opened this issue Jan 28, 2024 · 14 comments

Comments

@nickmcintyre
Copy link
Member

Increasing access

Reducing the size of the built p5.js library would increase access to people without high-speed connections or large data plans. Doing so would also reduce power consumption from data transfer and parsing.

Which types of changes would be made?

  • Breaking change (Add-on libraries or sketches will work differently even if their code stays the same.)
  • Systemic change (Many features or contributor workflows will be affected.)
  • Overdue change (Modifications will be made that have been desirable for a long time.)
  • Unsure (The community can help to determine the type of change.)

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

What's the problem?

Accessibility

p5.js is currently 1MB minified. For comparison, that's about the same size as the minified versions of D3 and three.js combined.

p5.js is currently 4.8MB unminified. For comparison, that's about 2.5x the size of the unminified versions of D3 and three.js combined.

In The "why" of web performance, MDN lays out very plainly how performance impacts accessibility, especially for folks with fewer resources. Their case study focuses on websites with large data transfer requirements. @GregStanton also made the case for considering performance through the lens of accessibility.

Overall, it seems likely that we can trim several hundred KB from the built library.

Sustainability

As a side note, @GregStanton also mentioned global considerations. Big +1. I've suggested elsewhere that the new p5.js website should follow the Web Sustainability Guidelines.

Our creative medium has very direct and measurable environmental impacts (see Sustainable Web Design). Those impacts tend to make underlying social issues worse. So, I believe we should do our best to minimize them. I'd be more than happy to serve as a sustainability steward if people are open to the idea.

What's the solution?

I propose minimizing the data transfer required to code with p5.js and to view sketches. This could include a few related efforts.

Default to a minified build

It’s not clear that anyone studies the unminified p5.js bundle. The original use case may no longer be relevant, or at least it’s extremely niche. It also takes a JavaScript expert to understand the transformed source code in the unminified bundle. Even though the inline reference comments appear in place, a curious beginner or even a seasoned developer would have a hard time getting much use out of them.

If someone wants to study the p5.js source code, they can follow links from the FES/Reference to this repo.

A minified FES build could work in the p5.js Web Editor.

Refactor/rewrite using ES6+

Since we already plan to refactor, I propose making a concerted effort to trim all bundles as we do so. We can make the source code more accessible to developers while making the built library more accessible to users. I believe these efforts are complementary.

Can we thoughtfully choose JavaScript features that are more concise and expressive, and that won't require polyfills?

Change the build target

Modern JavaScript can make the p5.js source code more concise and expressive. It'd be nice if that translated into smaller bundle sizes, which means avoiding polyfills where possible. A few questions about browser and JavaScript versions come to mind:

  • What are the minimum browser and JavaScript versions needed to support all functionality in the core library?
  • What percentage of those browsers can p5.js reasonably expect to support?
  • Should p5.js support all potentially compatible browsers? What's our criteria?

Consider removing opentype.js

This dependency accounts for >15% of the minified p5.js bundle. Do we need it, strictly speaking? Could some advanced features be implemented as an add-on library?

Pros (updated based on community comments)

TBD

Cons (updated based on community comments)

TBD

Proposal status

Under review

@davepagurek
Copy link
Contributor

I think this is a good goal!

In addition to the efforts you already mentioned, I think the biggest thing we can do in service of this is to make parts of p5 optional to include, which I believe is part of the plan in the current 2.0 proposal. For example, Opentype.js is currently required for rendering fonts in WebGL (not necessary, but it will take some R&D to see if other approaches are truly feasible. There's more discussion in #6391 if you're curious!) But it's only required for WebGL, and if you need to use textToPoints. I think a good approach might be to default to a more minimal build, and for some functionality like WebGL fonts or textToPoints, one has to also include another p5 file related to that functionality. To me this feels like an approach that lets us grow our feature set without imposing the size cost of all those features upon everyone. How does something like that sound to you?

@curran
Copy link

curran commented Jan 31, 2024

I came across this issue as well. It would be great to get the build size down. I wonder what is causing it...

image

This might be useful in tracking down what made it large:

image

https://bundlephobia.com/package/p5@1.9.0

@davepagurek
Copy link
Contributor

I made a fresh build and sent it through disc to analyze its contents. I've attached the output: it's an html file that you can open in the browser after unzipping: disc.html.zip Here's a brief summary:

Screenshot 2024-01-30 at 8 57 19 PM

so, some observations:

  • webgl is big -- it has a lot it has to do in order to provide an API at a similar abstraction level to 2D mode, and its scope has been increasing in the past few versions in order to fill some gaps, which I'm pretty sure is the growth present in the package size graph. However, barely any of that is useful for 2D sketches. this is the kind of thing that could be a big win if it were made an optional import.
    • The biggest chunk is RendererGL.js. I think this might be because of the included shader source code? Maybe we could look into doing some GLSL minification, e.g. to shrink down the variable names to single letters.
  • opentype.js is a big dependency. do we have any alternatives that provide just parsing of font files into path data? at the very least, this could be made optional too, as not even WebGL mode strictly requires it unless you need to render text.
  • core-js is, I think, polyfills? we could reexamine how necessary this is for more recent browsers, and maybe make it also optional for more backwards compatibility.
  • the docs folder includes parameter checking info for FES, which I believe is not present in minified builds already. It would be cool if there were a more minimal way to include this in minified builds too, but you can see why we currently exclude it.

@nickmcintyre
Copy link
Member Author

I think a good approach might be to default to a more minimal build, and for some functionality like WebGL fonts or textToPoints, one has to also include another p5 file related to that functionality.

Agreed this seems like an easy win. Most intro classes I'm aware of stick to 2D the entire time. When someone's ready for WebGL, they shouldn't have much trouble following a quick guide to include another file or two.

What do you think about having createCanvas(400, 400, WEBGL) raise a friendly error if p5.webgl.js (or whatever) hasn't been included? The same could go for text() in WebGL mode.

@davepagurek
Copy link
Contributor

I think that would be good! Like maybe in general we can keep around stubs of all the core methods, but where they only throw a friendly error telling you to add a script tag for that other feature.

Also, in case anyone's curious, here's that same visualization as above, but on p5.min.js. It's basically the same, but the docs folder is gone.
disc-min.html.zip

@curran
Copy link

curran commented Jan 31, 2024

The pattern is already there for the sound module. I think it would be excellent if all the WebGL-related things were chunked out into a similar external file.

image

@lee2sman
Copy link

Thanks for introducing this idea. It makes sense to explore minimizing bandwidth, for exactly the reasons you specified. I'm also thinking about the great paper Permacomputing Aesthetics: Potential and Limits of Constraints in Computational Art, Design, Culture by Aymeric Mansoux, Brendan Howell, Dušan Barok, and Ville-Matias Heikkilä, which seems relevant here.

Questions:

  • If WebGL was pulled out as a separate file, how large would its filesize be currently?
  • Going the other direction: if it's not considered desirable to remove webgl from the main p5.js file, potentially there could be an added "slim" p5 (or maybe some other non-ablist language. reduce?) that is p5 minus webgl?

@mvicky2592
Copy link

@lee2sman There is a project like this already. "q5" that's just a reimplementation of p5.js' 2D api and doesn't have any other dependencies, though unfortunately it lacks friendly error support.

https://github.com/quinton-ashley/q5.js/

@limzykenneth limzykenneth moved this to Proposal in p5.js 2.0 May 28, 2024
@limzykenneth
Copy link
Member

limzykenneth commented Jun 16, 2024

I've added Rollup bundle analyzer to the dev-2.0 branch and the output result of the main minified bundle is available here: stats.zip and a screenshot below:

Screenshot 2024-06-16 at 20-32-27 Rollup Visualizer

As suspected, the largest components currently taking up space are the FES parameter validation data and opentype.js. I would say while WebGL is significant at about 25% of the remaining file size, we'll gain better file size reduction with the two mentioned, which we already have proposals to refactor already.

@mvicky2592
Copy link

@limzykenneth thanks for this visual!

Open type is only necessary for webgl right? So webgl+opentype take up like 40%. Indeed, FES seems to be the next largest segment.

It'd be great if for p5.js v2.0 webgl and fes could be split into separate modules, then a smaller ~500kb bundle could be made.

Where is the FES parameter validation data located in the repo?

@Qianqianye Qianqianye self-assigned this Jun 18, 2024
@dhowe
Copy link
Contributor

dhowe commented Jun 20, 2024

Opentype is only necessary for webgl right?

This is not strictly true. All the functionality provided by p5.Font currently relies on opentype, including loading of custom fonts, calculation of bounding-boxes, and textToPoints(). This is not to say that much of this can't be replaced with newer browser-native features, but at least webgl text, textToPoints, and tight bounds will require font path data, for which there appears to be no great substitute at moment. Additionally it will require significant code and extensive testing to safely eliminate this dependency (this is not to say that it shouldn't be done).

@dhowe
Copy link
Contributor

dhowe commented Jun 20, 2024

To finish, as I've said elsewhere, I think textToPoints could happily exist as an external library, expecially as it doesn't exist in Processing at moment (though I did implement it in Processing 3) which would potentially allow webgl+opentype (or some subset of it) to be refactored into a module outside the core... But again, removing opentype from the core is not a small job

@davepagurek
Copy link
Contributor

I think there's a world where we make a "text metrics" module that can optionally be bundled into p5, or not loaded if it isn't used, similar to what we've been trying to do with math. Still nontrivial work, but maybe a more reasonable goal.

Maybe a question for the typography refactor issue instead of this one, but I'm curious how close native 2D canvas's text measuring APIs are to meeting the bounding box needs? They definitely don't do points on paths though.

@dhowe
Copy link
Contributor

dhowe commented Jun 20, 2024

Maybe a question for the typography refactor issue instead of this one, but I'm curious how close native 2D canvas's text measuring APIs are to meeting the bounding box needs? They definitely don't do points on paths though.

I believe we can get quite close, we just can't do tight bounds, which depends on paths/points. This is not a big deal except for things like precise collision detection, but again this could be part of a library or module

@Qianqianye Qianqianye moved this from Proposal to Implementation in p5.js 2.0 Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Implementation
Development

No branches or pull requests

8 participants