Headless Blockly

2,319 views
Skip to first unread message

Neil Fraser

unread,
Dec 23, 2014, 3:02:44 PM12/23/14
to blo...@googlegroups.com
Workspaces and blocks may now be created headlessly.  This opens the door for server-side generation of code from XML.  Here is a demo:
https://blockly-demo.appspot.com/static/demos/headless/index.html

I have no experience with node.js, so if someone wants to make a minimal demo of how to do server-side code generation I'll be happy to add it to the documentation.

The published Blockly API has not changed, so most projects should be able to update cleanly.  However, the diff for this commit is over 3000 lines long and it affects most core files, so if your code reaches into Blockly's private guts, you'll need to make some updates.

Quick technical summary of change:
* Blockly.Workspace has been split into two objects: Blockly.Workspace is the parent class that is headless, and Blockly.WorkspaceSvg is the child class that extends the workspace to include UI.
* Blockly.Block is now purely headless.  Blockly.BlockSvg is no longer a separate companion object that is linked to a block, it is now a subclass of Blockly.Block that extents the block to include UI.

Realtime has not yet been updated, so it is now very broken.  If you use realtime, wait until Mark gets a chance to do his magic.

Mark Friedman

unread,
Dec 23, 2014, 5:32:16 PM12/23/14
to blo...@googlegroups.com
Interesting.  I'll have to take a look.  It's conceivable that while this breaks Realtime in the short run, it might actually enable Realtime Collaboration to be to really work properly in the long term, since the intertwining of the UI/Svg into the basic Block and Workspace objects was a major issue in attempting to get the the Realtime Collaboration to work properly.

Now I just have to somehow find the time to do the work.

-Mark

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Blake

unread,
Dec 23, 2014, 7:53:27 PM12/23/14
to blo...@googlegroups.com
All,

I'm not having much success running Blockly headless. The problem stems from the use of the "document" variable to do mutations.

So then I tried a simpler case of just generating code for a color block. In this case there is a call to "Blockly.createSvgElement" which involves actions using the "document" object. That traces back to Blockly.Field in field.js:40

I'm not sure what the best path forward is. Any calls to methods on the "document" object will not work in headless running under nodeJS. For that matter any of the "interface" objects and functions like document, window, alert... will cause an error. alert and the like could be shimmed, alert() = console.log()


Here are the error messages:

Here is my attempt to run Blockly Headless with NodeJS

--

Blake

unread,
Dec 23, 2014, 10:21:38 PM12/23/14
to blo...@googlegroups.com
I found this [1] but I can seem to get goog.addDependency to work properly.

[1](https://code.google.com/p/closure-library/wiki/NodeJS)

Neil Fraser

unread,
Dec 24, 2014, 3:45:57 AM12/24/14
to blo...@googlegroups.com
On 23 December 2014 at 16:53, Blake <techplex...@gmail.com> wrote:
So then I tried a simpler case of just generating code for a color block. In this case there is a call to "Blockly.createSvgElement" which involves actions using the "document" object. That traces back to Blockly.Field in field.js:40

This is good news, thank you.  I've made a sweep through the various fields (text, colour, dropdown, etc) and purged all the DOM elements I could find.  Node.js might work on non-mutator blocks now, but it is after midnight here.  I can see the issue with mutators, looks pretty minor, hope I can get to it tomorrow.

Here is my attempt to run Blockly Headless with NodeJS
https://github.com/TechplexEngineer/blockly

That's great.  Should be very useful.  Looks a nothing like my attempt:
  http://pastebin.com/nsDErqmD
Mine loaded fine, but I couldn't figure out how to access Blockly since it didn't seem to be in any scope.

Blake

unread,
Dec 24, 2014, 9:09:39 AM12/24/14
to blo...@googlegroups.com
YIPPEE!

With the changes you made, I am able to generate the code for the color block headless!

More experimentation is needed to figure out the best way to load the language blocks. FOr now I messed with blockly_uncompressed.js

This is soo sweet!

--

cireyoretihw

unread,
Dec 24, 2014, 6:50:12 PM12/24/14
to blo...@googlegroups.com, ro...@neil.fraser.name
i like this because it helps me see how BLOCKLY works

now if some one can create a decompiler to start with python { or any language } to produce XML output that could be used to used by BLOCKLY

i think if you can produce the internals of BLOCKLY from BLOCKLY would be great

just like when c++ compiler is written in c++ and pascal interperter was written in pascal and now Python is written in Python

but now i like that those languages can be created in BLOCKLY

Neil Fraser

unread,
Jan 5, 2015, 3:24:37 PM1/5/15
to blo...@googlegroups.com
DOM objects created during the definition of mutators have been removed.  That's one less issue for node.js.  Let me know if you encounter any other problems which need fixing on this end.

Blake

unread,
Jan 5, 2015, 6:00:33 PM1/5/15
to blo...@googlegroups.com
Neil,

Great work!
Hope you had a great holiday.

Here is a minimal changeset to make headless work. 

In trying to parse the sample XML that ships with the headless example(https://blockly-demo.appspot.com/static/demos/headless/index.html) an error occurs. It seems to trace back to a Blockly.createSvgElement call in the Blockly.FieldDropdown constructor.  (core/field_dropdown.js:59)

Best,
Blake






Matthieu Nantern

unread,
Jan 6, 2015, 11:42:01 AM1/6/15
to blo...@googlegroups.com
I've got an other error when trying to generate code for the following XML:

<xml xmlns="http://www.w3.org/1999/xhtml">
 
<block type="text_print" id="18" inline="false" x="206" y="241">
   
<value name="TEXT">
     
<block type="text" id="36">
       
<field name="TEXT">Don't panic!</field>
     
</block>
   
</value>
 
</block>
</xml>



Error:


/private/tmp/closure-library/closure/goog/asserts/asserts.js:85
goog
.asserts.DEFAULT_ERROR_HANDLER = function(e) { throw e; };
                                                         
^
AssertionError: Assertion failed: Expected string but got undefined: undefined.
    at
new goog.asserts.AssertionError (/private/tmp/closure-library/closure/goog/asserts/asserts.js:62:20)
    at
Object.goog.asserts.doAssertFailure_ (/private/tmp/closure-library/closure/goog/asserts/asserts.js:119:11)
    at
Object.goog.asserts.assertString (/private/tmp/closure-library/closure/goog/asserts/asserts.js:211:18)
    at
Blockly.Block.interpolateMsg (/private/tmp/blockly/core/block.js:878:16)
    at
Blockly.Blocks.text_print.init (/private/tmp/blockly/blocks_compressed.js:138:117)
    at
Blockly.Block.fill (/private/tmp/blockly/core/block.js:128:10)
    at
Blockly.Block.initialize (/private/tmp/blockly/core/block.js:85:8)
    at
Function.Blockly.Block.obtain (/private/tmp/blockly/core/block.js:71:14)
    at
Object.Blockly.Xml.domToBlock (/private/tmp/blockly/core/xml.js:264:27)
    at
Object.Blockly.Xml.domToWorkspace (/private/tmp/blockly/core/xml.js:223:31)

Neil Fraser

unread,
Jan 6, 2015, 2:54:28 PM1/6/15
to blo...@googlegroups.com
On 6 January 2015 at 11:42, Matthieu Nantern <matthieu...@gmail.com> wrote:
> I've got an other error when trying to generate code for the following XML:
[...]
> AssertionError: Assertion failed: Expected string but got undefined: undefined.
[...]
> at Blockly.Block.interpolateMsg (/private/tmp/blockly/core/block.js:878:16)

That looks like the signature of not having a message file loaded:
msg/js/en.js or msg/messages.js

Matthieu Nantern

unread,
Jan 6, 2015, 3:24:51 PM1/6/15
to blo...@googlegroups.com, ro...@neil.fraser.name
Exactly, thanks for the help.

I have a new issue now :

/private/tmp/blockly/core/utils.js:263
      document
.createElementNS(Blockly.SVG_NS, name));
     
^
ReferenceError: document is not defined
    at
Object.Blockly.createSvgElement (/private/tmp/blockly/core/utils.js:263:7)
    at
new Blockly.FieldImage (/private/tmp/blockly/core/field_image.js:51:30)
    at
Blockly.Blocks.text.newQuote_ (/private/tmp/blockly/blocks_compressed.js:117:372)
    at
Blockly.Blocks.text.init (/private/tmp/blockly/blocks_compressed.js:117:169)

    at
Blockly.Block.fill (/private/tmp/blockly/core/block.js:128:10)
    at
Blockly.Block.initialize (/private/tmp/blockly/core/block.js:85:8)
    at
Function.Blockly.Block.obtain (/private/tmp/blockly/core/block.js:71:14)
    at
Object.Blockly.Xml.domToBlock (/private/tmp/blockly/core/xml.js:264:27)

    at
Object.Blockly.Xml.domToBlock (/private/tmp/blockly/core/xml.js:354:36)

    at
Object.Blockly.Xml.domToWorkspace (/private/tmp/blockly/core/xml.js:223:31)

Thanks again !

Neil Fraser

unread,
Jan 6, 2015, 6:28:07 PM1/6/15
to blo...@googlegroups.com
On 6 January 2015 at 15:24, Matthieu Nantern <matthieu...@gmail.com> wrote:
> at new Blockly.FieldImage
> (/private/tmp/blockly/core/field_image.js:51:30)
> at Blockly.Blocks.text.newQuote_

On 5 January 2015 at 18:00, Blake <techplex...@gmail.com> wrote:
> It seems to trace back to a Blockly.createSvgElement call
> in the Blockly.FieldDropdown constructor. (core/field_dropdown.js:59)

Hi Blake and Matthieu,

DOM objects are no longer created for headless checkboxen, images or
dropdowns. Any more DOM creation that's still lurking somewhere in
the code?

Matthieu Nantern

unread,
Jun 4, 2015, 5:40:59 AM6/4/15
to blo...@googlegroups.com, ro...@neil.fraser.name
Hi Neil !

Sorry to come back so late after...

I made a new attempt with the HEAD of Blockly and the following code:

// This program is to be used with NodeJS run Blockly headless. It loads
// Blockly XML from `input.xml` and outputs python code on `stdout`.

global.DOMParser = require('xmldom').DOMParser;
global.Blockly = require('./blockly_uncompressed.js');
require('./blocks_compressed.js');
require('./python_compressed.js');
require('./msg/messages.js');

var fs = require('fs');

//the contents of './input.xml' are passed as the `data` parameter
fs
.readFile('./input.xml', function (err, data) {
       
if (err) throw err;

       
var xmlText = data.toString(); //convert the data buffer to a string
       
try {
               
var xml = Blockly.Xml.textToDom(xmlText);
       
} catch (e) {
                console
.log(e);
       
return;
       
}
       
// Create a headless workspace.
       
var workspace = new Blockly.Workspace();
       
Blockly.Xml.domToWorkspace(workspace, xml);
       
var code = Blockly.Python.workspaceToCode(workspace);
        console
.log(code);
});

I still have issues with the import of blockly_uncompressed.js. Things like:

window.BLOCKLY_DIR = (function() {
^
ReferenceError: window is not defined
    at
Object.<anonymous> (/Users/matt/Projects/Newton/poc_blockly_nodejs/blockly/blockly_uncompressed.js:4:1)
    at
Module._compile (module.js:456:26)
    at
Object.Module._extensions..js (module.js:474:10)
    at
Module.load (module.js:356:32)
    at
Function.Module._load (module.js:312:12)
    at
Module.require (module.js:364:17)
    at
require (module.js:380:17)
    at
Object.<anonymous> (/Users/matt/Projects/Newton/poc_blockly_nodejs/blockly/app.headless.js:8:18)
    at
Module._compile (module.js:456:26)
    at
Object.Module._extensions..js (module.js:474:10)

And :

  var scripts = document.getElementsByTagName('script');

               
^
ReferenceError: document is not defined

    at
/Users/matt/Projects/Newton/poc_blockly_nodejs/blockly/blockly_uncompressed.js:6:17
    at
Object.<anonymous> (/Users/matt/Projects/Newton/poc_blockly_nodejs/blockly/blockly_uncompressed.js:16:3)
    at
Module._compile (module.js:456:26)
    at
Object.Module._extensions..js (module.js:474:10)
    at
Module.load (module.js:356:32)
    at
Function.Module._load (module.js:312:12)
    at
Module.require (module.js:364:17)
    at
require (module.js:380:17)
    at
Object.<anonymous> (/Users/matt/Projects/Newton/poc_blockly_nodejs/blockly/app.headless.js:6:18)
    at
Module._compile (module.js:456:26)


I change blockly_uncompress.js according to https://github.com/TechplexEngineer/blockly/blob/headless/blockly_uncompressed.js but it looks like a bad way to do it.

Do you know if I have other choice ? (I don't like messing around with files that start with "Do not edit this file; automatically generated by build.py.")

Thank you !

Neil Fraser

unread,
Jun 4, 2015, 3:28:11 PM6/4/15
to blo...@googlegroups.com
I've replaced 'window' with 'this' in blockly_uncompressed.js, so that problem should be gone now.  And I think I've addressed the DOMParser issue.  But there are still issues with document and imports.  I don't have any experience with node.js, so you are the expert here.  I'd recommend editing build.py rather than blockly_uncompressed.  Let me know what it takes to get things working and I'll try to port changes back.

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matthieu Nantern

unread,
Jun 4, 2015, 4:32:35 PM6/4/15
to blo...@googlegroups.com, ro...@neil.fraser.name
Yep, no more issue with window.

I didn't find a nice solution for document, but it's still working with the following diff:

https://github.com/mNantern/blockly/commit/c93a227798785305d41e636be5d68f86ae88e6ee (see blockly_uncompressed.js)
Reply all
Reply to author
Forward
0 new messages