Jump to content

ES6 Compilers with modules help


LTNGames
 Share

Recommended Posts

I'm having a bit of an issue with compiling ES6 code to es5 with import and export syntax. I'm not even sure if it's possible but what I'm trying to do is convert a few of my RPG Maker MV plugins to ES6, I rewrote one plugin in full ES6 with the export keyword to export a few of my objects. Now, the point of this specific plugin is to have common functions all in this one file that I call a core file,  that I can later import it's functions and objects into my future plugins and any other ones I decide to rewrite into ES6. The thing is, I did some reading and been told in order for the compiled file to work on the web or in production is to bundle them up with, webpack, browserfy or whatever. The problem is that these files can't be bundled up as it's not an app, it's a series of plugins that the user can decide to install or not. So each of my plugins that I would like to import from this specific core file without bundling them, is this possible? I've tried babel and it only compiles my ES6 into commonJS, systemJs, amd, umd etc which is fine but I haven't a clue how to get them working. So my question is how do I compile to ES6 without bundling? I assume it's possible by including the module library with my core plugin but I'm still unsure and would like to know for sure, before I start reading a hundred different pages explaining how to setup modules with compiled ES6 and trying  different solutions etc. Hope someone can help and thanks in advance.

Link to comment
Share on other sites

There are a couple of pieces to this puzzle:

Transpile

Babel, buble and traceur are examples of transpilers (clang and emscripten also do this as a more aggressive example, together they can convert C/C++ into JS), their only job is to convert code from one state into another. E.g. 'let' instructions can be converted into 'var' instructions.

Bundle

Using modules is different from transpiling. Client-side JS does not (yet) understand modules (its a delivery problem as much as an understanding problem, but lets ignore that for now and just take it for granted that 'importing' modules is impossible) so you need to use a tool, like webpack, jspm, browserify, rollup etc, then takes your code, with its tree of dependencies and turns it into a single JS file that can be run in a browser, or, imported into other projects.

The bundle step can be safely ignored if your target platform understands modules, such as node (although depending on how you have written your source you may still need the transpile step).

Consuming Modules

This is the bit I think you might be mixing up.

CommonJS modules (the module spec is very similar to this), as used by node, work by exposes entry points in to a module, this is pretty standard module behaviour for any language. You then consume that module by using those entry points. If your target platform understands how to import modules then this isn't too much of an issue, unfortunately the browser does not (yet) understand this.

If your library code (your plugin) uses a module system then you'll have to bundle it altogether so that the browser doesn't have to try and understand your requires, defines, or imports. You then expose a single entry point (or multiple) to consume that module.

I have no idea how RPG Maker modules are supposed to be consumed but I'm going to make an assumption that they expect some sort of global to be defined? Outputting a library/plugin as a UMD module should do this for you, but there are issues with this approach as it bundles everything, the following should show this problem:

6 hours ago, LTNGames said:

The problem is that these files can't be bundled up as it's not an app, it's a series of plugins that the user can decide to install or not.

If you have multiple plugins then you'll have to bundle them all up separately, which means each plugin will contain your core code, if the consumer uses 3 plugins they'll get that code 3 times! Not good.

The way this is often handled is to output a UMD build (or, one for each plugin) that can be consumed directly if necessary but also to output transpiled but not-bundled code i.e. just run babel over your src directory and have it output to a dist or lib directory. If you are using npm as your distribution medium then there are conventions for consuming a module.

The bundling step can only happen once, in your application. If you're using npm then there are well-defined mechanisms for consuming modules and browserify etc all understand that and can work through an entire dependency tree and tries to include only one of each dependency (you could get multiple version numbers if dependencies specify hard version numbers for their dependencies, but lets just ignore that complication for now).

For example, lets assume you have created 3 libraries, each one depends on a single core library. For each of the 3 libraries we transpile them so they can be understood everywhere and publish them to npm (for example). In our application we `import` each of the 3 libraries, which in turn `import` core. We use browserify (for example) to turn all this into a single bundle. Browserify traces the dependency tree, it sees that `core` is specified three times and only needs to import it once, which is does, it then handles hooking them all up and you end up with a single JS file that contains your app code, the 3 plugin code and the single core library.

There is a slightly different way to approach this too. Your plugins are all specified inside one module, they all import a local core file from inside the module, this module exposes multiple entry points for each plugin. In your app code you import three plugins from the module and run browserify (again, for example) over it, however, this time browserify imports the entire module which might contain 7 plugins when you only use 3. However however, there are tricks to resolve this redundancy too, known as tree-shaking, which your bundler can handle for you (webpack & rollup makes this easy, browserify has a harder time with it) although you might find minifiers actually handle this with dead-code removal, the basis of it being that if your module exposes 7 entry points for each plugin it contains, lets say they are functions, but only 3 of those functions are ever called, the other 4 are candidates for removal (this can either happen at the function level, dead-code removal, or at the module level, tree-shaking).

Note that these examples are all examples of how module systems and bundlers have been implemented and they expect that all pieces can work together, I don't know if RPG Maker can do this or how its plugin system works, so none of this may be applicable for you and you might be forced to produce a bundle for each plugin and accept duplication of core code (or maybe, core becomes a plugin, and other plugins depend on that plugin being used? pretty sure this is how modded minecraft works, for example, its not a nice experience this way but it might be your only choice).

Link to comment
Share on other sites

I'm really glad you answered this question for me, you covered so many different aspects in such a great way. It seems to me that for now, it's best not to use a module system for these types of projects I'm doing, which I have no problem omitting from my plugins. The way I did it before ES6 conversion, I was just wrapping my core functions in an IIFE and exported only 1 main objects which contained the functions I wanted, a classic ES5 module pattern. I think my best solution without bundling my core plugin with all the other plugins that utilize it, is to do it the classic way, at least until there are other solutions or native module support, which may be a few years away lol.

A few things about RPG Maker,  it exports for desktop, browser, and android, the desktop version is wrapped in nwjs(node-WebKit), probably an outdated version lol. It handles plugins by loading each file in the projects plugin folder and appending them to the index.html file, it's not the smartest way but it works. Almost everything in RPG Maker is in global space, probably the worst idea ever but they don't seem to care that they pollute the shit of the global space.

Anyways, thanks a ton for your detailed reply, I definitely understand more about how modules, and bundling work and it's not quite the solution I was hoping for, at least not for my type of projects at the moment. At least now I know how to proceed with the conversion to ES6.

If I have any more question in general about bundling and or transpiling I'll be sure to come back and ask but for now I think I'm happy with what I have and the solution I believe will work just fine for my plugins.

Link to comment
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...
 Share

  • Recently Browsing   0 members

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