This probably only applies to Babylon.js Playground.
The code below works in Chrome but gives an error in Safari.
In Safari, the const variable SCALE seems to be undefined in the addGround function.
const SCALE = 1 / 10; // TODO: "Can't find variable: SCALE" error in Safari
const createScene = function () {
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
light.intensity = 0.7;
const sphere = BABYLON.MeshBuilder.CreateSphere(
"sphere",
{ diameter: 2, segments: 32 },
scene
);
sphere.position.y = 1;
addGround(scene);
return scene;
};
function addGround(scene) {
// "Can't find variable: SCALE" error in Safari
const ground = BABYLON.MeshBuilder.CreateGround(
"ground",
{ width: 60 * SCALE, height: 60 * SCALE },
scene
);
}
I think this is due to the difference in how Chrome and Safari handle scopes.
There seem to be some workarounds, but I can’t decide which one is better.
Can you give me some good advice?
Idea 1) Use var instead of const
//const SCALE = 1/10;
var SCALE = 1/10;
Idea 2) Assign function to variable
//function addGround(scene) {
const addGround = function (scene) {
Thank you for your advice.
I think modern JavaScript should use const and let over var, but a simple way to solve this case might be to use var.
The following is a simplified representation of the part that dynamically executes JavaScript in Babylon.js Playground.
It seems that the Safari error can be resolved by removing the { } in the try-catch, but since it’s putting the cart before the horse, I think I’ll give up.
let code = `const SCALE = 1 / 10; // TODO: "Can't find variable: SCALE" error in Safari
const createScene = function() {
console.log("createScene()");
addGround();
};
function addGround() {
console.log("addGround()");
// "Can't find variable: SCALE" error in Safari
console.log("width:" + 60 * SCALE);
}
window.initFunction = async function() {
window.scene = createScene();
}
`;
function FastEval(code) {
const head = document.getElementsByTagName("head")[0];
const script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.innerHTML = `try {${code};}
catch(e) {
console.log(e);
}`; // Error in Safari
//script.innerHTML = `{${code};}`; // Error in Safari
//script.innerHTML = `${code};`; // No Errors in Safari
head.appendChild(script);
}
async function init() {
FastEval(code);
window.initFunction();
}
init();
Well, that makes little to no sense to me (from Safari’s side). The functions are being evaluated together with the initial const. It is a part of the scope of this specific script. We are not using module or anything fancy, just a script tag. Also, they can’t claim it’s a hoisting issue, as the variable is defined and set before the function is even evaluated (let alone executed).
Why is “createScene” defined and working well, but not SCALE?..
I don’t have a mac to test it, but that is most certainly a bug on their end (Unless it is some very weird quirk in the JS definitions that makes no sense but Safari decided to follow it )
Please let me know if you know.
There was a document on MDN that seemed to be related.
Does this mean that it is better to use function expressions instead of function declarations in non-strict mode?