Skip to content

Commit

Permalink
fix(tests): Fix bootstrapping of generators in compressed mode (googl…
Browse files Browse the repository at this point in the history
…e#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.
  • Loading branch information
cpcallen authored Dec 14, 2022
1 parent 768d184 commit f528ecc
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 27 deletions.
37 changes: 35 additions & 2 deletions tests/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
};

Expand Down Expand Up @@ -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>`);
}
Expand Down
80 changes: 55 additions & 25 deletions tests/bootstrap_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
})();

0 comments on commit f528ecc

Please sign in to comment.