Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS Code Splitting / Reloading #5831

Closed
ncannasse opened this issue Nov 21, 2016 · 43 comments
Closed

JS Code Splitting / Reloading #5831

ncannasse opened this issue Nov 21, 2016 · 43 comments
Milestone

Comments

@ncannasse
Copy link
Member

@ncannasse ncannasse commented Nov 21, 2016

Reading https://github.com/elsassph/haxe-modular I noticed that we (compiler authors) should provide more support to help these workflows.

For instance the author @elsassph mention that enums do not support @:expose which is something we could add easily.

Maybe that's not a big problem, but compiling several times is not very funny although I think the compilation server does a great job in these cases :)

Another topic is "hot reload", we could easily allow generation of hot reloadable JS code by preventing it to create new classes prototypes and instead mutate the previously declared class prototype stored in $hx_scope.

Maybe @elsassph can bring his own opinion to the discussion

@fullofcaffeine

This comment has been minimized.

Copy link

@fullofcaffeine fullofcaffeine commented Nov 21, 2016

Oh yes, please! Also - and sorry for hijacking this thread, I can create another one if needed - a better API for customizing the output in a more granular way, as discussed here:

https://groups.google.com/forum/m/#!msg/haxelang/jSTkkaNgfB8/09m1PhqgAgAJ.

It'd be very useful if we could only customize some parts of the output for certain constructs, while still using the built-in js generator when customization is not needed. Would make it much easier to integrate with current ES6 frameworks like Ember 2.0, while still retaining the power of the current generator.

@Justinfront

This comment has been minimized.

Copy link
Contributor

@Justinfront Justinfront commented Nov 21, 2016

Nicolas,

Totally agree.

Did you see users are starting to use React/Redux component workflows
with Canvas and WebGL

Generally - https://github.com/evilfer/react-anything

For Babylon - https://github.com/brochington/Akkad

For Three - https://github.com/toxicFork/react-three-renderer

For Pixi - https://github.com/Izzimach/react-pixi

For Phasor - https://github.com/evilfer/react-phaser

As far as I know there are none like this for Heaps, Armory,
Away3d-OpenFL, Haxor, haxe Pixi etc... and with the js setups loading
models, textures the normal assets stuff is confusing with webpack, and
breaking in and out of the jsx structures with real 3d code is not well
explained. Sure it's not ideal for a full on game but for applications
having quite a bit 2D and then maybe a 3D view window in jsx, the
component workflow allows 3d to be mixed with a larger react structure
and the same Reflux reducing, you get high performance 3D webgl graphics
but a kind of 3d wpf xaml quick clean setup, which is not really my
taste but I can see maintainace could be simpler than say a starling
project, and certainly if there was some library cooperation Haxe could
take that small top end part of React ecosystem.

Webpack and a million other npm are currently used for packaging and
distribution both web and electron, and it's got so complex there are
github's devoted to core npm structures to help developers get a system
setup fast and simply. @elassph approaches seem to remove much of this
but you have to buy into Haxe which is always a hard sell because of the
"sheep" factor, if Haxe is more integrated then it will no doubt reduce
the npm dependancy confusion, like minimizers etc... being not something
you just google but a tool lets you choose even! An approach would be to
get Franco, Phillipe etc... to put together some Haxelib's for this, and
for community to sort the documentation to be really simple and good.
There are AIR developers and C# developers etc... who have to spend
days reading about what npm libraries to use, and I don't think it's
fun! So if you give them a better solution...

But mostly I see React and think it's not very lean, Riot looks simpler
but it does not scale? Vue another one, but surely Haxe could do better
but maybe allow React people to stay within comfort zone, standards are
not always about being the very best, they are more about popularity, so
Haxe does perhaps need to kind of similar which is what @elassph is
doing, but still it's just hiding some of the facebook bloat so the haxe
remains non standard without really making enough difference. So that
needs someone smart to fix.

I think it's not so much just getting the complier to help but mapping
out the whole js application creation and deploy end to end and seeing
how Haxe would fit nicely assuming that js users quite like
React/Redux/Webpack at the moment, so thinking about making it simple,
efficient and fast. Tooling is the key word.

Having been looking at this area recently I think Haxe could do really
well and has a lot to offer but @elsassph work is still quite away from
convincing the most adventurous React sheep.

Very interested in the complier changes for this, think it's more
important than many other changes suggested, curious about the non dom
JSX and if it's a direction Haxe web graphics libraries should be trying
to offer in a way that allows easy interchange.

Sorry ideas but no actual contribution.

