Skip to main content

Maintaining compatibility

Once projects exist using your extension, it is critical that you do not change the extension in ways that will break compatibility as doing so will effectively corrupt projects.

What you must never change

The extension ID must never change

  getInfo() {
return {
// THIS MUST NEVER CHANGE
id: 'fetch'
// ...
};
}

Block opcodes and types must never change

Instead, create a new block and mark the old one as hideFromPalette: true.

It is generally safe to change blockType from REPORTER to BOOLEAN or from HAT to EVENT, but a conversion of HAT to BOOLEAN would be problematic.

  getInfo() {
return {
// ...
blocks: [
{
// THESE MUST NEVER CHANGE
blockType: Scratch.BlockType.REPORTER,
opcode: "fetch",
// ...
}
]
};
}

Blocks must never be removed

Instead, create a new block and mark the old one as hideFromPalette: true.

  getInfo() {
return {
// ...
blocks: [
// THIS MUST NEVER BE DELETED
{
opcode: "old",
hideFromPalette: true
// ...
}
]
};
}

Argument IDs and types must never change or be removed

  getInfo() {
return {
// ...
blocks: [
{
// THE ARGUMENT ID "INPUT" MUST NEVER BE CHANGED OR REMOVED
text: "block [INPUT]",
arguments: {
INPUT: {
type: Scratch.ArgumentType.REPORTER,
// ...
}
},
// ...
}
]
};
}

Arguments must never be added to existing blocks

Instead, create a new block and mark the old one as hideFromPalette: true. The new block can be reimplemented in terms of the old one:

  getInfo() {
return {
// ...
blocks: [
{
blockType: Scratch.BlockType.REPORTER,
id: "oldBlock",
text: "old [INPUT1]",
arguments: {
INPUT1: { /* ... */ }
},
hideFromPalette: true
},
{
blockType: Scratch.BlockType.REPORTER,
opcode: "newBlock",
text: "new [INPUT1] [INPUT2]",
arguments: {
INPUT1: { /* ... */ },
INPUT2: { /* ... */ }
}
}
]
};
}
oldBlock(args) {
return this.newBlock({
...args,
INPUT2: "Default value"
});
}
newBlock(args) {
// ...
}

Don't modify isTerminal

If a COMMAND block does not already have isTerminal: true, then don't add it as doing so will cause existing projects that connect blocks underneath to break. Instead, create a new block and optionally hide the old one.

Don't modify acceptReporters

Converting an input menu to a field menu and vice-versa does not work and will corrupt projects. Create a new menu and block instead.

Don't significantly change block behavior

Trivial bug fixes are typically fine, but significant changes may break projects. This is a bit harder to quantify; the best way to make sure your changes don't break projects is extensive testing.

What you can change

You can always change these parts of extension metadata:

  • name
  • docsURI
  • color1, color2, color3
  • menuIconURI and blockIconURI

You can always change these parts of blocks and arguments:

  • text, as long as it contains the same arguments (changing argument order is safe)
  • disableMonitor (enabling true just hides checkmark, does not remove existing monitors)
  • hideFromPalette
  • filter (adding filter just hides from palette, does not remove existing blocks)
  • defaultValue
  • dataURI and flipRTL in image inputs

For menus, you can always change text, but you should not change value without careful consideration. Adding menu items is always okay, but removing menu items is dangerous.

What if you need to break compatibility?

There are times when there is no option but to break backward compatibility. In these instances, you should create a brand new extension with an entirely new ID and leave the old version untouched.

For example, if your extension fetch needs a complete redesign, you could create a new extension with the ID fetch2.

Next steps

Next, let's learn how to share your extension with the world.