UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

119 lines (118 loc) 4.04 kB
import { platform } from "../../core/platform.js"; import { Debug } from "../../core/debug.js"; import { script } from "../script.js"; import { ScriptTypes } from "../script/script-types.js"; import { registerScript } from "../script/script-create.js"; import { ResourceLoader } from "./loader.js"; import { ResourceHandler } from "./handler.js"; import { Script } from "../script/script.js"; const toLowerCamelCase = (str) => str[0].toLowerCase() + str.substring(1); class ScriptHandler extends ResourceHandler { /** * Create a new ScriptHandler instance. * * @param {AppBase} app - The running {@link AppBase}. * @ignore */ constructor(app) { super(app, "script"); this._scripts = {}; this._cache = {}; } clearCache() { for (const key in this._cache) { const element = this._cache[key]; const parent = element.parentNode; if (parent) { parent.removeChild(element); } } this._cache = {}; } load(url, callback) { if (typeof url === "string") { url = { load: url, original: url }; } const self = this; script.app = this._app; const onScriptLoad = (url.load, (err, url2, extra) => { if (!err) { const obj = {}; for (let i = 0; i < ScriptTypes._types.length; i++) { obj[ScriptTypes._types[i].name] = ScriptTypes._types[i]; } ScriptTypes._types.length = 0; callback(null, obj, extra); const urlWithoutEndHash = url2.split("&hash=")[0]; delete self._loader._cache[ResourceLoader.makeKey(urlWithoutEndHash, "script")]; } else { callback(err); } }); const [basePath] = url.load.split("?"); const isEsmScript = basePath.endsWith(".mjs"); if (isEsmScript) { this._loadModule(basePath, onScriptLoad); } else { this._loadScript(url.load, onScriptLoad); } } open(url, data) { return data; } patch(asset, assets) { } _loadScript(url, callback) { const head = document.head; const element = document.createElement("script"); this._cache[url] = element; element.async = false; element.addEventListener("error", (e) => { callback(`Script: ${e.target.src} failed to load`); }, false); let done = false; element.onload = element.onreadystatechange = function() { if (!done && (!this.readyState || (this.readyState === "loaded" || this.readyState === "complete"))) { done = true; callback(null, url, element); } }; element.src = url; head.appendChild(element); } _loadModule(url, callback) { const isBrowserWithOrigin = platform.browser && window.location.origin !== "null"; const baseUrl = isBrowserWithOrigin ? window.location.origin + window.location.pathname : import.meta.url; const importUrl = new URL(url, baseUrl); import( /* @vite-ignore */ /* webpackIgnore: true */ importUrl.toString() ).then((module) => { const filename = importUrl.pathname.split("/").pop(); const scriptSchema = this._app.assets.find(filename, "script")?.data?.scripts; for (const key in module) { const scriptClass = module[key]; const extendsScriptType = scriptClass.prototype instanceof Script; if (extendsScriptType) { const lowerCamelCaseName = toLowerCamelCase(scriptClass.name); if (!scriptClass.scriptName) { Debug.warnOnce(`The Script class "${scriptClass.name}" must have a static "scriptName" property: \`${scriptClass.name}.scriptName = "${lowerCamelCaseName}";\`. This will be an error in future versions of PlayCanvas.`); } const scriptName = scriptClass.scriptName ?? lowerCamelCaseName; registerScript(scriptClass, scriptName); if (scriptSchema) this._app.scripts.addSchema(scriptName, scriptSchema[scriptName]); } } callback(null, url, null); }).catch((err) => { callback(err); }); } } export { ScriptHandler };