Kinrany/vue-p5

Critical problem when using ".createGraphics()"

lorenzki opened this issue · 23 comments

Thanks for your package - it has been quite helpful!

But now i stumbled upon a serious issue with my application.

I am using "createGraphics()" to create an imageMask.
Everything works fine on the first load. But when I leave the route with "vue-p5" of my Vue application and then re-enter it, it seems like p5 crashes:

[Vue warn]: Error in mounted hook: "TypeError: b.prototype._registeredMethods[u].slice is not a function"

found in

VueP5

TypeError: b.prototype._registeredMethods[u].slice is not a function
at new b (vue-p5.js?e25d:24)
at VueComponent.mounted (vue-p5.js?e25d:75)

I've tried to put .createGraphics() into the preload-, the setup, or the draw-method. It's the same everywhere.
On the first load everything works fine - leaving and re-entering the route crashes vue-p5.

This seems closely connected to the usage of createGraphics() - as soon as I am not using this method, the errors are gone.

Hi, thanks for the report and the kind words :)

I'd like to investigate. Do you by any chance already have a repo I could use to reproduce this?

Hi
Nice lib, I hadn't seen it when I started my project!
I'm facing the same problem, I believe it is some kind of problem with removing and re-creating the canvas when createGraphics has been called. Some kind of problem with _registeredMethods.

I'm using createGraphics in my default sketch (to integrate with other rendering lib) and now I can't "reset" my sketch.
The exact same error as described above appears when you push "RESET" button in my project here:
http://super-8.glitch.me/

Any hint will help! Thanks!

Hi, just a comment that I worked around my issue by NOT removing the p5 canvas, just resetting its state.
But I still think this is a bug with p5.createGraphics.
Thanks!

Hi icarito, this is super helpful, thanks :D

Oh, I cloned the repo and couldn't find any reference to vue-p5. It seems I misread your first comment, @icarito, and you never actually switched to using it, right?

Still, I'd like to find the problem and report it upstream. Do you by any chance remember a commit where RESET was still broken?

No problem, and I got it, thanks. Merry xmas :)

Sorry, I have been already in my xmas holidays when you both started to comment.
I have no repo to reproduce this problem right now - but I could make one if it's still needed.
And @Kinrany as far as I have understood you were talking about this being a native p5 error rather than a issue with your package?

@lorenzki yeah, since @icarito had this error too without using vue-p5, it seems to be a problem with p5 itself.

I have no repo to reproduce this problem right now - but I could make one if it's still needed.

It would be helpful, yes! Though a repo is not exactly necessary: a code snippet that demonstrates the problem would be good enough.

Any updates on this? I am currently running into the same problem using create graphics.

Hi! This is an upstream problem, and I haven't been able to pinpoint exactly why it happens. A small example that reproduces the problem would be very helpful.

Hi there. Thanks for replying :)
Here i've just attached the methods and data part of my component. https://gist.github.com/Chappie74/73115dc181e85fdeb5b8215e50c4bd71
The problem started occurring when I added in the line:
this.canvas.secondary = sk.createGraphics( this.canvas.width, this.canvas.height )

The error occurs when I make changes in the IDE and it automatically builds and updates to the page. The canvas wouldn't render. To solve this I have to hit the refresh button and reload the page.

####EDIT
Here is a gist to the full component. https://gist.github.com/Chappie74/0f25e30d6495aa3d6d487f5708d4e1ec

Thank you!

Hey @Kinrany. Just an update. For some reason during development, I had to remove node modules and reinstall them. Now I am not seeing the error anymore. I am not sure if this was a direct cause of that or something else during development. But i strongly believe that reinstalling the node modules fixed the issue.

Interesting, thanks for the heads up! Perhaps it was caused by an outdated dependency. I'll need to at least check that vue-p5 works with, and expects the current versions of its deps.

Hey @Kinrany. So it seems i've ran into this problem again. So in my current set up, I have vue routing with history enabled. I have a nested route which I use for my game. It works fine when I first route to the route with the canvas on it. But should I change to a different route in the nested routes, then route back to the one with the canvas on it, this error occurs. Unfortunately, I cannot share the project for you to use. I too am using createGraphics

Hmm, sounds like a lifecycle bug. Thanks again for the report!

Same problem.

I'm also running into this problem. Digging into core p5.js, the issues seems to be happening on this line:

  // Allows methods to be registered on an instance that
  // are instance-specific.
  this._registeredMethods = {};
  var methods = Object.getOwnPropertyNames(p5.prototype._registeredMethods);
  for(var i = 0; i < methods.length; i++) {
    var prop = methods[i];
    this._registeredMethods[prop] = p5.prototype._registeredMethods[prop].slice(); // <-- Here
  }

Seems like somehow one of these registeredMethods is not a type of String or Array, which is causing that slice to fail?
I have not yet figured out how to get to the bottom of where the registered method is getting set though.

EDIT: Pointed to core.js not the fork the pr originally was merged from in example.

More info (potential solution below!)

With my setup I basically have a flat js file that exports a P5 instance for each template 'sketch' I have for people to browse/use. That was effectively creating a p5 instance like so, and in that squareSketch setup method is where I am creating the graphics context.

export const simpleBorderSquare = (node) => {
  console.log(Object.getOwnPropertyNames(p5.prototype._registeredMethods));
  return new p5(squareSketch, node);
};

Previously, I had set up my Vue component to have the p5 instance as a reactive data property:

data() {
    return {
        p5Wrapper: null,
    }
}

When I'm logging the registeredMethods of the p5.prototype on the first initialization, you get the expected 4 valeus:

Array(4) [ "init", "pre", "post", "remove" ]

However, when I try to 'reset' the instance by re-initializing things you'll notice that registeredMethods has been polluted:

this.p5Wrapper = simpleBorderSquare(this.refs.$p5cavas);
Array(5) [ "init", "pre", "post", "remove", "_obj_"]

Turns out that obj is the Vue Observer which gets jammed in there because I had set it as a reactive property. At least on my setup, that is what was causing that error - .slice() does not work on the Observer because it's not a String or Array.

Solution

For me, all I did was pull out the p5Wrapper so that it was no longer reactive, like so:

  // This is a custom, non-reactive reference to the p5 wrapper so Vue doesn't pollute the P5 prototype
  // Access like this.$options.p5Wrapper
  p5Wrapper: null,
  data() {
    return {};
  },

Once that's done you can access it with this.$options.p5Wrapper. Verified working on Vue 2, not sure about Vue 3 since my project has not upgraded yet.

Like others, I was not actually using the vue-p5 wrapper for this so I don't know if it actually impacts this repository (maybe I should have just used this nice wrapper 😅). Thank you for letting us hijack an issue on here @Kinrany - this was the only thread I found on Google that was actually helpful with this issue!

You're welcome, haha. The wrapper is indeed so small that for larger projects it may very well be more useful as a hub for discussing the use of Vue and p5 together.

@msencenb's solution also put me on the right path. But for me, the solution was a bit more cumbersome, since I had references to both p5 and multiple p5.Graphics references inside an array of objects.

It looked something like this before fix:

export default Vue.extend({
  data() {
    return {
      canvas:p5,
      graphicsObjects:[
        {
          gfx:p5.Graphics
        },
        {
          gfx:p5.Graphics
        }
      ]
    }
  }
})

In the end, I had to move all p5 references out of data(). I didn't add a custom non-reactive property to Vue, but instead just declared the variables outside of the Vue instance:

let canvas = p5
let graphicsObjects = [
  {
    gfx:p5.Graphics
  },
  {
    gfx:p5.Graphics
  }
]
export default Vue.extend({
  data() {
    return {}
  }
})