AlbertTJames

How I bundled a Library using webpack with Babylon as a dependency

Recommended Posts

Hi, 

 

Since the problem took me over a  week to figure out, here is my solution to bundle your project using web-pack keeping Babylon as a dependency.

NB: I am not certain what are the NECESSARY steps (ie what I could simplify) but those are SUFFICIENT steps.

 

My constraints were :

  1. The final bundle can be imported both in the browser and in node using any kind of import method : require(), import/export, or <script src=...> tags
  2. It has to protect against errors in node due to access to window or document that will be undefined
  3. BABYLON has to load has a global in the browser using the script tag (window.BABYLON)
  4. BABYLON needs to include Canvas2D
  5. BABYLON needs to remain external of the bundle so the custom library is light and in theory could load any version of BABYLON

 

Solution to protect loading in node.js:

  1. Build a custom bundle on Babylon website with Canvas2D ONLY, un-minified, and WITHOUT OIMO OR HANDJS. I did not test all possibilities but since the bundle is a concatenation suppose to be web compatible only, the exports will break in webpack or node in general. But using only this custom version will produce bugs in node due to access to undefined window.
  2. Then I had to bundle this custom build using webpack, you can see the configuration of webpack and the builder.js here : https://github.com/albertbuchard/experiment-babylon-js.git The important thing here is how the builder checks for window being defined and the webpack config exporting your named library with UMD.
  3. Publish this bundle to NPM (in the github look at the package.json it has three scripts to produce a unminified version, a minified version, and publish the repo on npm)

Those two steps will allow to load Babylon using any kind of import method, and do not produce errors in node (but returns an empty object, of course any call to BABYLON function will fail)

 

Solution to keep Babylon as a dependency in your custom library:

  1. In your library npm install the-custom-babylon-we-just-built
  2. Import BABYLON in your scripts any way you want using this custom repo ( es6 import syntax will work <3 ) i.e import BABYLON from 'the-custom-babylon-we-just-built'
  3. Then take a look at the webpack config and builder.js of this repo to understand how to manage EXTERNALS: https://github.com/albertbuchard/Experiment.js 

The key element here is how you write your external array:

externals: {
    ...
    lodash: {
      commonjs: 'lodash',
      commonjs2: 'lodash',
      amd: 'lodash',
      root: '_',
    },
    ...
    'experiment-babylon-js': {
      commonjs: 'experiment-babylon-js',
      commonjs2: 'experiment-babylon-js',
      amd: 'experiment-babylon-js',
      root: 'BABYLON',
    },
    ...
   'experiment-babylon-js/lib/babylon.custom.js': {
      commonjs: 'experiment-babylon-js/lib/babylon.custom.js',
      commonjs2: 'experiment-babylon-js/lib/babylon.custom.js',
      amd: 'experiment-babylon-js/lib/babylon.custom.js',
      root: 'BABYLON',
    },


  },

 

All but the root (Global environment reference) must be the NAME OF OUR MODULE as you would import it using require('NAME OF YOUR MODULE') so usually the name of your npm folder like the first two exaple, OR the direct path to the file you want to load like the third example.  It has to be the same as the import names you are using in your library. 

So if you import babylon like so : 

// in your library
const BABYLON = require('./path/to/babylon.js')


// in your webpack config
externals: {
  ...
  './path/to/babylon.js': {
    commonjs: './path/to/babylon.js',
    commonjs2: './path/to/babylon.js',
    amd: './path/to/babylon.js',
    root: 'BABYLON' 
  }
  ...
}

 

Hope it will help some of you ! :) @Nikos123

Share this post


Link to post
Share on other sites
44 minutes ago, Temechon said:

Yes ! That would be a perfect entry for the doc :) 

Do you want to do it @AlbertTJames ? Or do you want me to do it and credit you ? Thanks !

Mmmh it is still a bit messy no ? And it does not cover the most frequent use-case of bundling only for frontend.. (with hashed / entry specific bundling etc..)

I could do it but maybe when I will have a working solution for both use-case ?

I am working on all the possible use cases these days anyway, I can get back to you when i have explored the question fully 