Justin

On 21/11/2016 12:35, Nicolas Cannasse wrote:

Reading https://github.com/elsassph/haxe-modular I noticed that we
(compiler authors) should provide more support to help these workflows.

For instance the author @elsassph https://github.com/elsassph
mention that enums do not support |@:expose| which is something we
could add easily.

Maybe that's not a big problem, but compiling several times is not
very funny although I think the compilation server does a great job in
these cases :)

Another topic is "hot reload", we could easily allow generation of hot
reloadable JS code by preventing it to create new classes prototypes
and instead mutate the previously declared class prototype stored in
$hx_scope.

Maybe @elsassph https://github.com/elsassph can bring his own
opinion to the discussion


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
#5831, or mute the
thread
https://github.com/notifications/unsubscribe-auth/AAd385yzPMQXf9oeBuVlEft2S5rSHxI1ks5rAZAJgaJpZM4K4JcQ.

@back2dos

This comment has been minimized.

Copy link
Member

@back2dos back2dos commented Nov 21, 2016

Yeah, let's have it.

Another topic is "hot reload", we could easily allow generation of hot reloadable JS code by preventing it to create new classes prototypes and instead mutate the previously declared class prototype stored in $hx_scope.

Be warned that the resulting behavior has an important issue: We potentially create a lot function objects that keep alive old implementations, which makes this highly unpredictable. In particular $bind caches the implementation itself, rendering changes to the prototype ineffective. It's quite easy to change so that it retrieves the method at every turn, although I assume that can lead to performance degradation (a decent middleground might be not to actually use $bind but generate something like var self = this; function (arg1, ... argN) return self.method(arg1, ... argN)). So Iit might be better to make this an opt-in and if it is, then it could also be coupled to promoting local functions to (static) methods, not unlike many other backends (e.g. Java) do it. So that a reload can also affect existing function objects created as local functions. The alternative is to say live reload doesn't work on local functions, but that is quite an imposition on how people factor their code.

For React this tends to be a non-issue, because when code is reloaded, you just make a full rerender and everything that could still reference an old implementation gets discarded (unless your state itself contains function objects, but that is not common practice to the best of my knowledge). In any case, if we advertise support for hot reloading, we should communicate the limits very clearly. And I see value in pushing those limits so that code written against frameworks using more persistent object graphs (e.g. OpenFl, HaxeFlixel and what not) also gets the benefits.

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 21, 2016

Eh, I'm happy to have your attention ;)

I think the React/JSX discussion is a bit off-topic - though I'm not entirely happy with the JSX macro and I wish there would be actual ways to define DSLs. Non-DOM JSX can be done in Haxe without more compiler support than what is needed for DOM JSX.

For good code-splitting there would really be 2 options IMHO:

  1. follow modular-js approach

Basically be able to emit one JS file per class; maybe only the files that changed. The JS community is coming up with optimiser capable of recombining the modules in an efficient way. One complexity: how to express split points (eg. require.ensure()).

I honestly believe that's a very reasonable, and probably straightforward long term decision, but it may dilute the strengths of Haxe as a language VS others, and we'll have to continually play catch up (see the crazy frequency of releases of the other compile-to-JS langs).

  1. make code splitting a compiler feature

Instead of doing all the planning as I'm describing we could:

  • annotate with @:bundle('bundleName') entry point classes,
  • compiler would build the dependency graph and automatically exclude from main module the bundles dependencies,
  • classes shared between modules would be exposed; possibly in a better way than I do, but it's surprisingly effective although it doesn't work for toplevel classes,
  • we add a system to load a bundle and have a callback when it's loaded.

I think this model could even be used for other targets, like SWF (if we still care), C++/Cppia, HL, Lua, ....

Hot-reload approach would depend on the code splitting approach. Using 1., we can basically just rely on JS tools and we're done. Using 2. we could regenerate only the modules which changed, and possibly only the classes that need to updated (and their direct, non-shared, dependencies).

However, as @back2dos mentions, we can't update prototypes because of closures, unless you can really patch code at the VM level (I think Konrad is trying that in his Chrome-based game IDE). But it's ok if you can't reload everything, or you set a listener and recreate instances: using Redux you even just recreate your store and reuse the last state.

PS: I hope you like my NPM bundling idea. It doesn't really need complicated compiler support: I'm leaving the require calls but injecting a custom require function which gets modules from my NPM bundle.

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 21, 2016

