phaserjs / phaser

Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
https://phaser.io
MIT License
36.95k stars 7.08k forks source link

require('phaser') with Browserify throws error: Error: Cannot find module './Scalar' #1186

Closed totty90 closed 9 years ago

totty90 commented 10 years ago

I've also got these errors:

galarant commented 8 years ago

tried this recently with Phaser 2.4.4 and browserify still shits itself on PIXI. If I have time over the holiday season I hope to address this and send a PR as an Xmas present to the Phaser community =)

D34THWINGS commented 8 years ago

Is anyone here can make a TL;DR on how to make it work with browserify. I read from the beginning but everything seems to be hacky. I saw instructions in the README for Webpack but doesn't help much for browserify. I already have a pretty huge stack built with browserify so i don't want to change my build system for the moment. The error i'm getting is:

phaser.js:23083 Uncaught ReferenceError: PIXI is not defined

If someone explain it right, I'll make a PR to add to the README so that no-one will have to ask on this post anymore

konsumer commented 8 years ago

It's looking for pixi to be defined globally. The proper way to fix this is to define the requirement, at the top of any file that references PIXI:

var PIXI = require('pixi.js');

The quick hack way is to monkey-patch it into the window, before you require phaser:

window.PIXI = require('pixi.js');

You will probably still need to monkey-patch all the phaser stuff into the global Phaser object. You can see an example, here where I actually track all the external & internal dependencies on a per-file basis.

D34THWINGS commented 8 years ago

I wish i made it to work with browserify-shiw but i just can't seem to find anything that works at all. I'll stick with the monkey-patch for now as i don't want to lost time with Phaser's wrong UMD definitions. I really love this framework but I find it so sad that the foundation of the framework, the dependency resolution is done so wrong. It could be easier for everyone to build their custom version of Phaser if every module was declared in UMD with proper resolution of dependencies. The best exemple I have for that is lodash. You just require the files you want in your build and that's it, no need for cloning and custom grunt task, it works with CommonJS/AMD/Window like a charm. I really want this to be in the v4.

photonstorm commented 8 years ago

There isn't a single module in Phaser, and never has been. It would require re-coding the entire thing from scratch, every single class, every single file. This is not something to be undertaken lightly, and I'm dubious of the merit of doing it at all, seeing as that's how Lazer is being built.

galarant commented 8 years ago

@D34THWINGS I've gone back and forth on this for a long time and have dug into many threads on the topic. In short, @photonstorm has given the best answer available. As I understand it, the Phaser team has made so many modifications to their own custom fork of PIXI that it's essentially a different package at this point, and there is no browserify magick that will make the npm version of those two packages work together.

You can still use Phaser as an npm package, but just do it like this:

  1. Install Phaser as an npm package: npm install --save phaser
  2. from your project root, create a /static/vendor folder and add a symlink to your node_module: phaser -> ../../node_modules/phaser
  3. In your index.html just inject Phaser into the global scope by pointing to the symlink:
  <body style="margin: 0; padding: 0;">
    <!-- Have to include Phaser via script tag due to an incompatibility with Browserify -->
    <script type="text/javascript" src="/static/vendor/phaser/dist/phaser.min.js" defer></script>

    <script type="text/javascript" src="static/dist/bundle.js" defer></script>
  </body>

Then you can just refer to the Phaser object anywhere in your application, and the browser will recognize it since it's part of the global scope. But since it's still just a package, you can avoid adding the source to your repo etc.

Granted this approach is not aesthetically perfect, but speaking from experience it's a much better use of your time to simply punt on this issue for now and focus on building your game.

D34THWINGS commented 8 years ago

@galarant i'd better stick with the window hack for now because if i include it in my index.html, i will have to do a custom task to copy Phaser somewhere in my build from the node_modules then modify the name file for cache busting purpose if phaser is updated and also replace the relative path to the file to an absolute path to my Akamai CDN like I do with every single assets i have, and that's kind of work i can't afford for now. As you said, i need to focus on making the game, thanks for the advices !

Thanks @photonstorm for your work and sorry for bringing back old issues from the dead. I did a lot of development in Node and built huge frontend webapps but never seen libraries without proper UMD, that's why it surprised me, but I understand that it's not top priority. The JavaScript scene has a huge churn and tools come and go really fast, that's truly annoying.

