/** * @license * Copyright 2023 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /** * @fileoverview Helper functions for loading Blockly in tests. * * Used by playgrounds and test harnesses, both directly and via the * shims generated by the buildShims function in * scripts/gulpfiles/build_tasks.js. * */ if (typeof window !== 'object') { // Not running in a browser. Maybe we wish to support this? // blockly_uncompressed formerly supported node.js, though it // appears that the code had not been working for some time (at // least since PR #5718 back in December 2021. For now just throw // an error. throw new Error('Bootstrapping without window is not supported.'); } /** * URL of the blockly repository. This is needed for a few reasons: * * - We need an absolute path instead of relative path because the * advanced_playground and the regular playground are in * different folders. * - We need to get the root directory for blockly because it is * different for github.io, appspot and local. * * The formulation given here will work so long as top-level page is loaded from * somewhere in tests/. */ export const ROOT = window.location.href.replace(/\/tests\/.*$/, '/'); /** * Decide whether to use compressed mode or not. * * Honours a "?compressed=" query parameter if present; otherwise uses * uncompressed for when loading from local machine and compressed * otherwise. See issue #5557 for additional background. * * @return {boolean} True if should load in compressed mode. */ function compressed() { const param = location.search.match(/compressed=([^&]+)/)?.[1]; if (param) { if (['y', 'yes', 'true', '1'].includes(param)) return true; if (['n', 'no', 'false', '0'].includes(param)) return false; console.error(`Unrecognised compressed parameter "${param}"`); } const LOCALHOSTS = ['localhost', '127.0.0.1', '[::1]']; const isLocalhost = LOCALHOSTS.includes(location.hostname); const isFileUrl = location.origin === 'file://'; return !(isLocalhost || isFileUrl); } /** @type {boolean} Load in compressed mode. */ export const COMPRESSED = compressed(); /** * Load a chunk, either by importing its ESM entrypoint or loading the * compressed chunk script. * * When loading in uncompressed mode, if scriptExports is a simple * variable name (e.g. 'Blockly') then globalThis[scriptExports] will * be set to the chunk's Module object. This attempts to provide * backward compatibility with loading the compressed chunk as a * script, where this is done by the compressed chunk's UMD wrapper. * The compatibility is not complete, however: since Module objects * are immutable, it is not possible to set (e.g.) * Blockly.libraryBlocks. * * The intention is to allow the chunk to be accessed either via * the returned Module / exports object (preferred) or via the global * scope (needed by dev-tools) regardless of whether it was loaded * compressed or uncompressed. * * Paths should be relative to the repository root. * * @param {string} modulePath Path to the chunk's ESM entry point. * @param {string} scriptPath Path to the chunk's _compressed.js file. * @param {string} scriptExports The global variable name (or * dotted-identifier path relative from a global variable) in * which the compressed chunk's UMD wrapper will save the module's * exports object. Should be the same as the correspodning * chunks[].scriptExport property in * scripts/gulpfiles/build_tasks.js. * @return {Module} The module's Module or exports object. */ export async function loadChunk(modulePath, scriptPath, scriptExports) { if (COMPRESSED) { await loadScript(`${ROOT}${scriptPath}`); return get(scriptExports); } else { const exports = await import(`../../${modulePath}`); if (!scriptExports.includes('.')) globalThis[scriptExports] = exports; return exports; } } /** * Load a given URL using a