Thinking again about NPM dependencies and code splitting:

  • If you're using Webpack, it would make sure that all the require calls will be resolved appropriately (we'd also have to use require.ensure for lazy loading and hot-reload) - but you don't save any complexity as you'll have to still do the work of creating additional Webpack configuration to create your vendor/libs bundle.

  • If you're not using Webpack (like this simpler LiveReload server approach), then we need the system I figured, where all the NPM dependencies are gathered (either manually or automatically by the compiler) into one (or several) JS where the require calls can be resolved, while the Haxe modules' require calls will pull from these NPM bundles (which is more or less what Webpack does under the hood).

Some of the other things Webpack does well:

  • processing/remapping/removal of modules (eg. Moment library comes with hundreds of Kbs of usually useless languages),
  • plugins like https://www.npmjs.com/package/webpack-bundle-analyzer can create amazing code size analysis; it's been really useful. I've worked on something (non-visual) like that for Haxe but it was a bit imprecise because it was based on parsing the JS output.
@benmerckx

This comment has been minimized.

Copy link
Contributor

@benmerckx benmerckx commented Nov 22, 2016

I wish there would be actual ways to define DSLs

@elsassph I think you should join the discussion here: HaxeFoundation/haxe-evolution#12

@Justinfront

This comment has been minimized.

Copy link
Contributor

@Justinfront Justinfront commented Nov 22, 2016

Webpack seems pretty confusing, I don't think that haxe should support webpack although that is a big risk, Haxe needs to offer cleaner solutions, getting involved with it would only cause headaches, I don't feel it will survive long term in the javascript community, coming as an outsider it looks fine as a copy and paste tech but trying to add a blender mesh and it's obvious that some perl developers were involved in it's creation, despite it's json facade. One pure front end developer spent several days getting some webpack working right, so the only fans are hardcore nodejs developers the rest only use it because they don't have anything better.

@fullofcaffeine

This comment has been minimized.

Copy link

@fullofcaffeine fullofcaffeine commented Nov 22, 2016

Opening a parenthesis here - shouldn't this be part of the Haxe Evolution process? cc @nadako

@nadako

This comment has been minimized.

Copy link
Member

@nadako nadako commented Nov 22, 2016

If there'll be concrete proposal, then sure, that's what haxe-evolution is for :)

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 22, 2016

We should certainly offer a simple out-of-the-box solution, but being
consumable by JS toolchains should be regarded as a good thing.

BTW Webpack is actually very powerful, but arcane for 90% of the JS devs.

On 22 Nov 2016 10:48, "Justinfront" notifications@github.com wrote:

Webpack seems pretty confusing, I don't think that haxe should support
webpack although that is a big risk, Haxe needs to offer cleaner solutions,
getting involved with it would only cause headaches, I don't feel it will
survive long term in the javascript community, coming as an outsider it
looks fine as a copy and paste tech but trying to add a blender mesh and
it's obvious that some perl developers were involved in it's creation,
despite it's json facade. One pure front end developer spent several days
getting some webpack working right, so the only fans are hardcore nodejs
developers the rest only use it because they don't have anything better.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#5831 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AASL646gE4RTGfu34ZWWjwfwuetR7HuQks5rAsiKgaJpZM4K4JcQ
.

@ncannasse

This comment has been minimized.

Copy link
Member Author

@ncannasse ncannasse commented Nov 22, 2016

@fullofcaffeine if this does not involve a syntax change or break it doesn't require to go through Haxe Evolution, if it's just an extra metadata for instance

@ncannasse

This comment has been minimized.

Copy link
Member Author

@ncannasse ncannasse commented Nov 22, 2016

Regarding the proposed solutions I'm not sure I have a strong opinion, given my lack of practice in the JS ecosystem (which I'm glad). Maybe allowing splitting one file per class and list the dependencies in requires should be good enough to allow different kind of post processing on it?

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 23, 2016

I would love the bundling options, especially as I think it ultimately has potential to be applied to other platforms and you don't need to fight with Webpack. For JS I'd suggest the implementation to be done without providing support classes for loading these bundles.

That said, emitting one JS per class is likely to be the quickest/easiest task for the compiler team - though if we go this way we should support both commonjs and and modules. It will take some time though to finetune the output to work with hot-reload and bundling; maybe the first task should be to take some Haxe output and manually split it into JS files and making it work with all we need.

Oh one issue with one JS per class: I think you can end up with circular references in Haxe, for instance in the static initialisation code. It wouldn't be possible with requires because class definition and static initialisation have to be in the same file.

@Justinfront

This comment has been minimized.

Copy link
Contributor

