-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
Background
At the moment, the blocks modules (Blockly.blocks.*, in blocks/) generally do not have any exports; instead, importing one causes the created blocks definitions to be loaded into the block definitions dictionary (Blockly.Blocks, or more specifically the Blocks export of the Blockly.blocks module) as a side effect. Various extensions are also registered (again as a side-effect) via the register* exports of the Blockly.Extensions module.
Additionally, library block modules are normally imported via a single import 'blockly/blocks' statement, which imports the Blockly.blocks.allmodule, which in turn imports the rest of the individualBlockly.blocks.*` modules.
This creates some problems for developers:
- Loading blocks via
import 'blockly/blocks'is all-or-nothing: only developers using the Closure module system can usegoog.requireto load only a specific module (e.g.Blockly.blocks.loops). - There is no way to load only certain blocks from an individual module. At best you must load them all and then delete unwanted ones from
Blockly.Blocks(as well as unregister any unwanted extensions). - There is at present no way for developers who use ES Module
importstatements to access exports from individual block module (e.g., theloopTypesexport fromBlockly.blocks.loops)—see There is no mechanism to register custom loops anymore since the 2021 Q4 release #5819.
Proposed solution
Refactor the block modules in several steps, as follows:
-
Add a standard set of
exportsto the block modules:blocks: a dictionary object (@type {!Object<string, !Object>}), keyed by block type, of the block definitions that that module creates.extensions: a dictionary object (@type {!Object<string, !Object>}) keyed by extension name, of the extensions registered by the module.- Any other module-specific exports (e.g.,
loopTypes).
The
blockly.blocks.allmodule will provideblocksandextensionsdictionaries that include all the entries form all of the individual block modules. Additionally, it will re-export the exports objects from each of those modules using the corresponding names (e.g.colour,lists,loops, etc.)This will enable importers to see the full set of blocks (and extensions) that are loaded, as well as access any other exports provided by individual block modules (e.g.,
loops.loopTypes).This will be a breaking change to the exports provided by importing
blockly/blocks:- At present
blockly/blocksprovides a default export of the wholeBlockly.Blocksdictionary. - As proposed above, it will instead provide a named export of a dictionary containing only the blocks defined in
blocks/(and not any which might have been added toBlockly.Blocksbefore or afterblockly/blockswas imported), in addition to other named exports.
…but it is not believed that very many external developers will be impacted by it.
-
Optional intermediate step: refactor block modules so that rather than creating block definitions in the
Blockly.Blocksdictionary and then extracting them for theblocksexport, they are created in theblocksexported dictionary and then added toBlockly.Blocks—and similarly for extensions. This will not be a breaking change. -
Refactor the block modules so that they do not by default add block (and extension) definitions to Blockly. Instead, provide a method on Blockly to copy block definitions from a provided dictionary into
Blockly.Blocksupon request. This will be a breaking change necessitating developers to manually request block and extension definition installation—but thereby allowing them to choose exactly which definitions they wish to install.For convenience, an exported function (perhaps
registerAllor'installBlocks) could be provided on each block module to facilitate making the correct install the block definitions and register extensions from that module.
Alternatives
Some alternatives to the proposal above (which have not yet been fully considered):
- Do only step 1 above, leaving the modules as they presently are, such that they install block definitions and register extensions as a side effect.
- Instead of having
blocksandextensionsas separate named exports, they could be encapsulated into a single named export (possibly of a type such asBlocksAndExtensionswith instance properties.blocksand.extensions) which could be passed to an install-and-register function onBlockly. This might slightly ease the transition for developers.
Current status
- Add a standard export for blocks.
- Add a standard export for extensions.
- N.B.: @cpcallen is not sure that proposal as written above is optimal; further thought may be warranted.
- Additionally, might it be better to export block definitions individually, as we have opted to do for generators (see Proposal: Library generator publication changes + supporting change to
CodeGenerator#7086)?- Not so easy to keep block vs. extension exports straight, though…
- Refactor block modules so they are created in the exported
blocksdictionary and then installed inBlockly.Blocks. - Refactor block modules so they do not by default install blocks in
Blockly.Blocks. (Breaking change!)