Jump to content

Require.js best practices?


dr.au
 Share

Recommended Posts

require.js was a stab at AMD (asynchronous module definition), however, since then AMD has lost the module war to commonJS, at some point (hopefully this year although the subject is complicated) we will have 'native' JS modules for the browser and they are a variant of commonJS. require.js does support commonJS style but its a massive hack, best to stay well clear.

Packagers such as browserify, webpack or jspm are all excellent. They require a little bit of learning, but there is a lot of good information out there and once set up they are very easy to use (far easier than require).

With Phaser though its easiest to include the Phaser files outside of your package manager i.e. include the Phaser script in the head which shoves Phaser into a global variable and then leave your package manager to manage and bundle your application logic. This is kind-of against the module philosophy. I'm hoping someone can point out a setup for Phaser and browserify, I found some info from Rich on Github but couldnt get it to work (I think it will be different for Lazer anyway), but including as a global works perfectly.

Link to comment
Share on other sites

Hi @mattstyles — Webpack + hot module replacement with Phaser would make for super fast development in the browser. I'd love to see a setup for that.

Still learning JS structure for projects. I started with basic game states

game.state.add('Boot', BasicGame.Boot);
game.state.add('Preloader', BasicGame.Preloader);
game.state.add('MainMenu', BasicGame.MainMenu);
game.state.add('Game', BasicGame.Game);
game.state.add('GameOver', BasicGame.GameOver);
game.state.start('Boot'); // start it up

And I try to break out my files into logical 'components'

<script src="lib/phaser2.4.4.js"></script>
<script src="js/Boot.js"></script>
<script src="js/Game.js"></script>
<script src="js/moon.js"></script>

And that's fine when i'm in the Game.js file and referencing this.

BasicGame.Game.prototype = {
  create: function () {
    this.input.maxPointers = 2; // for mobile
    this.input.addPointer();

    drawMoon();
  }
}

But then I run into issues in other files like moon.js referencing the global game. vs this.

// # Moon.js
function drawMoon() {
  game.moon = game.add.sprite(500, 200, bmd);
  game.moon.deathTween = game.add.tween(game.moon).to({
    alpha: 0,
    y: 0
  }, 500, Phaser.Easing.Cubic.Out);
}

 

Link to comment
Share on other sites

If you want to use `this` inside your `drawMoon` function then you just have to tack it on to the prototype of the state you want to use it with, or you could bind it to that scope during the constructor i.e.

function drawMoon() {
  ...
}

BasicGame.Game = function() {
  this.drawMoon = drawMoon.bind( this )
  ...
}

The binding way would allow you to re-use your function elsewhere, but, really, why do you even want to scope it?

The only problem with your `drawMoon` function is that it is not referentially transparent, as in, it references 3 variables from outside of the function, so, when you call it, you have no idea what it will do without also having knowledge of those other objects. If you changed that function to look like:

function drawMoon( game, sprite ) {
  var moon = game.add.sprite( 500, 200, sprite )
  moon.deathTween = game.add.tween( moon ).to({
    alpha: 0,
    y: 0
  }, 500, Phaser.Easing.Cubic.Out )

  return moon
}

In this example I've accepted that Phaser is a global and I've also accepted mutating the game object (this destroys pure functions as it has side effects). The idea of a library function like this is that it takes an input and it returns an output, in this case, it also has side-effects as it calls `game.add` (in practise, as you've already mutated `game` you might as well go ahead and do the `game.moon = ...` bit in there too, although you could restructure to get around this entirely).

This may seem a little alien to you but there are several very important reasons that make pure (referentially transparent) functions a good thing:

* A function with no side-effects is relatively safe to change, you know what is going in and you have complete control over what comes out and thus, what happens next. This means you only need knowledge of the function and it is detached from the larger system it will become a part of. It wont muck with the system and the system wont muck with it, this is such a powerful technique that it means your reliance on testing the whole app diminishes greatly i.e. you test just this function knowing that it does not affect the system (or be affected by it) in unforeseen ways.

* It is easy to write tests for

* It is predictable, given the same inputs you will always have the same output (result/behaviour/action)

* Later down the line optimisations can be made more easily as behaviour is predictable and repeatable

* As the functionality is detached from the greater system you can reuse this code as-is in other projects

* As the functionality is a result of inputs the documentation needed for other people to use it, and the cognitive load associated with usage, is greatly reduced

* It is simpler, a defined set of inputs and outputs, and simple is good as it enables most of the points above (you have enough to worry about as a developer without trying to work out why calling a function way over in one part of your codebase is affected a function in another at a different time)

 

This way paves the way towards functional programming, and whilst you may prefer to use OOP (it makes more sense in some situations) you can still take some of this philosophy to gain the advantages listed above.

TL:DR

Dont get hung up on `this` and creating classes and objects for everything, a function that takes an input, produces an output and does one thing well is a thing of beauty that should be strived for with every coding stroke on your keyboard.

 

 

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...