@Justinfront Justinfront commented Nov 23, 2016

Perhaps a test cases would be most useful. So for instance Haxe should go for high end, so more than mum and pup website, because low end it's probably not worth a js developer switching. So perhaps a clothing or toy store where you can see clothes in 3D interact to find out more but with also flex box and carousel or similar interactive interfaces, hooked up to a mysql database so end to end with backend in HashLink perhaps ( as long as node could be used easily instead ), no point in PHP and big companies don't take it seriously, then perhaps a microsite web game promo competition with email. Payment system for the clothes or toys. I presume you could setup something with Haxe merchandise. Nice to have allow you to add your name to T-Shirt in 3d and some graphics.
If you consider such a use case which is probably outside what most Haxe users currently use Haxe JS for but covers perhaps a larger user market, and the sort of thing a design agency might want to create.
So how would Haxe address this type of requirement, what payment system is supported, what email and webspace could they use, cloud servers?
We assume that front end users will expect 'React' familiar workflow, backend I am not sure.
But unless you think in terms of real life use cases your not going to get a tech that focuses on productivity, instead the tech could end up forfilling easiest use cases only, or just the limited use cases of some current Haxe users.
So before implementing changes to compiler it's probably worth think about a rich web application/site and what type of stuff would need to be bundled, the type of interaction, I fleshed out a fairly typical use case where Haxe might excel.
If Haxe actually created such a use case end to end or the important parts would that not be extremely attractive.
Can you decide what to support for stuff like React without any user cases to prove the workflow would be good, too many frameworks prove they can do a too list, but who can make money from creating a too do list and is that really anything like what a client may need?

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 23, 2016

I think I have enough large scale Haxe JS and TypeScript applications experience, with and without React, to validate the scalability of the solution.

My sample to-do apps are scalable in principle, but to be idiot-proof I should probably add React-router.

Beyond that it's architecture work - you don't make money out of a sample app, you have to have the architecture skills.

@Justinfront

This comment has been minimized.

Copy link
Contributor

@Justinfront Justinfront commented Nov 23, 2016

Electron option would be a nice addition to your example.

@wiggin77

This comment has been minimized.

Copy link

@wiggin77 wiggin77 commented Nov 23, 2016

Would splitting the modules up into files, only to have them merged later by another tool make it impossible to generate correct map files for JavaScript? We use them for debugging.

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 24, 2016

Good point @wiggin77 sourcemaps will be an issue. Right now common, beginner friendly, Webpack templates aren't going to easily "just work".

I've been trying to avoid it, but I think the right way to approach "one file per class" should be to comply with the "loader" pattern of the JS build tools:

Webpack (and other systems) need to be made aware if .hx files (just like they will manipulate .coffee or others). This means that Webpack will need to be able to say: "give me the JS version of this .hx file". And that's where you can return both the JS and the map for this particular file.

However we'd go down a rabbit hole: we need to be able to require things $extend, $bind, etc. Which means they have to be .hx (or JS) files that Webpack can resolve.

This mean having a npm module for the Haxe support files, and possibly the compiler itself. And a whole lot of complexity to add in the compiler server to support the loader protocol.

...

Should we talk again about the bundles splitting approach instead? :D

@Justinfront

This comment has been minimized.

Copy link
Contributor

@Justinfront Justinfront commented Nov 24, 2016

perhaps -dce could be amended

# no dce outputs Haxe javascript core all automaticly exposed as haxeStd.js
-dce no HaxeStd haxeStd fullExposure

#  exporting just a package or class
-dce full thx.* thx fullExposure

# _ would export the main class and all dependancies but only expose the main unless 
addtional @expose are used.
-dce full _ myLib
@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Nov 25, 2016

Update about sourcemaps @wiggin77: I can confirm that Haxe source maps can work with webpack, whether we use bundles or single classes, using source-maps-loader.

@binki

This comment has been minimized.

Copy link
Contributor

@binki binki commented Dec 22, 2016

