跳到主要内容

编译扩展

编译扩展是高级的 Scratch 扩展,直接与 Bilup 的 JavaScript 编译器集成以提供优化性能。与通过 VM 解释器运行的常规扩展不同,编译扩展将代码直接注入编译输出中,实现原始 JavaScript 性能。

什么是编译扩展?

编译扩展通过修补编译器的代码生成阶段来修改 Bilup 的内部编译过程。当项目使用编译扩展时,扩展的积木被转换为优化的 JavaScript 代码,以原始速度运行而不是通过 Scratch 的虚拟机。

与常规扩展的主要区别

常规扩展

  • 通过 Scratch 的 VM 解释器运行
  • 每个积木调用经过多个抽象层
  • 由于运行时解释,执行速度较慢
  • 开发和调试更容易
  • 与所有 Scratch 环境兼容

编译扩展

  • 在编译期间生成直接 JavaScript 代码
  • 完全绕过 VM 解释
  • 接近原始 JavaScript 性能
  • 开发过程更复杂
  • 仅在支持编译的环境中工作(如 Bilup)

编译工作原理

当 Bilup 编译项目时,它经历多个阶段:

  1. 脚本树生成:将积木结构转换为中间表示
  2. IR 生成:将树转换为中间表示(IR)
  3. JavaScript 生成:将 IR 转换为可执行的 JavaScript 代码

编译扩展使用修补系统在每个阶段注入自定义行为。

性能优势

编译扩展可以比常规扩展快得多。例如:

  • 常规数学扩展:每个数学运算需要 VM 调用、类型检查和解释消耗
  • 编译数学扩展:生成直接 JavaScript 如 Math.pow(a, b),消耗最小

这种差异在循环或性能关键代码中尤其明显,其中操作可能每帧被调用数千次。

开发要求

创建编译扩展需要:

  1. 深入的 JavaScript 知识:理解高级 JavaScript 概念、闭包和代码生成
  2. Bilup 内部知识:熟悉编译器架构和内部 API
  3. 非沙箱环境:扩展必须在非沙箱环境中运行才能访问编译器内部
  4. 测试基础设施:适当的测试设置,因为调试更复杂

何时使用编译扩展

考虑使用编译扩展时:

  • 性能至关重要:数学计算、数据处理或实时操作
  • 大量计算:在紧凑循环中频繁运行的操作
  • 原始 JavaScript 功能:访问常规扩展 API 不可用的 JavaScript 功能
  • 优化要求:当 VM 消耗显著影响用户体验时

避免使用编译扩展时:

  • 简单功能,不需要优化
  • 原型设计或实验性功能
  • 与其他 Scratch 环境的兼容性很重要
  • 开发时间和复杂性超过性能优势

架构概述

编译扩展通过修补三个主要编译器组件工作:

JSGenerator

处理最终的 JavaScript 代码生成阶段。扩展定义其积木应如何转换为 JavaScript 代码。

IRGenerator

管理中间表示阶段,其中积木逻辑在 JavaScript 生成之前被转换为结构化格式。

ScriptTreeGenerator

处理初始积木树结构,识别扩展积木并为编译做准备。

安全性和限制

编译扩展具有强大的功能,但也有局限性:

功能

  • 直接 JavaScript 代码注入
  • 访问浏览器 API 和功能
  • 性能优化机会
  • 自定义编译行为

限制

  • 仅在编译环境中工作
  • 调试过程更复杂
  • 代码注入存在潜在安全隐患
  • 兼容性仅限于特定的 Bilup 版本

入门指南

开始开发编译扩展,您应该:

  1. 首先了解常规 Scratch 扩展开发
  2. 学习 Bilup 的内部架构和 API
  3. 研究现有的编译扩展,如 Mist 的 Utils
  4. 设置适当的开发和测试环境
  5. 在尝试复杂功能之前,从简单积木开始

以下章节将指导您创建自己的编译扩展的技术细节,从基本设置到高级优化技术。