简体   繁体   中英

Can't call any Blockly methods in index.html even though it works in other .js files and a workspace is shown

I'm trying to create a tool where you can create HTML pages using Blockly blocks. I already have a page that shows my workspace and my self-created block. Now I want to write a script that gets the code from the workspace. Normally there is a workspaceToCode method in the Blockly library. Unfortunately I can't access any Blockly methods or really anything Blockly-related in my index.html.

I've looked up similar projects and can't seem to find any differences. I'm loading blockly_compressed.js , blocks_compressed.js and javascript_compressed.js . And because it shows me a workspace with "functioning" blocks I'm pretty sure that the paths are correct.

See below what I tried and thanks in advance for your help:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="styles.css">
    <style>
        ...
    </style>

    <script src="node_modules/blockly/blockly_compressed.js"></script>
    <script src="node_modules/blockly/blocks_compressed.js"></script>
    <script src="node_modules/blockly/msg/en.js"></script>
    <script src="node_modules/blockly/javascript_compressed.js"></script>

</head>

<body>

...

<script src="html_blocks.js"></script>
<script src="html_generator.js"></script>
<script src="main.js"></script>


<script>
    function update(event) {
        var code = HtmlGenerator.workspaceToCode(workspace);
        document.getElementById('HTMLCodeDiv').innerText = code;
    }
    workspace.addChangeListener(update);
</script>

</body>
</html>

The error it is giving is "unresolved function or method" for the workspaceToCode method as well as the addChangeListener method.

Since you haven't shown all of your code, I can't provide a precise answer to explain exactly what's gone wrong for you here, but I can say that Blockly in a classical (non-module) script tag adds itself to the window as follows:

// ...
  } else { // Browser
    var factoryExports = factory();
    root.Blockly = factoryExports;
  }
// ...

where root is window (by way of this ) and factory() is the entire Blockly code. All Blockly functions are namespaced inside of the window.Blockly object, so there is no such window.workspace variable that would be created unless one of your other scripts (not shown) created this and attached it to the window.

If you open your browser console, you can type Blockly. and see the list of available properties that were imported by the scripts. The other Blockly scripts simply attach more properties to the global Blockly object that was created by the first script tag. Blockly.Workspace and Blockly.workspaceToCode are some of these properties, and you can call Blockly.inject to create a workspace.

For example,

 const blocklyWorkspace = Blockly.inject("blockly-container", { toolbox: document.getElementById("toolbox") }); document.querySelector("button") .addEventListener("click", e => { const code = Blockly.JavaScript .workspaceToCode(blocklyWorkspace); console.log(code); });
 #blockly-container { height: 100vh; } xml { display: none; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/blockly/8.0.0/blockly.min.js" integrity="sha512-m19pjKFpHlhFqUAWB49IQt7ip1P7UDKyV0k0f7UGnN8pXSLFjtvsrRcDlwRw+ZhaNeqQTwHwE9+CJgPAWUyA9Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <button>Workspace to code</button> <div id="blockly-container"></div> <xml xmlns="https://developers.google.com/blockly/xml" id="toolbox"> <block type="text_print"></block> <block type="text"></block> </xml>

It strikes me as an antipattern to use node_modules in script tags like this, even though some of the Blockly examples do this. Usually, you'd use a bundler of some sort (webpack, parcel, vite, browserify, rollup, etc) to allow you to dynamically import the code using modules (example below). Or else keep your build without any local dependencies and use a CDN and take advantage of client caching (as shown above). Using node_modules directly seems like the worst of both worlds, especially without a minification build.

For example, you can use parcel to build your app for the web. A bundler makes it easy to use node_modules without specifying the paths. You can develop using modules rather than legacy UMD script tags, which help you organize the project into chunks and avoid polluting the window with shared data.

The example below is contrived for clarity, but hopefully you can extrapolate the approach (or something similar) to your project.

index.html :

<!DOCTYPE html>
<html lang="en">
<head>
  <style>
  #blockly-container {
    height: 100vh;
  }
  xml {
    display: none;
  }
  </style>
</head>
<body>
  <div id="blockly-container"></div>

  <xml xmlns="https://developers.google.com/blockly/xml" id="toolbox">
    <block type="text_print"></block>
    <block type="text"></block>
  </xml>

  <xml xmlns="https://developers.google.com/blockly/xml" id="start-blocks">
    <block type="text_print" id="N4+B!H6xh[=wx]z^LqGk" x="38" y="38">
      <value name="TEXT">
        <shadow type="text" id="~uw6Vr9}hxZS-=a(Zjt{">
          <field name="TEXT">hello world</field>
        </shadow>
      </value>
    </block>
  </xml>

  <script src="src/index.js" type="module"></script>
</body>
</html>

src/index.js :

import Blockly from "blockly";
import generateCode from "./generate-code";

const blocklyWorkspace = Blockly.inject("blockly-container", {
  toolbox: document.getElementById("toolbox")
});

Blockly.Xml.domToWorkspace(
  document.getElementById("start-blocks"),
  blocklyWorkspace
);

console.log(generateCode(blocklyWorkspace));

src/generate-code.js :

import Blockly from "blockly";

export default blocklyWorkspace =>
  Blockly.JavaScript
    .workspaceToCode(blocklyWorkspace);

package.json :

{
  "scripts": {
    "start": "node node_modules/parcel/lib/cli index.html"
  },
  "dependencies": {
    "blockly": "^8.0.3"
  },
  "devDependencies": {
    "parcel": "^2.6.2"
  }
}

Building and running:

npm i
npm start

Now, navigate to (by default) http://localhost:1234 (or whatever parcel tells you on the console) and begin developing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM