news 2026/11/4 1:21:30

Blockly 代码生成:用内置生成器还是自定义?看完这篇不纠结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Blockly 代码生成:用内置生成器还是自定义?看完这篇不纠结

Blockly 代码生成:用内置生成器还是自定义?看完这篇不纠结

【免费下载链接】blocklyThe web-based visual programming editor.项目地址: https://gitcode.com/gh_mirrors/bloc/blockly

你的积木拼好了,现在要把它变成能跑的代码,结果在"直接调 Blockly 自带的代码生成器"和"自己写一套"之间来回纠结,选错后面返工很麻烦。

这篇文章先给你一张选型表,再按投入从低到高分三档讲清楚:每一档适合谁、改哪几行代码、要付什么代价。前两张表看完,你就能做决定了。

选型速查:先对号入座

对比维度直接用内置生成器自定义代码生成
上手成本引一个模块 + 一次函数调用建类、补保留字、实现所有积木函数
维护负担版本升级即修复每种语言各维护一份实现
语言选择锁定 JavaScript / Python / Lua / PHP / Dart 五种任意目标语言
输出控制缩进、括号、注释格式由内置决定完全按你的规范来

30 秒决策:目标语言就在这五种之内、又不需要改输出格式,直接走内置生成器;语言不在列表里,或者输出要完全贴你的工程规范,才值得上自定义。

五分钟跑通内置代码生成

内置生成器是仓库generators/目录下五个现成的实现:入口文件分别是javascript.ts、python.ts、lua.ts、php.ts、dart.ts,每个入口在实例化生成器后把 lists、logic、loops、math 等模块的积木函数批量注册进去,你拿到手的就是一个能直接用的成品。

谁适合:目标语言是这五种之一的项目,绝大多数场景停在这档就够了。

怎么配:

  1. 安装依赖:npm install blockly,包体积和构建配置不用你操心;
  2. 按package.json的 exports 映射(第 52-100 行),用对应子路径引出生成器;
  3. 拼积木的界面用core/inject.ts的inject注入到一个空div;
  4. 生成时调生成器实例的workspaceToCode。

app.js里只需要这几行:

import { javascriptGenerator } from 'blockly/javascript'; import { pythonGenerator } from 'blockly/python'; import { inject } from 'blockly/core'; const workspace = inject(document.getElementById('blocklyDiv')); const code = javascriptGenerator.workspaceToCode(workspace); console.log(code);

代价:

  • 注意:语言被锁死在那五种,想换语言只能再引一个内置实例,没有中间档;
  • 注意:输出格式内置说了算,缩进、注释、变量命名规则你插不上手;
  • 注意:内置积木的生成逻辑升级跟随版本走,你的业务积木类型仍要自己补(下一档的事)。

不满足于上一档的话,往下走。

给自定义积木注册生成函数

在内置生成器上注册函数,本质是往生成器的forBlock字典里加条目:积木类型映射到(block, generator)函数。基类core/generator.ts的blockToCode(第 257 行)按block.type查这个字典,查到就执行,查不到就抛错。

谁适合:目标语言还在五种之内,但你有自定义积木,或想微调某个内置积木的输出。

怎么配:

  1. 复用内置生成器实例,不新建类;
  2. 在forBlock上补你的积木类型;
  3. 值积木返回[代码, 优先级]二元组,语句积木返回字符串。
import { javascriptGenerator } from 'blockly/javascript'; javascriptGenerator.forBlock['my_sensor_read'] = function (block, generator) { const pin = generator.valueToCode(block, 'PIN', 0) || '0'; return [ `read(${pin})`, javascriptGenerator.Order.ATOMIC, ]; };

代价:

  • 注意:每个自定义积木类型都要在用的每种语言上各注册一次,五个语言就是五份;
  • 注意:返回值约定错了(值积木返回字符串、或语句积木返回二元组)会在生成时抛TypeError,见core/generator.ts第 272-274 行的检查;
  • 注意:内置积木的生成函数你看得到、但不建议在实例上覆盖,升级时容易覆盖丢。

继承基类自建一个完整生成器

自建生成器 = 继承core/generator.ts的CodeGenerator(第 40 行),只重写它给过的钩子:init、INDENT、Order枚举、各积木的生成函数,基类负责遍历顶层积木、拼接、前导定义注入。

谁适合:要生成 Go、Rust 这类不在五种里的语言,或输出必须严格贴自家 lint 规范的平台型产品。

怎么配:

  1. 子类里定义该语言的Order优先级枚举(照抄generators/python/python_generator.ts第 27 行起的写法);
  2. 重写init,给nameDB_建Names实例,传入保留字;
  3. 按目标语言设INDENT;
  4. 把积木函数按generators/lua/lua_generator.ts的模块结构分批挂载。
import { CodeGenerator } from 'blockly/core'; import { Names } from 'blockly/core'; class GoGenerator extends CodeGenerator { INDENT = '\t'; init(workspace) { this.nameDB_ = new Names('func,if,for,range,var'); this.nameDB_.setVariableMap(workspace.getVariableMap()); } } const goGenerator = new GoGenerator('go');

代价:

  • 注意:每种语言都是一份独立维护,字符串转义、换行约定、定义前置这些细节基类不代劳;
  • 注意:init里不初始化nameDB_,取变量名时直接抛错,见core/generator.ts第 540-547 行的getName;
  • 注意:积木类型覆盖不全的代价在这里被放大——forBlock缺一个类型就整个工作区生成失败。

从零到跑通:完整落地路径

按时间顺序走一遍,以"内置 JavaScript 生成器 + 一个自定义积木"为例。

  1. 装依赖:npm install blockly。本仓库可离线 clone 查看源码:git clone https://gitcode.com/gh_mirrors/bloc/blockly;
  2. 准备注入点:页面放一个id="blocklyDiv"的div,尺寸自己定;
  3. 注入编辑器:app.js里调inject(document.getElementById('blocklyDiv')),返回主workspace;
  4. 注册自定义积木:往javascriptGenerator.forBlock挂my_sensor_read(代码见上一节);
  5. 接生成按钮:把"生成"按钮的点击事件绑到workspaceToCode(workspace),结果填进一个textarea。

关键改动就这一处,app.js:

import { javascriptGenerator } from 'blockly/javascript'; import { inject } from 'blockly/core'; const workspace = inject(document.getElementById('blocklyDiv')); document.getElementById('runBtn').addEventListener('click', () => { const code = javascriptGenerator.workspaceToCode(workspace); document.getElementById('output').value = code; });

怎么确认成功了?拼一个"循环 + 变量"的积木组,点生成,输出应是带缩进的for循环且变量名不撞保留字。想核对标准答案,仓库里tests/generators/golden/generated.js和generated.py就是固定积木组合的基准输出,对照一眼就知道对不对;跑npm run test:generators(对应package.json第 47 行)可以过一遍仓库自带的生成器测试。

踩坑预警

报 "does not know how to generate code for block type"

现象:一调workspaceToCode就抛错,工作区里明明没坏积木。原因:blockToCode在forBlock里查不到该积木类型的函数(core/generator.ts第 258-263 行)。解法:到generators/javascript/对应模块里确认这个类型本就有内置函数;如果是你自定义的积木,按上一节的格式补注册;如果你用的是 UMD 压缩包而不是 npm 子路径,生成器可能挂在Blockly.JavaScript下,别和模块入口混着拿。

变量名和保留字撞了

现象:用户把变量命名为if或func,生成的代码直接语法错误。原因:名字映射走Names,但你的init没传保留字表,或压根没初始化nameDB_。解法:在init(workspace)里给nameDB_赋new Names('保留字,逗号,分隔')并setVariableMap,参考generators/lua/lua_generator.ts的init写法。

缩进或括号位置不对

现象:Python 缩进错一行、比较表达式少一层括号。原因:INDENT仍是基类默认两空格(core/generator.ts第 97 行),或生成函数没返回优先级、返回了 0。解法:自建生成器按语言重写INDENT;所有值积木函数返回二元组时,第二项必须用Order枚举里的正确档位,照抄generators/python/python_generator.ts第 27 行起的枚举对照着填。

生成的代码能跑但和 golden 文件对不上

现象:手动跑的输出和tests/generators/golden/下的基准差在换行或空格上。原因:你本地装的是另一个版本的 blockly,内置生成逻辑已经变了。解法:锁住package.json里的 blockly 版本,别用*;升级前先跑一遍生成器测试再换。

按场景对号入座

你的场景走哪条路
教学网站、儿童编程工具内置生成器,五分钟完事
行业工具,有几十个自定义积木内置生成器 +forBlock补注册
平台型产品,要出五种之外的语言自建生成器,长期维护

先跑通内置生成器,再往forBlock上加自定义积木,确认这条路撑不住了再动继承基类的主意。每一档的投入都比上一档大一个数量级,按需升级比一步到位省事得多。

【免费下载链接】blocklyThe web-based visual programming editor.项目地址: https://gitcode.com/gh_mirrors/bloc/blockly

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/4 1:20:17

一条命令看穿文件真实身份:Detect It Easy 快速识别教程

一条命令看穿文件真实身份:Detect It Easy 快速识别教程 【免费下载链接】Detect-It-Easy Program for determining types of files for Windows, Linux and MacOS. 项目地址: https://gitcode.com/gh_mirrors/de/Detect-It-Easy 一个 .txt 后缀的文件&#…

作者头像 李华
网站建设 2026/11/4 1:20:03

BlackHole 完整教程:3 步打通 macOS 应用间音频零延迟传输

BlackHole 完整教程:3 步打通 macOS 应用间音频零延迟传输 【免费下载链接】BlackHole BlackHole is a modern macOS audio loopback driver that allows applications to pass audio to other applications with zero additional latency. 项目地址: https://git…

作者头像 李华
网站建设 2026/11/4 1:20:00

XHS-Downloader 小红书无水印下载:粘贴链接到拿到文件的 3 分钟

XHS-Downloader 小红书无水印下载:粘贴链接到拿到文件的 3 分钟 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具 项目地址: https://gitcode.com/gh_mirrors/xh/XHS-Downloader XHS-Downloader 是…

作者头像 李华
网站建设 2026/11/4 1:19:59

终端交互新体验:Hermes Agent TUI界面高效操作指南

终端交互新体验:Hermes Agent TUI界面高效操作指南 Hermes Agent是一款强大的终端用户界面(TUI)工具,为开发者提供了直观高效的命令行交互体验。通过其简洁的界面设计和丰富的功能,用户可以轻松管理和执行各种任务&am…

作者头像 李华