Problem using p5 'esm' via jsdeliver (cdn)

Hello,

I am very new to javascript and even more to ES modules. However, I think I am trying things out correctly here. But as I am not sure if I am doing things right, I first drop a question here before I report an issue at either jsdeliver or p5. My final question will be: is this a bug, or am I doing things wrong?

I am trying to use the p5 via cdn as esm from jsdeliver. However, when trying to load my html, the console reports

jsdelivr-header.js:7 Uncaught SyntaxError: The requested module '/npm/@davepagurek/bezier-path@0.0.2/+esm' does not provide an export named 'createFromCommands' (at jsdelivr-header.js:7:1)

as far as I could find in here in the bezier-path source, the createFromCommands command does get exported (but again I am totally new to modules, so I am not sure if my conclusion is right).

As I am not sure how to use esm modules, I asked ā€˜Gemini AI’ for a usage example. Trying to use that example results in the same error.
Here is my html

<!DOCTYPE html>
<html>
<head>
  <title>p5.js ESM from jsDelivr Example</title>
  <style>
    body { margin: 0; }
    canvas { display: block; }
  </style>
</head>
<body>
  <script type="module">
    import p5 from 'https://cdn.jsdelivr.net/npm/p5@2.0.1/+esm';

    let x = 100;
    let y = 100;
    let speedX = 2.5;
    let speedY = 3;

    function setup() {
      createCanvas(400, 300);
      noStroke();
      fill(255, 0, 150);
    }

    function draw() {
      background(220);
      ellipse(x, y, 50, 50);
      x += speedX;
      y += speedY;

      if (x > width - 25 || x < 25) {
        speedX *= -1;
      }
      if (y > height - 25 || y < 25) {
        speedY *= -1;
      }
    }

    // You can also use the instance-based approach if you prefer
    // const mySketch = function(p) {
    //   let circleX = 50;
    //   let circleY = 50;
    //
    //   p.setup = function() {
    //     p.createCanvas(200, 150);
    //     p.fill(0, 100, 200);
    //     p.noStroke();
    //   };
    //
    //   p.draw = function() {
    //     p.background(240);
    //     p.circle(circleX, circleY, 30);
    //     circleX += 1;
    //     if (circleX > p.width + 15) {
    //       circleX = -15;
    //     }
    //   };
    // };
    //
    // new p5(mySketch);

  </script>
</body>
</html>

So now again my question, is the above described behavior due to a bug or me doing things the wrong way?

Thank you!

A JS script using type ā€œmoduleā€ doesn’t behave the same way as a regular 1.

1 of its many ā€œgotchasā€ is related to declaring variables using keywords var & function.

For example, your 2 functions function setup() {} & function draw() {} will have different global visibility depending on whether they’re being run using type ā€œmoduleā€ or not!

For regular JS script type, the variable declaring keyword function (and var as well) will also append the variables setup & draw on the globalThis:

However, for type ā€œmoduleā€, that won’t happen!

B/c neither setup() nor draw() callbacks are present on globalThis, p5js won’t ā€œseeā€ them; and thus your sketch won’t run!

As a workaround, you can manually add those 2 function variables as globalThis properties:

globalThis.setup = setup;
globalThis.draw = draw;
1 Like

That is very useful information, I would be one step closer to getting the ā€˜module’ setup to work. Just, I still need to get rid of that error message when trying to use the ā€˜esm’ library.
I guess, there is something wrong with that ā€˜esm’ package on jsdeliver, but I am not sure (how it should work). Anyway, after getting it ā€˜imported’ I will be aware of your ā€˜advice’. Thank you very much for this explanation :slight_smile:

Officially there’s no ESM version of p5js.
p5js has always been a regular non-ESM library.

And by the looks of that bezier-path:

Those imports are incompatible w/ browser ESM syntax b/c they’re using filenames w/o their extension!

For example, import { BezierSegment } from "./BezierSegment";
should be instead: import { BezierSegment } from "./BezierSegment.ts";

Browsers only accept the full filename, including its extension, for the keyword import.

1 Like