**BUT** To be totally honest, this technique feels like a hack. The real solution would be to set up the typescript compiler to output an umd compatible module would greatly simplify the whole process. Also protect window / document access to make sure it will not bug in node / server side rendering frameworks. 

I am not very familiar with TS so I dont know how hard it would be, but for the modular future of javascript, it would really help. :)

Share this post


Link to post
Share on other sites

Thanks @AlbertTJames!

Its a bit more complex than I need atm!

One thing I am looking for is a nice little world-state-sync node server for my RTS game. I will be running animations server side and updating the client from the server. Does anyone know of any good node libs for this, and/or ideally a dockerised container that wraps the basics up?

Share this post


Link to post
Share on other sites

Nice work  @AlbertTJames!

I have never gotten an import of canvas2d to work - I noticed it was one of your constraints.  Using ES6 imports, I would expect this to work:
import BABYLON from 'babylonjs' // or import { Mesh } from 'babylonjs'
import 'babylonjs/2.5/babylon.2.5.canvas2d.max'

I would expect the Canvas2D to load with side effects and I have done this with other libraries like d3 (with and without side effects) to import around 10 modules with no issues (using webpack).  I cannot get Canvas2d to import :)  When my webpage loads I get "Uncaught BabylonJS is a required dependency, please include it first!" (I know how to fix that in a standard webpage with script tags). If I use the Babylon.js Generator (http://www.babylonjs.com/versionBuilder/) the generated file imports but has runtime errors.  I keep putting off getting canvas2d import working as I give up and when I try again still fail.. eventually I will need to invest some extra time here.

I am doing something completely wrong (which would not surprise me) or I think a change has to come from within the BabylonJS community to make modules easier to work with.  Perhaps something like what d3 did for v4 (https://github.com/d3/d3/blob/master/CHANGES.md).  They provide a nice list of benefits on their page for having modules/microlibraries written as ES6 modules.

Share this post


Link to post
Share on other sites
On 01/04/2017 at 11:10 AM, Nikos123 said:

Thanks @AlbertTJames!

Its a bit more complex than I need atm!

One thing I am looking for is a nice little world-state-sync node server for my RTS game. I will be running animations server side and updating the client from the server. Does anyone know of any good node libs for this, and/or ideally a dockerised container that wraps the basics up?

I think a good framework could be meteor, I have yet to try it with babylon but in theory with subscriptions and minimongo clientside you could achieve a relatively smooth interaction between server and client without too much code. 

If you do not want meteor, an approach using websockets would be best i think. 

Share this post


Link to post
Share on other sites
On 04/04/2017 at 7:25 AM, brianzinn said:

 I cannot get Canvas2d to import :)  When my webpage loads I get "Uncaught BabylonJS is a required dependency, please include it first!" (I know how to fix that in a standard webpage with script tags). If I use the Babylon.js Generator (http://www.babylonjs.com/versionBuilder/) the generated file imports but has runtime errors.  I keep putting off getting canvas2d import working as I give up and when I try again still fail.. eventually I will need to invest some extra time here.

The main problem is that the babylon builder concatenates several libraries and if you plan to use module.exports to require or import the libraries it will not work since there are several module.exports = .. (one for each file you add) 

One build that works for import is the way I describe: Build a custom bundle on Babylon website with Canvas2D ONLY, un-minified, and WITHOUT OIMO OR HANDJS.

BUT this bundle will not work in node since it accesses window objects without testing for environment. That's why I needed to bundle it using a custom webpack config, as well as manually check for window in the builder.js. To make it work clone my github repository, and use the babylon version you want. The bundle produced by this config will work in the browser script tags, in node, and using ES6/CommonJS or any UMD compatible framework (you can use require() or import .. from .. ).

 https://github.com/albertbuchard/experiment-babylon-js.git

 

 

Share this post


Link to post
Share on other sites

I did generate the canvas2D as you described.  The run time error was that the function getInnerPosToRef() was not defined.  I think the RectPackingMap is not inheriting properly from a class in the main babylon js file.  I appreciate your help, but I think I will wait for 3.0, since it sounds like the npm will include Canvas2D.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.