-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Description
Check for duplicates
- I have searched for similar issues before opening a new one.
Problem
At the moment much of our documentation and examples (including most of the code in the blockly-samples repository) load Blockly by doing
import * as Blockly from 'blockly'
as if Blockly were published as ES modules—but in fact the blockly NPM package contains only UMD modules which are (in practice) either require()ed as CJS modules or simply loaded as <script>s.
Certain JavaScript runtimes—notably node.js—can deal with this, allowing developers to load UMD modules (as CJS modules) using the import keyword, but no browser supports this. This means that none of the examples we publish can be run without some kind of bundler, such as webpack or the Closure Compiler, or other build step, to combine and/or convert the developer code and Blockly modules into a compatible form.
Request
- Make it possible to
importBlockly in a browser without needing a build step, by publishing Blockly as an ES module (or, more accurately, as one ES module for each chunk:blockly,blocks,javascriptetc.) Althoughimport … from 'blockly'cannot work in a browser without an import map, it should be possible toimport * as Blockly from './path/to/blockly.js';(or'…/blockly.mjs'`, depending on choices discussed below). - Continue, for the time being at least, to support loading Blockly as a
<script>and/or as a CJS module viarequire().
Alternatives considered
The NPM format allows publication of hybrid ESM+CJS modules. This is done by having separate "main": and "module": entries in the package's package.json file, pointing at the CJS and MJS entry points for the package respectively. For subpackages such as blockly/blocks there is an "exports": directive supported by node.js and by webpack, but this is not part of the official NPM package.json format.
There are at least two possible approaches to how such hybrid packages work, however:
- The package can contain two completely separate copies of each entry point module: one built as an ES module and the other as a CJS module. Here is a description of how such a dual-binary package might be created.
- The package can each entry point module built as a CJS module, and an thin ESM wrapper that loads the CJS module and re-
exportsits exports. This is roughly akin to what the loading shims introduced in PR refactor(tests): Introduce loading shims, use in playgrounds #7380 do when loading Blockly in compressed mode. This article explains why this approach might be preferred and details about how to implement it (along with much additional background information about the ESM vs. CJS situation).
Additional context
-
Although the UMD format allows one to publish a single file that can be treated as a plain script, as an AMD module or as a CJS module, there is no way for a file to be simultaneously both a UMD module and also an ES module—at least, not if it has any exports, because the
exportkeyword is only legal in an ES module, and it is not possible to export anything from an ESM without using theexportkeyword. This means that there must be at least two entry point files present (one for ESM and one for UMD) in any package if it is to support being loaded both withimportandrequire(). -
Although we should continue to support loading Blockly as a CJS module for the time being—at minimum to provide a substantial transition period in which developers can move to using the ESM version—we may well wish to ultimately ship the
blocklyNPM as ESM-only. There may be some value in continuing to support CJS in the long term, but UMD's abilito to allow one to load Blockly via<script>is largely unnecessary when all current browsers now support<script type="module"> import * as Blockly from './path/to/blockly.js';.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status