To support modules (or is this issue only for codesplitting?), Haxe doesn’t need to do too much other than improve its JavaScript extern and @:expose support.

  1. If the standard library can be compiled (by users) to a module which can be consumed through extern headers, then multiple independent haxe modules using standard library classes can, e.g., use the same haxe.io.Input base class. I.e., haxe’s current behavior of inlining types from the standard library probably breaks instanceof. I think the suggested -dce changes are intended for this, but I’m not sure they’re quite the right approach. I think the feature needed here is a C-compiler-like -nostdlib. If eventually a standard way of packaging haxe modules targeting JavaScript is decided upon, having the haxe foundation maintain a haxe-stdlib package on the official npmjs repository would be helpful. It could offer deep requires on a module-by-module basis which haxe can properly automatically consume with a correctly-generated set of extern definitions annotated with @:native('require("haxe-std/haxe/io/File")') (a post-processor can hopefully hoist those require() calls). To use it, you would just ship an haxe-externs directory in your npm module, add it to -cp, and compile with -nostdlib to force use of the npm module. Some tooling to automatically add all node_modules/*/haxe-externs to -cp and build the haxe-externs folder before npm publish might be nice.

  2. Modules can only work well if the JavaScript target’s @:expose support is aligned with its extern support. I just discovered the enum issue which this issue was opened with. Currently, haxe won’t expose an enum marked @:expose and yet if I try to consume an extern enum it expects to find it provided by the environment and it bakes enum member values as compile-time constants instead of loading them from the environment at runtime. If tests could be added to ensure that if haxe is willing to consume an extern it has @:exposed, that would be great.

Finally, I’m not sure how on-topic I’ve been or if this is the right place, but I’ve myself been using yar3333’s codegen. With its help, I am able to compile haxe to distinct JavaScript modules which can interact with each other in a type-safe way with a few hiccups. I have started working on a couple test-cases verifying that the externs it generates can be properly consumed by haxe. This was meant to verify that codegen handles more obscure cases, but has ended up also testing if haxe is capable of consuming what it @:exposes. Perhaps tests like these could be added to haxe itself (minus codegen, haxe’s stdlib probably needs hand-crafted externs)? You can see my enum workaround, isn’t it beautiful? (I understand it is relying on internal implementation details it shouldn’t be and won’t write real code looking like that).

@Justinfront said

Webpack seems pretty confusing, I don't think that haxe should support webpack although that is a big risk, Haxe needs to offer cleaner solutions, getting involved with it would only cause headaches,

If you support generating and consuming npm modules at all, you’re already supporting webpack ;-). I personally consider consuming npm to be the primary feature of webpack.

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Dec 22, 2016

It's working! Automatic code (and sourcemaps) splitting into bundles: https://github.com/elsassph/haxe-modular

However, as the treatment is done post-generation, there can be issues with __init__ code, because I can't know what bundle it belongs to.

@fullofcaffeine

This comment has been minimized.

Copy link

@fullofcaffeine fullofcaffeine commented Dec 22, 2016

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Dec 22, 2016

@fullofcaffeine

This comment has been minimized.

Copy link

@fullofcaffeine fullofcaffeine commented Dec 22, 2016

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Dec 22, 2016

I really think that this bundling approach could be implemented at the compiler level, and made to work not only for JS but other platforms.

@fullofcaffeine you can read here about __init__: http://old.haxe.org/doc/advanced/magic - it has some edge case uses when you need to generate initialisation code that will run before your main().

@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Dec 23, 2016

Maybe allowing splitting one file per class and list the dependencies in requires should be good enough to allow different kind of post processing on it?

I agree with that.

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Dec 23, 2016

It's a bit more complicated than exporting one JS file per class: if you go this route you have to consider the question of sourcemaps and integration with bundlers and watchers.

The ideal way to approach it is to implement a "loader" API for .hx files for systems like Webpack. Such loader will be able to return both the JS (with require pointing on other .hx files), and sourcemaps. But this won't easily fit with the way the Haxe compiler works.

If we want to emit JS (+map) for each class there we would need:

  • update code gen to be valid with common Webpack setups (like create-react-app); otherwise it causes interoperability problems with JS processors and linters: we can't just say "disable babel/your linter",
  • avoid overwriting files that did not change.
@Simn Simn added this to the 4.0 milestone Jan 9, 2017
@Simn Simn added this to the 4.0 milestone Jan 9, 2017
@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Jan 16, 2017

avoid overwriting files that did not change.

This is not super high priority. A decent packager/bundler would be able to detect any changes, even the file is "modified without changes"

@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Jan 16, 2017

Btw, I need this feature badly. Is there any suggestions for a quick workaround? (like macros?)
Emitting classes as individual js files would suffice for me.

@back2dos

This comment has been minimized.

Copy link
Member

@back2dos back2dos commented Jan 16, 2017

I suppose you could always use a custom js generator.

@fullofcaffeine

This comment has been minimized.

Copy link

@fullofcaffeine fullofcaffeine commented Jan 16, 2017

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Jan 17, 2017

Look at modular-js project. Haxe JS custom generator gives you most of the code, it just can't be made to output sourcemaps.

@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Jan 17, 2017

I have some initial success in modifying modular-js to support commonJS-style require() which works on nodejs. But the problem is that the macro stops working on 3.4 #5944

@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Jan 18, 2017

So I have modified modular-js to output ES6 modules, and seems to work fine in my react-native project.

https://github.com/kevinresol/modular-js

Here are some notes for what I encountered, which may be useful if someone is going to move the implementation into the compiler:

Do not assign value directly to module.exports

(i.e. module.exports = AnyValue). Otherwise circular references will not work. Instead, add fields to the module.exports object (e.g. module.exports.default = SomeValue) Actually, this is just what the ES6 syntax export default does.

Circular reference & static vars

It seems impossible to access static var of another class while initializing static vars, if they are circularly referenced. Example:

class Foo {
  public static var foo = Bar.bar;
}

class Bar {
  public static var bar = 1;
  public static var foo = Foo; // needed so that circular reference is established between Foo and Bar
}

This is because in case of circular referencing, the required module is incomplete and the static vars are not assigned yet. So in this case Foo.foo will be undefined.

To solve it, we may need to generate some "higher level" code to manage these references.

@back2dos

This comment has been minimized.

Copy link
Member

@back2dos back2dos commented Jan 18, 2017

If you're outputting ES6 modules anyway, a possible workaround would be to generate the static vars as properties that compute the initial value lazily. This presumes of course that their initialization doesn't cause side effects other code might be relying on.

@kevinresol

This comment has been minimized.

Copy link
Contributor

@kevinresol kevinresol commented Aug 29, 2017

My latest experiment:

  • uses require() (no ES6 import)
  • no need modify existing haxe code
  • works out of the box!

https://github.com/kevinresol/hxgenjs

@Simn

This comment has been minimized.

Copy link
Member

@Simn Simn commented Sep 17, 2017

I had a lot of discussions with several people about this topic. To summarize my current thoughts:

  • I agree that we need something like this.
  • I think that we should just go for a straightforward .hx -> .js approach. It should be easy to bundle some .js files together as a separate step.
  • I'm worried about static inits.

It's not clear to me who's responsible for correct static init order. I'm not even talking about the circular case where it's outright impossible, but just the straightforward situation of a static init in Foo depending on a static init in Bar. If you load everything at run-time, how would it be ensured that Bar's static inits are handled before Foo's?

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Sep 17, 2017

Circular static values isn't impossible to handle and I believe it was solved by @kevinresol for hxgenjs - unfortunately the workaround is very inefficient so it should be optimised to be used only to break cycles.

Evaluation of JS code happens in order of the require calls.

Some static inits don't (didn't?) work though in hxgenjs, like the fallbacks (typed arrays).

@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Sep 17, 2017

The big problem with static init is the way Haxe JS currently generate them; flat in the output, in the scope where other declarations exist.

It should be accepted as a breaking change: with splitted JS the static init code will run within the module scope, and people will have to use different patterns.

@Simn Simn modified the milestones: Release 4.0, Design Apr 17, 2018
@Simn Simn mentioned this issue Sep 5, 2018
Closed
@jgranick

This comment has been minimized.

Copy link

@jgranick jgranick commented Sep 6, 2018

The most naive way to implement static initialization is in each module JS file, so when you require for the first time, it initializes. However, as has already been discussed, this could result in a static initialization order that's different than expected, which is thorny. Currently I control this in some projects by forcing that code to go through only one static initialization method.

One possibility (if the naive approach is wrong, or maybe if a circular case is detected) would be to use something akin to how Webpack handles the requires. It requires based on a numeric index, which provides a means to exert more control. Here's a psuedo-code example:

// file A
StaticInit.init (0);

// file B
StaticInit.init (1);

// StaticInit

function init (index:Int):Void {
    // if necessary, force initialization of pre-requisite static inits here
    switch (index) {
        // run init code by index
    }
}
@elsassph

This comment has been minimized.

Copy link
Contributor

@elsassph elsassph commented Sep 7, 2018

Solution in hxgenjs has been (last time I checked) to make all the requires basically deferred until use by using wrapper functions. Maybe circular dependencies could be resolved by introducing this pattern at the right places.

@ncannasse

This comment has been minimized.

Copy link
Member Author

@ncannasse ncannasse commented Dec 13, 2019

I think a lot of solution already exists for this now. Let's open specific improvements requests in case things could be further improved in that area.

@ncannasse ncannasse closed this Dec 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.