refactor(build)!: Provide all generator exports when loaded as script (#7169)

Previously, when loading a generator chunk (e.g.,
javascript_compressed.js) as a script (e.g., in a browser using
a <SCRIPT> tag), only a single named export from that chunk would
be made available (e.g, javascriptGenerator would be made availabe
as Blockly.JavaScript).

Until recently, that was fine because each generator chunk had only
a single named export, but now each one additionally has a
<Lang>Generator class and Order enum export.

To allow these new exports to be accessed by script users, the
chunk wrappers are modified to provide the whole export object
at a correspondingly-named global variable—e.g., when loaded as
a script javascript_compressed.js creates a global variable named
javascript, so the named exports can be accessed as
javascript.javascriptGenerator, javascript.JavascriptGenerator
and javascript.Order, as if the user had imported them via

    import * as javascript from 'blockly/javascript';

This PR includes a breaking change and a deprecation, both of
which are only applicable when loading generators as scripts
(e.g. via a <SCRIPT> tag):

BREAKING CHANGE: The generator chunks will, when loaded as scripts
(e.g. via a <SCRIPT> tag, now clobber any existing global variable
of the corresponding name:

- dart_compresed.js will set dart
- javascript_compresed.js will set javascript
- lua_compresed.js will set lua
- php_compresed.js will set php
- python_compresed.js will set python

DEPRECATION: Accessing the generator instances at their previous
locations (Blockly.Dart, Blockly.JavaScript, Blockly.Lua,
Blockly.PHP, and Blockly.Python) is deprecated and may cease
to work in a future version of Blockly.
This commit is contained in:
Christopher Allen
2023-06-15 16:52:51 +01:00
committed by GitHub
parent a3458871db
commit 2d97e5aaf1

View File

@@ -75,12 +75,15 @@ const NAMESPACE_PROPERTY = '__namespace__';
* chunk.
* - .exports: an expression evaluating to the exports/Module object
* of module that is the chunk's entrypoint / top level module.
* - .reexport: if running in a browser, save the chunk's exports
* object (or a single export of it; see reexportOnly, below) at
* this location in the global namespace.
* - .reexportOnly: if reexporting and this property is set,
* save only the correspondingly-named export. Otherwise
* save the whole export object.
* - .scriptExport: When the chunk is loaded as a script (e.g., via a
* <SCRIPT> tag), the chunk's exports object will be made available
* at the specified location (which must be a variable name or the
* name of a property on an already-existing object) in the global
* namespace.
* - .scriptNamedExports: A map of {location: namedExport} pairs; when
* loaded as a script, the specified named exports will be saved at
* the specified locations (which again must be global variables or
* properties on already-existing objects). Optional.
*
* The function getChunkOptions will, after running
* closure-calculate-chunks, update each chunk to add the following
@@ -97,48 +100,48 @@ const chunks = [
name: 'blockly',
entry: path.join(TSC_OUTPUT_DIR, 'core', 'main.js'),
exports: 'module$build$src$core$blockly',
reexport: 'Blockly',
scriptExport: 'Blockly',
},
{
name: 'blocks',
entry: path.join(TSC_OUTPUT_DIR, 'blocks', 'blocks.js'),
exports: 'module$exports$Blockly$libraryBlocks',
reexport: 'Blockly.libraryBlocks',
scriptExport: 'Blockly.libraryBlocks',
},
{
name: 'javascript',
entry: path.join(TSC_OUTPUT_DIR, 'generators', 'javascript', 'all.js'),
exports: 'module$build$src$generators$javascript$all',
reexport: 'Blockly.JavaScript',
reexportOnly: 'javascriptGenerator',
scriptExport: 'javascript',
scriptNamedExports: {'Blockly.Javascript': 'javascriptGenerator'},
},
{
name: 'python',
entry: path.join(TSC_OUTPUT_DIR, 'generators', 'python', 'all.js'),
exports: 'module$build$src$generators$python$all',
reexport: 'Blockly.Python',
reexportOnly: 'pythonGenerator',
scriptExport: 'python',
scriptNamedExports: {'Blockly.Python': 'pythonGenerator'},
},
{
name: 'php',
entry: path.join(TSC_OUTPUT_DIR, 'generators', 'php', 'all.js'),
exports: 'module$build$src$generators$php$all',
reexport: 'Blockly.PHP',
reexportOnly: 'phpGenerator',
scriptExport: 'php',
scriptNamedExports: {'Blockly.PHP': 'phpGenerator'},
},
{
name: 'lua',
entry: path.join(TSC_OUTPUT_DIR, 'generators', 'lua', 'all.js'),
exports: 'module$build$src$generators$lua$all',
reexport: 'Blockly.Lua',
reexportOnly: 'luaGenerator',
scriptExport: 'lua',
scriptNameExports: {'Blockly.Lua': 'luaGenerator'},
},
{
name: 'dart',
entry: path.join(TSC_OUTPUT_DIR, 'generators', 'dart', 'all.js'),
exports: 'module$build$src$generators$dart$all',
reexport: 'Blockly.Dart',
reexportOnly: 'dartGenerator',
scriptExport: 'dart',
scriptNameExports: {'Blockly.Dart': 'dartGenerator'},
}
];
@@ -441,7 +444,7 @@ function chunkWrapper(chunk) {
// JavaScript expressions for the amd, cjs and browser dependencies.
let amdDepsExpr = '';
let cjsDepsExpr = '';
let browserDepsExpr = '';
let scriptDepsExpr = '';
// Arguments for the factory function.
let factoryArgs = '';
// Expression to get or create the namespace object.
@@ -452,25 +455,22 @@ function chunkWrapper(chunk) {
JSON.stringify(`./${chunk.parent.name}${COMPILED_SUFFIX}.js`);
amdDepsExpr = parentFilename;
cjsDepsExpr = `require(${parentFilename})`;
browserDepsExpr = `root.${chunk.parent.reexport}`;
scriptDepsExpr = `root.${chunk.parent.scriptExport}`;
factoryArgs = '__parent__';
namespaceExpr = `${factoryArgs}.${NAMESPACE_PROPERTY}`;
}
// Code to assign the result of the factory function to the desired
// export location when running in a browser. When
// chunk.reexportOnly is set, this additionally does two other
// things:
// - It ensures that only the desired property of the exports object
// is assigned to the specified reexport location.
// - It ensures that the namesspace object is accessible via the
// selected sub-object, so that any dependent modules can obtain
// it.
const browserExportStatements = chunk.reexportOnly ?
`root.${chunk.reexport} = factoryExports.${chunk.reexportOnly};\n` +
` root.${chunk.reexport}.${NAMESPACE_PROPERTY} = ` +
`factoryExports.${NAMESPACE_PROPERTY};` :
`root.${chunk.reexport} = factoryExports;`;
// Code to save the chunk's exports object at chunk.scriptExport and
// additionally save individual named exports as directed by
// chunk.scriptNamedExports.
const scriptExportStatements = [
`root.${chunk.scriptExport} = factory(${scriptDepsExpr});`,
];
for (var location in chunk.scriptNamedExports) {
const namedExport = chunk.scriptNamedExports[location];
scriptExportStatements.push(
`root.${location} = root.${chunk.scriptExport}.${namedExport};`);
}
// Note that when loading in a browser the base of the exported path
// (e.g. Blockly.blocks.all - see issue #5932) might not exist
@@ -485,9 +485,8 @@ function chunkWrapper(chunk) {
define([${amdDepsExpr}], factory);
} else if (typeof exports === 'object') { // Node.js
module.exports = factory(${cjsDepsExpr});
} else { // Browser
var factoryExports = factory(${browserDepsExpr});
${browserExportStatements}
} else { // Script
${scriptExportStatements.join('\n ')}
}
}(this, function(${factoryArgs}) {
var ${NAMESPACE_VARIABLE}=${namespaceExpr};