p5.js
p5.js copied to clipboard
p5.js + NextJS compilation error
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)
p5.js version
1.9.0
Web browser and version
No response
Operating system
No response
Steps to reproduce this
Steps:
- add p5 to a nextjs
14.1.0
project - create a simple canvas with a bouncing ball
- run
npm run dev
to start the development server - the process is interrupted with an error:
$ next dev
▲ Next.js 14.1.1-canary.1
- Local: http://localhost:3000
✓ Ready in 2.2s
○ Compiling / ...
⨯ ./node_modules/p5/lib/p5.min.js
Module parse failed: Identifier 'o' has already been declared (7314:37)
| if (g ? x || (d = !0, w(), x = !0) : d = Boolean(o.first), t = Math.max(0, Math.floor(t)), r = Math.max(0, Math.floor(r)), d) {
| if (!a) throw new Error("First frame must include a { palette } option");
> var [o, h, f, p, m = 8] = [
| v,
| t,
Import trace for requested module:
./node_modules/p5/lib/p5.min.js
./app/p5-error.tsx
Snippet:
This is a fully working example on CodeSandbox which reproduces the problem:
https://codesandbox.io/p/sandbox/dry-tree-rnzjq9
PLEASE NOTE:
I have also raised this issue in the Next.JS repo:
https://github.com/vercel/next.js/issues/60897
Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, please make sure to fill out the inputs in the issue forms. Thank you!
I don't have an answer but I do have a bit more info. It's something to do with the bundling of external dependencies, or possibly a problem with the dependency itself.
I wanted to see what part of the code that is and what variable o
is before minification. It's in the loading_displaying
file where we have two external dependencies omggif
and gifenc
.
The throw new Error
on the line right above the compilation error is from the gifenc
package here:
https://github.com/mattdesl/gifenc/blob/64842fca317b112a8590f8fef2bf3825da8f6fe3/src/index.js#L85
The block of minified code is this:
function h(e = {}) {
const {initialCapacity: t = 4096, auto: g = !0} = e, v = E(t);
const b = new Uint8Array(256), j = new Int32Array(5003), _ = new Int32Array(5003);
let x = !1;
return {
reset() {
v.reset(), x = !1
}, finish() {
v.writeByte(a.trailer)
}, bytes() {
return v.bytes()
}, bytesView() {
return v.bytesView()
}, get buffer() {
return v.buffer
}, get stream() {
return v
}, writeHeader: w, writeFrame(e, t, r, o = {}) {
var {
transparent: n = !1,
transparentIndex: s = 0,
delay: i = 0,
palette: a = null,
repeat: l = 0,
colorDepth: u = 8,
dispose: c = -1
} = o;
let d = !1;
if (g ? x || (d = !0, w(), x = !0) : d = Boolean(o.first), t = Math.max(0, Math.floor(t)), r = Math.max(0, Math.floor(r)), d) {
if (!a) throw new Error('First frame must include a { palette } option');
var [o, h, f, p, m = 8] = [v, t, r, a, u];
p = F(p.length) - 1, m = 128 | m - 1 << 4 | p, M(o, h), M(o, f), o.writeBytes([m, 0, 0]), T(v, a), 0 <= l && (p = v, h = l, p.writeByte(33), p.writeByte(255), p.writeByte(11), C(p, 'NETSCAPE2.0'), p.writeByte(3), p.writeByte(1), M(p, h), p.writeByte(0))
}
var y, f = Math.round(i / 10), o = v, m = c, l = f, h = n, p = s,
i = (o.writeByte(33), o.writeByte(249), o.writeByte(4), p < 0 && (p = 0, h = !1), h = h ? (y = 1, 2) : y = 0, 0 <= m && (h = 7 & m), h <<= 2, o.writeByte(0 | h | y), M(o, l), o.writeByte(p || 0), o.writeByte(0), Boolean(a) && !d);
c = v, n = t, s = r, y = i ? a : null, c.writeByte(44), M(c, 0), M(c, 0), M(c, n), M(c, s), y ? (n = F(y.length) - 1, c.writeByte(128 | n)) : c.writeByte(0), i && T(v, a), [l, o, s, n, c = 8, i, a, e] = [v, e, t, r, u, b, j, _], S(s, n, o, c, l, i, a, e)
}
};
The specific line which is a problem is
var [o, h, f, p, m = 8] = [v, t, r, a, u];
Where we are defining an o
variable even though there is already an o
variable in scope.
That code corresponds somehow to the encodeLogicalScreenDescriptor
function?
https://github.com/mattdesl/gifenc/blob/64842fca317b112a8590f8fef2bf3825da8f6fe3/src/index.js#L181C10-L201
function encodeLogicalScreenDescriptor(
stream,
width,
height,
palette,
colorDepth = 8
) {
const globalColorTableFlag = 1;
const sortFlag = 0;
const globalColorTableSize = colorTableSize(palette.length) - 1;
const fields =
(globalColorTableFlag << 7) |
((colorDepth - 1) << 4) |
(sortFlag << 3) |
globalColorTableSize;
const backgroundColorIndex = 0;
const pixelAspectRatio = 0;
writeUInt16(stream, width);
writeUInt16(stream, height);
stream.writeBytes([fields, backgroundColorIndex, pixelAspectRatio]);
}
The variable o
which is an argument of writeFrame
is actually opts
, the options object. And then we get another variable o
which is unrelated, representing the stream
argument of encodeLogicalScreenDescriptor
. That variable should be scoped within that function, but it doesn't seem like there's a function in that part of the minified code? So I'm confused.
Seems like something went wrong with the minification of gifenc
but I don't know how or why that happens.
Hello @lindapaiste, so me let me understand, you are providing the minified code in your library. The interesting thing is that importing p5
in NextJS 14.0.4
is perfectly fine. When I have updated to 14.1.0
is when the problem started.
If nothing has changed on your side, the guys over at nextjs might have done some work on the bundler which has highlighted this problem. Unfortunately the issue I've opened there did gather interest from users that encountered this problem but not from the developers.
I'm not sure this is actually an error in the minification of p5, it's certainly not conventional code that a human would write, but I think it's valid to re-declare a variable in a different scope? e.g.:
function test(a) {
console.log(a)
var a = 2
console.log(a)
}
test(1)
/* Logs:
1
2
*/
I also ran into this issue and had some luck also just using a different nextjs version (13.5.6 broke for me but 13.5.1 didn't.) I think this is probably just a bug in swc that they use for compilation, and seemingly has something to do with some other internal state that changes from version to version?
If it helps, a quick test will be to turn off all optimizations (ie. minification) to see if the problem did stem from there. I don't use NextJS myself so it will take a bit more digging for me to know what's going on here.
Also generally using p5.js currently through npm installs are not tested and cannot be guaranteed to work.