blockly-samples icon indicating copy to clipboard operation
blockly-samples copied to clipboard

Backpack plugin - TypeError: workspace.getComponentManager is not a function

Open chrisbansart opened this issue 1 year ago • 7 comments

Backpack Plugin v5.0

getComponentManager() method

When I switch from one workspace from another it occurs a bug TypeError: workspace.getComponentManager() is not a function. It occurs there

/**
   * Resets the state of a workspace.
   * @param {Blockly.Workspace} workspace the workspace to reset
   */
  clear(workspace) {
    const componentManager = workspace.getComponentManager(); // it raises the bug
    const backpack = componentManager.getComponent('backpack');
    backpack.empty();
  }
}

This bug doesn't occur with the v3 of BackPackPlugin even if I use it with Blockly v10.

It seems that it happens when I switch from a rendered workspace to another one which is not rendered and not contains any plugins. The second workspace is just used to generate Javascript in background.

Steps to reproduce the behavior:

  1. Create a new workspace rendered with a theme etc
  2. Dispose the workspace. I've tried to dispose backpack plugin before disposing the workspace but it didn't solve the issue (same bug occurs)
  3. Open a new Workspace not rendered and generate Javascript from JSON

Thanks for your help Chris

chrisbansart avatar Jul 21 '23 18:07 chrisbansart

Thanks for reporting! This would happen if you used any headless workspace because headless workspaces don't have the component manager or the backpack. The serializer should check if the workspace is an instance of WorkspaceSvg before attempting to access the component manager. Also, it should handle the case where we have a WorkspaceSvg but there is no backpack component. In these cases, the serializer should just do nothing, i.e. save or load no data. This is important to handle because serializers are registered globally, but the backpack is registered per-workspace.

Thank you for filing this @chrisbansart. We'll aim to fix this soon and we've prioritized it accordingly.

@johnnyoshika would you be interested in working on this one too while you're poking at this plugin? If not, our team will address this within the next couple of sprints. Thanks!

maribethb avatar Jul 27 '23 01:07 maribethb

I'll try to reproduce this.

@chrisbansart for step 3, are you creating a headless workspace (i.e. new Blockly.Workspace()) and hydrating it with serialized JSON that includes backpack data? You can check if the serialized JSON includes backpack data by checking whether there's a backpack property at the root of the JSON object. The reason why I need clarity on this is that I'm able to get an error by following these steps, but my error message is different: Uncaught Error: DOMParser was unable to parse: {"blocks": ...

johnnyoshika avatar Jul 27 '23 19:07 johnnyoshika

Hi, sorry for my late answer. Yes, I create a headless workspace with new Blockly.Workspace(). You are right, the json I try to load contains backpack property. Thus, I delete this attribute before loading it :

var json = JSON.parse(jsonTextFromDB);
delete json.backpack; //delete attribute backpack
console.log("convertJSONWorkspaceIntoJSCode JSON ", json); // to check backpack is not present anymore
    Blockly.serialization.workspaces.load(json, workspaceCodeGenerator); // workspaceCodeGenerator is a global var created with new Blockly.Workspace()

Unfortunately, the error still occurs. How could I neutralize backpack when I load json in a headless workspace ? Thanks

chrisbansart avatar Sep 12 '23 22:09 chrisbansart

@chrisbansart Can you try this new skipSerializerRegistration option in the backpack? https://github.com/google/blockly-samples/pull/1829

johnnyoshika avatar Sep 13 '23 17:09 johnnyoshika

Thanks @johnnyoshika , that works and it prevents the issue. If I understood well, it disables BackPack to be serialize, therefore when I save a workspace the blocks in the backpack doesn't be present anymore in the json ?

By the way, could you confirm that I understand correctly how BackPack works and maybe other plugins, because It appears to me that the BackPack plugin is loaded globally. Let my explain : In my program, I use one variable to store a visible workspace to use blocks and design program and I use another variable with a headless workspace to only generate code. When I load BackPack in the visible workspace it still be enabled for the another headless workspace. Am I correct ?

Thanks for your help.

chrisbansart avatar Sep 14 '23 07:09 chrisbansart

Thanks @johnnyoshika , that works and it prevents the issue. If I understood well, it disables BackPack to be serialize, therefore when I save a workspace the blocks in the backpack doesn't be present anymore in the json ?

By the way, could you confirm that I understand correctly how BackPack works and maybe other plugins, because It appears to me that the BackPack plugin is loaded globally. Let my explain : In my program, I use one variable to store a visible workspace to use blocks and design program and I use another variable with a headless workspace to only generate code. When I load BackPack in the visible workspace it still be enabled for the another headless workspace. Am I correct ?

Thanks for your help.

The module with all of the code is loaded globally, and registers like for serialization happen globally, but the backpack needs to be instantiated for each individual workspace:

const backpack = new Backpack(workspace);
backpack.init();

So unless you instantiate a backpack for your workspace it shouldn't have a backpack!

Best wishes, --Beka

BeksOmega avatar Sep 14 '23 16:09 BeksOmega

The problem is that because serializers are registered globally, the serializer shouldn't assume we have a backpack or a rendered workspace, which it currently does. The serializer functions should first check the workspace is WorkspaceSvg before calling getComponentManager or anything related to the backpack.

maribethb avatar Sep 14 '23 17:09 maribethb