control order that scripts are loaded?

  • is there a way to control the order in which scripts are loaded on the page? if i have serveral js files how can i ensure they are loaded in a specific order.

  • What I have found so far is that it groups everything alphabetically when adding scripts. So if I add a base class after I add the super class, it fails because the base didn't load. If I then create a sub folder called "A" and move the base class into that folder, it's not read before the super class and everything loads.

    Not sure if they'll give us more flexibility with this later on, but you can make it work.

    I have almost reworked my entire game into mostly JavaScript and that's how I worked around it.

  • the folder thing is nice, i did not think of that, i have been merging all my js into one file in the order i needed. but that get really tiring when you have more than 1000 lines in one file. thanks.

  • In JS land you would use a module loader to deal with this normally, the files are already loaded so you don't really need to worry about waiting for the file to load. You just need the blocks to execute in the correct order.

    const moduleInitalisers = new Map;
    const moduleDirectory = new Map;
    
    function define(moduleID, dependancies, moduleInitialiser) {
    	if (moduleInitalisers.has(moduleID))
     		throw new Error(`"${moduleID}" has already been defined`);
    	moduleInitalisers.set(moduleID, [dependancies, moduleInitialiser]);
    }
    
    function require(moduleID) {
     	function getModule(moduleID, parents) {
     		if (moduleDirectory.has(moduleID))
     			return moduleDirectory.get(moduleID);
    
     		const isCircular = parents.includes(moduleID);
    
     		parents.push(moduleID);
     
     		if (isCircular)
     			throw new Error(`Circular dependancy ${parents.join(" -> ")}`);
     
     		const [dependancies, initialiser] = moduleInitalisers.get(moduleID);
     		const mod = initialiser(...dependancies.map(m => getModule(m, parents.slice(0))));
     
     		moduleDirectory.set(moduleID, mod);
    
     		return mod;
     	}
     	return getModule(moduleID, []);
    }
    

    This is a very simple module loader. For each module you have you call "define" with a unique module name, a list of modules it depends on, and an initialiser function that returns the module.

    To load a module you call "require" with the module name. It will load all the modules that it depends on, then calls the initialiser with those modules as arguments. The module is then returned.

    Example use:

    define("Lemon", ["Fruit"], Fruit => {
     	return class Lemon extends Fruit {};
    })
    
    define("Strawberry", ["Fruit"], Fruit => {
    	return class Strawberry extends Fruit {};
    })
    
    define("Peach", ["Fruit"], Fruit => {
     	return class Peach extends Fruit {};
    })
    
    define("Fruit", [], () => {
     	return class Fruit {};
    })
    
    define("FruitSalad", ["Lemon", "Strawberry", "Peach"], (Lemon, Strawberry, Peach) => {
     	return class FruitSalad {
     		constructor () {
     			this.contains = [
     				new Lemon,
     				new Strawberry,
     				new Peach
     			];
     		}
     	}
    })
    
    const FruitSalad = require("FruitSalad");
    
    const mysalad = new FruitSalad;
    

    There's a few minor restrictions you need to be aware of though. The module loader itself has to be loaded BEFORE anything else, the require call has to be AFTER all the needed modules have been defined and you cannot do circular dependencies.

    The initialiser for a module is only ever called once, so this probably works best if you define the loader and the modules in script files. Then "require" the modules from inline script blocks as needed.

    If you need it then it is possible to write module loaders that support circular dependencies but they add additional restrictions that are somewhat awkward.

  • The script order isn't really well defined - I'd avoid using subfolder hacks because that's depending on weird details that might change over time.

    Normally you can just put all startup code in runOnStartup and all classes will be defined by then. However I can see it's a problem for using class X extends Y - X has to come after Y.

    You could just put both classes in the same file, one after the other, but that's not great for large classes. I think the best approach is to move any script files that depends on others to the Files folder in the project bar, so they're not automatically loaded, and then use loadScripts to load them in the right order. You can pass multiple scripts to a single loadScripts call and they are guaranteed to run in the order you pass them.

  • I really like the approach of LoadScripts. I will change things over to use that instead of relying on folder order.

  • using load scripts is a good idea, so the project files does not have an option to create a new js file, that only exists under the script folder. a work around is to import the js file, using the project file import. but if you wanted to create one that option is missing

  • but if you wanted to create one that option is missing

    Good point, added an option for the next release.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Does this mean that if we add the js files to the imported files section that command/syntax checking will happen like in the scripts folder ?

  • I don't think that happens currently, when I import js script on project section I don't get syntax highlighting or errors.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)