Unexpected token 'export' when exporting scenes?

Like this developer, I was following along with this post. Unfortunately, I got an error that says it doesn’t know what “export” means, and I don’t know how to fix it (though, it does load the title scene). Additionally, I’m not sure how to call other JS files from each method of the class (example later). If someone has the time to help, I’d greatly appreciate it.

game.js

import TitleScene from '/js/titleScene.js';
import GameScene from '/js/gameScene.js';

var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [TitleScene, GameScene]
};

var game = new Phaser.Game(config);

titleScene.js

class TitleScene extends Phaser.Scene {

	constructor() {
		super({ key: 'titleScene' });
	}

	preload = function () {
        this.load.image('background', 'assets/title/welcome.png');
    };

    create = function () {
        var bg = this.add.sprite(0, 0, 'background');
        bg.setOrigin(0, 0);

        var text = this.add.text(100, 100, 'Welcome to my game!');
        text.setInteractive({ useHandCursor: true });
        text.on('pointerdown', () => this.clickButton());
    };

    clickButton() {
        this.scene.switch('gameScene');
    }
}

export default TitleScene;

gameScene.js

class GameScene extends Phaser.Scene {

	constructor() {
		super({ key: 'gameScene' });
	}

	// Is it possible to call other JS files from here?  
	// If I have "gameCreate.js", can I call that from the create() method below ?
	init() { };

	preload() { }

	create() { }

	update() { }

	end() { }

}

export default GameScene;

Script loading:

<script src="~/js/phaser.js"></script>
<script src="~/js/preload.js"></script>
<script src="~/js/create.js"></script>
<script src="~/js/update.js"></script>
<script src="~/js/game.js"></script>
<script src="~/js/player.js"></script>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>

Please forgive me if this is an asinine question, I’m not sure why the export isn’t working.

For each script that includes export, remove the <script> for it. The imports should all go through game.js.

Also, final scene setup in the tutorial is more complicated than it needs to be. You can just use

import TitleScene from './titleScene.js';
import GameScene from './gameScene.js';

var config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  scene: [ TitleScene, GameScene ]
};

var game = new Phaser.Game(config);
1 Like

I think I understand the point of it, but it still breaks.

If I remove the two tags importing titleScene.js and gameScene.js, and add the “module” type to game.js

<script type="module" src="~/js/game.js"></script>

And my relative paths start with /

import TitleScene from '/js/titleScene.js';
import GameScene from '/js/gameScene.js';

I get an “Uncaught SyntaxError: Cannot use import statement outside a module” message in the console.

I thought perhaps it was my paths, but those check out, and game.js is specified as being a module. Can you think of anything else that I might be doing wrong?

Is this error definitely in game.js?

1 Like

Definitely, it’s breaking as soon as it hits the first import statement:

import TitleScene from '/js/titleScene.js';

I updated each file above in my original post to reflect the current code.

Look at the HTML source in the browser with the error, verify it has

<script type="module" src="~/js/game.js"></script>

and no other script for game.js.

1 Like

Very strange…I got it to work. But in order to do that, I had to make the code changes so that they were correct (type=“module”, etc), and then close down VS22, open it back up, and then hit the page. For some reason, it wasn’t registering that I had made changes…which was apparent when I had an entire code block commented out in game.js, but it was still showing up in the Sources tab in the debugger in Chrome. Weird.

So now that I have titleScene.js loaded and working, it will call gameScene.js when that’s done. However, in the gameScene.js file, the functions in there are empty.

class GameScene extends Phaser.Scene {

	constructor() {
		super({ key: 'gameScene' });
	}

	init() { };

	preload() { }  // How do I get this preload to load up my /js/preload.js content?

	create() { }

	update() { }

	end() { }

}

export default GameScene;

How do I go about telling them to use content from other files. For example, previously I had game.js, which had:

    scene: {
        preload: preload,
        create: create,
        update: update
    }

and each file (preload.js, create.js, update.js) would load for them. I’m not seeing how to do that in Phaser.Scene - Phaser 3 API Documentation (beta).

Thank you for the awesome help so far.

If you’re using scene classes, you give the class or an instance in the game config:

scene: [ TitleScene, GameScene ]

And usually you would just move your preload code into GameScene’s preload() method. However, you could export and import that too.

function preload () {/* … */}

export default preload;
import preload from '/js/preload.js';

class GameScene extends Phaser.Scene {/* … */}

GameScene.prototype.preload = preload;

export default GameScene;
1 Like

Interesting!

So in game.js, I added the imports and set the GameScene prototypes to what I was importing…

import TitleScene from '/js/titleScene.js';
import GameScene from '/js/gameScene.js';
import preload from '/js/preload.js';
import create from '/js/create.js';
import update from '/js/update.js';

GameScene.prototype.preload = preload;
GameScene.prototype.create = create;
GameScene.prototype.update = update;


var config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [TitleScene, GameScene]
};

var game = new Phaser.Game(config);

Then have gameScene.js like this…

class GameScene extends Phaser.Scene {

	constructor() {
		super({ key: 'gameScene' });
	}

	// Is it possible to call other JS files from here?  
	// If I have "gameCreate.js", can I call that from the create() method below ?
	init() { };

	preload() { }

	create() { }

	update() { }

	end() { }

}

export default GameScene;

And for example, create.js is like this:

function create() {

    // Set world bounds
    this.physics.world.setBounds(0, 0, 800, 252);

    // Other stuff
}

