fix(tests): Fix bootstrapping of generators in compressed mode (#6703)

Previously we had code that would, in uncompiled mode, make sure
that javascriptGenerator etc. were set to the corresponding module
exports object (by fetching it with goog.module.get), but in
compressed mode we made no effort to set (e.g.) javascriptGenerator
to Blockly.JavaScript, which is where that export actually appears
in the namespace tree when loading the chunk via a <script> tag.

This commit introduces two new configuration options to bootstrap.js
(preconfigured with defaults that should work in most cases) mapping
global variable names to their corresponding module identifiers, and
modifies the code in bootstrap_helper.js to set global variables
appropriately in both uncompressed and compressed modes.
This commit is contained in:
Christopher Allen
2022-12-14 19:47:27 +00:00
committed by GitHub
parent 768d18468a
commit f528eccba7
2 changed files with 90 additions and 27 deletions

37
tests/bootstrap.js vendored
View File

@@ -92,6 +92,34 @@
'dist/python_compressed.js',
],
// List of imports to give global names to. The keys are the
// global variable names, the values are goog.module IDs to name,
// or (when loading in compressed mode) the paths within the
// Blockly namespace at which the corresponding chunk is loaded by
// its UMD wrapper. Note that entries in this map are ignored if
// the corresponding goog.module has not been loaded via an entry
// in requires or compressedScripts.
namedImports: {
Blockly: 'Blockly',
libraryBlocks: 'Blockly.libraryBlocks',
},
// List of destructured imports. As for namedImports, but only
// the named export corresponding to the mentioned global variable
// will be imported.
//
// Exception: in compressed mode, the UMD wrapeprs generated by
// chunkWrapper() in scripts/gulpfiles/build_tasks.js already pull
// out the desired named export - so in that case the entries here
// are treated identically to those in namedImports.
destructuredImports: {
dartGenerator: 'Blockly.Dart',
javascriptGenerator: 'Blockly.JavaScript',
luaGenerator: 'Blockly.Lua',
phpGenerator: 'Blockly.PHP',
pythonGenerator: 'Blockly.Python',
},
// Additional scripts to be loaded after Blockly is loaded,
// whether Blockly is loaded from compressed or uncompressed.
// Paths relative to root.
@@ -117,6 +145,8 @@
window.bootstrapInfo = {
/** boolean */ compressed: options.loadCompressed,
/** ?Array<string> */ requires: null,
/** Object<string> */ namedImports: options.namedImports,
/** Object<string> */ destructuredImports: options.destructuredImports,
/** ?Promise */ done: null,
};
@@ -188,8 +218,11 @@
} else {
// We need to load Blockly in compressed mode. Load
// blockly_compressed.js et al. using <script> tags.
const scripts =
[...options.compressedScripts, ...options.additionalScripts];
const scripts = [
...options.compressedScripts,
'tests/bootstrap_helper.js',
...options.additionalScripts,
];
for (const script of scripts) {
document.write(`<script src="${options.root + script}"></script>`);
}

View File

@@ -14,30 +14,60 @@
* undeclared dependencies on them.
*/
/* eslint-disable-next-line no-undef */
for (const require of window.bootstrapInfo.requires) {
goog.require(require);
(function() {
const info = window.bootstrapInfo;
// If require is a top-level chunk, create a global variable for it.
// This replaces the goog.module.declareLegacyNamespace calls that
// previously existed in each chunk entrypoint.
const exportName = {
'Blockly.Dart': 'dartGenerator',
'Blockly.Dart.all': 'dartGenerator',
'Blockly.JavaScript': 'javascriptGenerator',
'Blockly.JavaScript.all': 'javascriptGenerator',
'Blockly.Lua': 'luaGenerator',
'Blockly.Lua.all': 'luaGenerator',
'Blockly.PHP': 'phpGenerator',
'Blockly.PHP.all': 'phpGenerator',
'Blockly.Python': 'pythonGenerator',
'Blockly.Python.all': 'pythonGenerator',
}[require];
if (exportName) {
window[exportName] = goog.module.get(require)[exportName];
} else if (require === 'Blockly') {
window.Blockly = goog.module.get(require);
} else if (require === 'Blockly.libraryBlocks') {
window.libraryBlocks = goog.module.get(require);
if (!info.compressed) {
// Force debug module loader to finish loading all modules.
for (const require of info.requires) {
goog.require(require);
// This is a kludge to work around an issue where attempting to
// load Blockly.libraryBlocks (blocks/blocks.js) fails if the
// Blockly global variable is not defined.
//
// This is apparently because the debug module loader fails to
// load Blockly.libraryBlocks.lists (blocks/lists.js) and
// .procedures (blocks/procedures.js) first, despite they both
// being required from blocks.js, and that is apparently because
// they both depend on Blockly.Xml which the debug loader seems
// to think has not been loaded yet even though it has.
if (require === 'Blockly') {
window.Blockly = goog.module.get('Blockly');
}
}
}
}
// Create global names for named and destructured imports.
for (const varName in info.namedImports) {
const id = info.namedImports[varName];
const value = info.compressed ? get(id) : goog.module.get(id);
if (value) {
window[varName] = value;
}
}
for (const varName in info.destructuredImports) {
const id = info.destructuredImports[varName];
const value = info.compressed ? get(id) : goog.module.get(id)[varName];
if (value) {
window[varName] = value;
}
}
return; // All done. Only helper functions after this point.
/**
* Get the object referred to by a doted-itentifier path
* (e.g. foo.bar.baz).
* @param {string} path The path referring to the object.
* @return {string|null} The object, or null if not found.
*/
function get(path) {
let obj = window;
for (const part of path.split('.')) {
obj = obj[part];
if (!obj) return null;
}
return obj;
}
})();