playcanvas
Version:
PlayCanvas WebGL game engine
105 lines (102 loc) • 3.57 kB
JavaScript
import { platform } from '../../core/platform.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 {
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, url, 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 = url.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) ;
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 };