konsumer commented 8 years ago

@photonstorm I did manage to do the modular thing in my fork with (which is 1486 commits behind photonstorm:master,) and it does work. I traced the concat-order you are using in your build system, turned those into requires, and defined PIXI & Phasor wherever it was needed (at the top of many files.) A similar idea could be applied to this repo, but I couldn't figure out what version to apply the changes to, and it sounded like it would duplicate other efforts you have going on.

konsumer commented 8 years ago

You can test it out by downloading it, running npm install and npm run full-min which will build phaser.js & phaser.min.js

pbj-time commented 8 years ago

hah looks like @konsumer actually achieved the task I wanted to do four months ago but gave up on. Awesome work!!

konsumer commented 8 years ago

Thanks! It's outdated, but fairly easy to redo. Basically put these at the top of every file:

var PIXI = require('pixi.js'); // npm install --save pixi.js
var Phasor = require('../Phasor.js'); // whatever the location is relative to the file you are in

and then make a commonjs entry-point like mine. I based that on the current build stuff to figure out the right order. You can make multiple entry points for all the different versions of built files you want, but also, you can just include the files directly in your browserify/webpack project.

konsumer commented 8 years ago

It relies on the trick that commonjs keeps a singleton reference to the object in module.exports, so anywhere that you include Phasor.js, you are getting the same object (so you can monkey-patch new stuff into it)

hayesmaker commented 8 years ago

just add a script tag to ur html to add Phaser. It saves you having to recompile 100,000lines of phaser code each time you browserify. And it works.

On Tuesday, 12 April 2016, Benjamin Delamarre notifications@github.com wrote:

Is anyone here can make a TL;DR on how to make it work with browserify. I read from the beginning but everything seems to be hacky. I saw instructions in the README for Webpack but doesn't help much for browserify. I already have a pretty huge stack built with browserify so i don't want to change my build system for the moment. The error i'm getting is:

phaser.js:23083 Uncaught ReferenceError: PIXI is not defined

If someone explain it right, I'll make a PR to add to the README so that no-one will have to ask on this post anymore

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/photonstorm/phaser/issues/1186#issuecomment-209094292

D34THWINGS commented 8 years ago

@hayesmaker I don't recompile Phaser each time since I marked it as external in my build. I have a second build for my vendors that I run only once at the start of my dev task and it works like a charm. That's how i do my dev build :

return browserify(options)
    .transform('babelify')
    .external(vendors);

And for my vendors build :

return browserify()
    .require(vendors);

@konsumer when I was reading the thread i saw your fork and it was a great job but as you said it's outdated. And @photonstorm said that you shouldn't use the pixi.js repo since Phaser has a very custom version of PIXI, so the require of PIXI should also be relative. I think that the best way to achieve this is to fix the UMD. I'll try to make a POC this weekend on a fork. I think it could be more trivial than we think.

Here's an example, thats how Phaser uses UMD at the moment:

(function (root) {
    var Phaser = {};
    // ... Phaser code goes here

    if (typeof exports !== 'undefined') {
        if (typeof module !== 'undefined' && module.exports) {
            exports = module.exports = Phaser;
        }
        exports.Phaser = Phaser;
    } else if (typeof define !== 'undefined' && define.amd) {
        define('Phaser', (function() { return root.Phaser = Phaser; })() );
    } else {
        root.Phaser = Phaser;
    }

    return Phaser;
}).call(this);

But the proper way to it is:

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['./pixi'], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('./pixi'));
  } else {
    root.Foo = factory(root.PIXI);
  }
}(this, function(PIXI) {
  var Phaser = {};
  // ... Phaser code goes here
  return Phaser;
}));

Using the factory pattern is way more efficient to handle dependencies for everything. And you don't have to do this on your own, there's some grunt and gulp plugins that can do that. You juste have to tell for each file what it depends on and everything will be wrapped up in the end so no pollution nor conflicts on the global scope can happen.

D34THWINGS commented 8 years ago

Also the UMD shouldn't wrap the whole code but each file so that each file can resolve dependencies on it's own. You will not have to change anything in the custom building feature since you'll have to concat all files in the right order because UMD wrapping doesn't solve the problem of defining order. The only thing that will change is the intro/outro that will no longer be required.