export default create;

I end up getting two errors in the console:

The first error with “unexpected token ‘export’” for the export default xyz at the end of each file.

The other I assume has to do with this not meaning what I think it’s meaning, but I’m unsure of what to refer to when setting those world bounds.

I would do this in gameScene.js, if at all.

Probably you need to remove <script>s for those from the main document.

The second error is telling you that this.physics is undefined, probably because the scene has no Arcade Physics.

class GameScene extends Phaser.Scene {
  constructor() {
    super({
      key: 'gameScene',
      physics: { arcade: {} }
    });
  }
}
1 Like

Thank you. I’m really grateful for the help, but I feel like I’m just not understanding how to go about structuring everyything.

I would do this in gameScene.js, if at all.

How else would you approach it? For example, I followed the tutorial and ended up with a structure like this:

  • game.js
    • preload.js
    • create.js
    • update.js

That was really easy, but I’m already hitting the point where it’s making it very messy, with a huge create.js file. What I’d like to do is restructure everything so that I can split that up into other files, I’m just not sure how Phaser does that.

  • titleScene.js
    • preload.js
    • create.js
    • update.js
  • game.js
    • preload.js
    • create.js
    • update.js
    • (and other classes in their own .js file)

If this were your game, and you just wanted a title scene, a game scene, and maybe an end scene, how would you go about doing that and setting it up? I can’t seem to find any examples of this on the Explorer page or the Examples page.

I mean that if you want to modify GameScene.prototype, it makes sense to do it in gameScene.js, where it’s being created and exported.

It’s a little unusual to split up a class into separate modules, but you can still do it. If the main scene methods get unruly people usually add helper methods:

class GameScene extends Phaser.Scene {
  // …
  create() {
    this.createPlayer();
  }

  createPlayer() {
    /* … */
  }

  update() {
    this.updatePlayer();
  }

  updatePlayer() {
    /* … */
  }
}

See the multiscene games in the official examples.

You can also modularize those functions, if you call them in the scene context:

import createPlayer from './createPlayer.js';
import updatePlayer from './updatePlayer.js';

class GameScene extends Phaser.Scene {
  // …
  create() {
    createPlayer.call(this);
  }

  update() {
    updatePlayer.call(this);
  }
}
1 Like

Ahh, that’s what I was trying to do! I don’t understand something though.

When I set up GameScene.js like this:

import gamePreload from '/js/preload.js';
import gameCreate from '/js/create.js';
import gameUpdate from '/js/update.js';

class GameScene extends Phaser.Scene {

	constructor() {
		super({ key: 'gameScene' });
	}

	preload() {
		gamePreload.call(this);
	}

	create() {
		gameCreate.call(this);
	}

	update() {
		gameUpdate.call(this);
	}

	end() { }

}

export default GameScene;

And then load something like gameCreate.js like this:


function gameCreate() {

    // Set world bounds
    this.physics.world.setBounds(0, 0, 800, 252);
}

It doesn’t understand what world is. When I log this to the console, it recognizes the scene (GameScene) but this.physics comes back as undefined (which should be where Phaser.Physics.Arcade.World exists, right?).

Arcade Physics needs to be enabled in the scene or game config.

class GameScene extends Phaser.Scene {
  constructor() {
    super({
      key: 'gameScene',
      physics: { arcade: {} }
    });
  }
  // etc.
}
1 Like

Oooh, that makes sense!

Is there a way to persist something like the player through multiple functions then?

For example, if I declare my player and initialize my player in my create function, it’s undefined in the update function. But if we set the physics on the scene, why wouldn’t it recognize physics.add.sprite?

gameScene.js

class GameScene extends Phaser.Scene {

	constructor() {
		super({
			key: 'gameScene',
			physics: {
			    default: 'arcade',
			    arcade: {
			        debug: false
			    }
			},
		});
	}

	preload() {
		gamePreload.call(this);
	}

	create() {
		gameCreate.call(this);
	}

	update() {
		gameUpdate.call(this);
	}
}

gameCreate.js

function gameCreate() {
    var ship, asteroids, cursors, events;

    // Player
    player = this.physics.add.sprite(1000, 252, 'dude');

and then gameUpdate.js

function gameUpdate() {
    // Camera follows player
    // Breaks on 'player.x', as player is undefined?
    scrollX = player.x - game.config.width / 2;
    this.cameras.main.scrollX = scrollX;
}

Store it on the scene.

this.player = this.physics.add.sprite(1000, 252, 'dude');
1 Like

So if I store something in the scene(this.player) then I’ll need to refer to it everywhere else as a part of the scene (referencing this.player since that’s what we’re passing to each function), right?

What about things that we’ll later check inside of another function? For example, if I declare this.cursors in the scene and log it in the console in my gameCreate.js file, it logs fine. But if I try to log it inside of a this.physics.add.overlap in my gameCreate.js then it’s undefined (presumably because of this having a different scope).

Other than reassigning it before checking it (something like var myCursors = this.cursors and then referencing myCursors inside of the function), is there another way to deal with that?

Phaser functions that take a callback argument also take a calling context argument. In overlap() or collider(), it’s the fifth argument, and you can pass this there to keep the scene context.

Or you can pass an arrow function expression as the callback.

1 Like

Ugh, I was looking right at it in the documentation too, I’m sorry I missed that! Thank you so much for your help, I’ve learned a lot!

1 Like