Cannot read property 'Engine' of undefined

60 views
Skip to first unread message

Yury Sidorenko

unread,
Dec 25, 2016, 4:19:20 PM12/25/16
to excaliburjs
Hello, guys!

I am trying to get started with the Excalibur game engine.
I'm writing my project in TypeScript, using Webpack to pack to keep my development environment clean.

I've added "export default ex;" to "excalibur.d.ts" file and then I'm trying to import it from my GameService.ts file. As you can see from the screen below, WebStorm recognized import and everything should be fine.

Based on what I see inside my "bundle.js" Webpack also managed to pull "excalibur.js" in.


But when open my "index.html" page (which includes "bundle.js") I get an error regarding this statement:

let game = new ex.Engine({
width: 800,
height: 600
});


Do you know what is wrong ? Why do I get an undefined reference ?

Yury Sidorenko

unread,
Dec 25, 2016, 4:24:34 PM12/25/16
to excaliburjs
By the way, I you need to take a look at the source code, I put it here.

Erik Onarheim

unread,
Dec 28, 2016, 2:32:03 PM12/28/16
to excaliburjs
Hi Yury,

Sorry for the delayed reply! It's been busy with the holidays around here.

If I had to take a guess, the actual JS for Excalibur is not being loaded at runtime for your Angular app, even though WebStorm seems to like the types and the import from the d.ts file.

Do you see the Excalibur "Engine.prototype" in your bundle.js? If it is not being emitted that would explain why we are seeing "Engine is not a property of undefined", because ex would not be loaded.

I'll take a look at your source and see if I can spot anything.

Erik Onarheim

unread,
Dec 28, 2016, 3:22:13 PM12/28/16
to excaliburjs
Hi Yury,

I think I've found the issue, and have a workaround for you. (I have an example here in this thread https://groups.google.com/d/msg/excaliburjs/bTE3ACbo30Q/WZ3p-92HAAAJ

If you change your import in GameService.ts to:


And instead of "export default ex" you add "export = ex":




It works! :)



Here is what I think is happening, there is a subtle difference between "export default ex" and "export = ex", extensive discussion here https://github.com/Microsoft/TypeScript/issues/2242#issuecomment-83694181 

Because of this difference, all of the Excalibur types were not hanging off of ex.* but instead ex.default.* when webpack is run, which would definitely be undefined given the way that excalibur.js is setup (module.exports = ex at the bottom).

Here is an example of what I'm talking about if I switch back to "export default ex" and view it in the chrome debugger.




Hope this clears things up for now! We are working on making our module story better in regards to ES6 style syntax this next release which should drop then end of January https://github.com/excaliburjs/Excalibur/issues/606 

Would you say it is more expected to use the form "import ex from 'excalibur';" over "import * as ex from 'excalibur';"? If so I think we should definitely take that into consideration when we close #606

I'm going to add this discussion to our documentation so it is more discoverable (https://github.com/excaliburjs/Excalibur/issues/733). There has definitely been an uptake in angular/webpack apps using Excalibur, and this is valuable info for anyone trying to do that.

Let me know if you run into any more issues, we would love to see what you're building and help answer any questions about Excalibur :)

Cheers,
Erik

Erik Onarheim

unread,
Jan 1, 2017, 9:33:42 PM1/1/17
to excaliburjs
Hi Yury,

We've updated our docs with some clear working examples, note this will only work with the latest alpha available via "npm install excalibur@next"


Cheers,
Erik

Yury Sidorenko

unread,
Jan 2, 2017, 6:27:56 AM1/2/17
to excaliburjs
Hi, yeah, it works now with "excalibur@next" and "import * as ex from 'excalibur';", thanks ;)

Comparing the two:
 "import ex from 'excalibur';" vs "import * as ex from 'excalibur';"
I would say that the second one (the one you chose in the end is better).
Although, the way I think is the best is to do something like "import { Engine } from "excalibur";" - thus you don't have to prefix your entities with "ex.".

I have one more question (may be a bit off the topic) - why do you use triple slash syntax to import typescript dependencies (in some places in your code), e.g. here ?

Kamran Ayub

unread,
Jan 5, 2017, 4:30:09 PM1/5/17
to excaliburjs
Hey Yury,

I've found with using webpack, you can actually use the second syntax like you suggested, so that might be an option. You can play with the webpack example here: https://github.com/excaliburjs/example-ts-webpack

Regarding your second question, we've actually since updated our codebase to use module syntax as of January. The reason we started out with triple-slash references is because Excalibur is over three years old! And at that time, we only had TS 0.9 which didn't support modules as well as it does now. After TS 1.8 is when the module story started getting better, in that you could output a single file using AMD/SystemJS and generate a single declaration file. Before then, you would have had to bundle it yourself and concatenate the declaration files using a 3rd party tool (which at the time, I don't even think existed). You can browse the codebase at that time (0.1.1) if you want to see what we had back then.

Triple-slash references are definitely the easiest way to create a TS project since introducing modules definitely incurs build tool overhead (bundling, concatenation, loaders, etc.). Remember also that Excalibur is only meant to be used in a browser and introducing module loaders is conceptual overhead that many new or junior developers aren't comfortable with. The philosophy of Excalibur has always been to keep it simple so even someone brand new to JS or TS can write a game. In typical browser projects, we never used module loaders until recently (think jQuery). Only now are people starting to get much more comfortable with module loaders, so now was a good time to convert the codebase over. We still kept the same backwards compatibility by including the Almond.js AMD loader as well as exporting to the "ex" namespace the entire public API. This means we can support both non-module and module loading environments.

Hopefully that provides some context. Thanks for asking!

Yury Sidorenko

unread,
Jan 9, 2017, 6:10:58 PM1/9/17
to excaliburjs
Thanks for detailed answer !
Reply all
Reply to author
Forward
0 new messages