p5.js
p5.js copied to clipboard
[p5.js 2.0] ESM usage in global mode
Increasing access
existing feature in v2
Most appropriate sub-area of p5.js?
- [ ] Accessibility
- [ ] Color
- [x] Core/Environment/Rendering
- [ ] Data
- [ ] DOM
- [ ] Events
- [ ] Image
- [ ] IO
- [ ] Math
- [ ] Typography
- [ ] Utilities
- [ ] WebGL
- [ ] Build process
- [ ] Unit testing
- [ ] Internationalization
- [ ] Friendly errors
- [ ] Other (specify if possible)
Feature enhancement details
In issue #7332 @limzykenneth wrote:
p5.js 2.0 will support ESM and due to the nature of ESM, sketches have to be written in instance mode. The way we are testing and iterating in 2.0 development is using an ESM sketch.
I understand that since functions declared in a module are not attached to the window, only the module's scope, users would have to define functions using the p5 v2 instance.
Yet, p5 v2 could otherwise start in global mode by attaching p5 instance functions and variables to window, which would make them top-level accessible in the module.
Ideally global mode would be the default when p5 v2 is used in an ESM module, or at least it should be an option, otherwise all p5 functions and vars would need to be instance prefixed.
I'm planning on making q5.js WebGPU top level global mode in an ESM the default way to use q5play (upcoming sequel to p5play), so it'd be great if p5 v2 supported this as well.
Hi @quinton-ashley, additional to opening this one up for discussion, from reading the https://github.com/processing/p5.js/issues/7332 it seems like the most immediate and valuable next step is better documentation for instance mode. Seems straightforwardly a good idea for improving related documentation, so I made this task on the website in the meantime: https://github.com/processing/p5.js-website/issues/754
In this issue, I think what would be most helpful is to understand whether this (lack of global mode with ESM usage in particular) is a general challenge for users of p5.js, or more specific to q5.js.
So, for those reading - please do chime in with your thoughts, especially if you have some personal experience of being confused with global vs instance mode at some point! What would be helpful to reduce that confusion?
I've had discussions with other creative coders about loading ESM modules before and that confused a few of us. The workaround was not obvious to me. So much so that I made this heavily commented example to explain it to myself and others. Generally speaking, coming from Processing (or p5.js 1.0 for that matter), the intricacies of modern JS can be daunting at first.
@ksen0 I would say for this issue, I just added the part about q5play for personal context, but it's irrelevant to this being a limitation on the usability of p5.js v2 in an ESM.
Sorry, I should've also linked to this page that explains the benefits of top-level global mode in greater detail.
https://github.com/q5js/q5.js/wiki/Top%E2%80%90Level-Global-Mode
I understand that p5's global mode causes a lot of so-called global namespace "pollution", which is a problem when using web building frameworks or other libraries outside the p5 ecosystem, which can have functions with the same name as p5's, known as function overlap. Thus, most professional JS developers seem to prefer p5's instance mode.
CS Educators basically never have a reason to use instance mode, and I doubt most of them even know it exists. When sticking to addons within the p5 ecosystem that don't trample on the names of p5's functions, global namespace "pollution" is a non-issue.
Also up until @davepagurek showed how p5 can do namespaced instance mode, I'd only ever seen function scoped instance mode documented and used, see related issue #7332
Currently this throws an error just by using new p5() which I reported in #7678
let p = new p5();
p.setup = () => {
createCanvas(200, 200);
};
p.draw = () => {
rect(mouseX, mouseY, 100, 100);
};
Thanks @SableRaf for the valid workaround:
let p = window;
p.setup = () => {
createCanvas(200, 200);
};
p.draw = () => {
rect(mouseX, mouseY, 100, 100);
};
Thanks @SableRaf for the valid workaround
Giving credit where credit is due: the workaround was actually from @davepagurek. I just made the minimal commented example to understand it better :)
Added this to a draft issue related to global mode documentation: https://github.com/orgs/processing/projects/21/views/8?pane=issue&itemId=107924677 - draft because I am not yet sure what the scope of that issue should be.
If the workaround above is made more clear in a more central global mode usage documentation, would that address this issue specifically @quinton-ashley ? Has this workaround still been working out for you for the past month?
@ksen0 I think it's an awkward workaround. Ideally new p5() would return the p5 instance and not the entire window by implementing #7737
But even just having new p5() with no arguments return window would be better.
@davepagurek Thoughts?