mithril.js icon indicating copy to clipboard operation
mithril.js copied to clipboard

ES Module support

Open Qrokqt opened this issue 7 years ago • 18 comments

ES Modules have landed under flags in all browsers, so it would be great if we could get a build of mithril that supports it.

Being able to import { m, request, route, promise } from './mithril.js' would be great.

Qrokqt avatar Jun 28 '17 17:06 Qrokqt

It would be possible if we altered the bundle to optionally emit an ES module and export it instead. Do note that it would most likely default-export the m factory with all its attachments, so you wouldn't see much stripped from Rollup if you were to try to use it.

dead-claudia avatar Jun 29 '17 08:06 dead-claudia

I think I brought up this issue inside the chat room couple of months ago. I was advised to use syntax like this

import m from "mithril/hyperscript";
import render from "mithril/render";

gyandeeps avatar Jun 30 '17 20:06 gyandeeps

I would personally just advise in the meantime using Rollup's rollup-plugin-commonjs, if you're using that. It's low-priority for us currently, but it's something easily fixed. PRs would be welcome, if you would like.

dead-claudia avatar Jun 30 '17 23:06 dead-claudia

If we're gonna do this it should go all the way. I haven't tried converting everything to ES Modules + rollup recently, but the last time I tried bundler beat it by a few bytes. Probably worth trying again as rollup has continued improving in the meantime (albeit slowly)

tivac avatar Jul 13 '17 03:07 tivac

Added to the 2.0 milestone, dunno that it'll actually make it in that timeframe but it's good to aspire to something.

tivac avatar Jul 17 '17 21:07 tivac

@tivac The current bundler still has the advantage that the module polyfill works in every supported browser, out of the box. We'd have to deprecate the tests/index.html files and find an alternative... The interest of these files is limited since the DOM API is mocked in the tests, even in browsers, but it allows one to check that the JS at least runs, even if it doesn't exercises the real DOM.

pygy avatar Jul 17 '17 22:07 pygy

Long term I think we should focus on integration-testing via the public APIs instead of the more tightly-scoped tests we have now. They're sometimes harder to write up-front but we end up with better guarantees of API-correctness. That shift would mean all tests could use the bundle for testing instead of needing to support piecemeal usage.

Investigating ES Modules is solely in the "experimental" phase right now, I added the milestone o try and ensure that I experiment w/ it again before too much longer.

tivac avatar Jul 17 '17 22:07 tivac

Module Unminified Unminified + Gzip Minified Minified + Gzip
CommonJS (Bundler) 45.27KB 11.35KB 21.73KB 8.03KB
ES Modules (Rollup) 46.17KB 11.50KB 21.85KB 8.08KB

bundler beats rollup by 0.05KB, or 50 bytes for the "Minified + Gzip" test in a naive port.

A more complete port of mithril's internals to ES Modules would probably yield smaller overall app bundles when factoring in tree-shaking. It'd require a lot of refactoring & removing of the way current APIs work though.

While I appreciate the way the framework has been broken up into discrete chunks, I do wonder if some of the files that enable piecemeal usage could be dropped entirely. This is anecdata at it's finest, but has anyone ever heard of someone actually using anything other than the default m export? I can't think of an example that I've seen.

tivac avatar Jul 19 '17 05:07 tivac

Aren't there at least a few people on gitter (names escape me) that are using mainly the m.render / hyperscript API in their projects because they want full control of rendering? IIRC that's at least what @foxdonut does with meiois, apart from the routing implementation, and there are probably others. I'm sure there's a spectrum of how usable parts of the codebase is piecemeal, where at least streams, requests (not that I think anyone does this), maybe querystring could be used separately somewhere...

orbitbot avatar Jul 19 '17 07:07 orbitbot

@tivac Just out of curiosity, what's the Rollup bundle look like?

Regarding improving the port:

  • I don't think 50 bytes would be a big deal, especially if we can recover it. We've had bug fixes that have added more than that. For comparison, an empty gzip file is 28 bytes and an empty UMD Rollup bundle is 230 bytes raw, 164 gzipped, 154 minified, and 130 bytes min+gzip, so if you're using --format=umd, there's your extra 50 bytes, since Rollup generates AMD support.
  • There's a few people who use api/ stuff and lower-level hooks (like mithril-node-render IIRC), but if we exposed them somehow*, perhaps in a separate bundle, that could help their use cases while giving us more freedom to change internals and keep the primary bundle smaller.

* Of course, on a "you're on your own" basis, where it may change even across patch versions.

dead-claudia avatar Jul 19 '17 13:07 dead-claudia

I agree with @orbitbot above. We also use just hyperscript and render from Mithril. Also I think we should avoid including promise by default as most of the environments already have promise in it either natively or through babel-polyfills.

gyandeeps avatar Jul 19 '17 13:07 gyandeeps

@gyandeeps the Promise polyfill is there to have Mithril work out of the box in IE9-11. IE 11 is still relevant, and not everyone uses Babel or polyfills. Being able to get started with Mithril without other deps is IMO an important feature

pygy avatar Jul 19 '17 14:07 pygy

Which I dont disagree with. But today, people who use libraries like react and mithril in production tend to use polyfill libraries. That when we have repeated code. Thats why I suggested that their should be a way to ignore it. Most of the libraries today avoid carrying polyfills with them because then you are having duplicates.

gyandeeps avatar Jul 19 '17 15:07 gyandeeps

I would like to exclude the full polyfill from the bundle, and instead have a small shim layer that can either return a reference to global.Promise or throw a helpful error like Environment is missing Promises, please see https://mithril.js.org/promises.html.

It increases friction a tiny bit for IE users, but it'd be part of a major version bump and then means that every other environment would be running less code. That'd improve both our download and parsing time, improving overall startup.

tivac avatar Jul 19 '17 15:07 tivac

I'd love to use mithril with rollup to only include the code and functions I actually use.

In particular, I often don't use routing, the request code or the polyfill. Consider hybrid apps or other apps that only support a small set of browser engines.

creationix avatar Aug 17 '17 20:08 creationix

So our new plan is to revert our initial design (#2366) and instead expose the ES module source under mithril/esm, with each transpiled file duplicated with .js and .mjs extensions since tools depend on both. To ensure the files are only valid as modules, I'll append an export {} to each file so they can never be successfully parsed as scripts, to help encourage people to have their bundlers set up correctly.

Mirroring everything via .js and .mjs variants in the same directory structure sounded good in theory, but tooling and runtimes deviate from one another too much in this area for that to work out.

dead-claudia avatar Feb 14 '19 03:02 dead-claudia

Here's a +1 so you guys are encouraged to treat this issue as more of a priority...

nandoflorestan avatar Aug 22 '19 17:08 nandoflorestan

Here's the status: we're waiting for someone to file a PR for something like this. There's two reasons why this is low-priority currently:

  • Having a v2 out the door that wasn't breaking everyone was higher priority than having ESM support. So that took most of the time until the last couple weeks, and I'm still working on ensuring a few common community modules are updated for v2 ASAP, most notably mithril-node-resolve.
  • Most bundlers either offer support for CommonJS modules natively or they have a commonly used plugin (or set of plugins, as is the case for Rollup with rollup-plugin-commonjs + rollup-plugin-node-resolve) for it, and we do offer a UMD bundle for global usage if you don't want to bundle.

Once I resolve the first, then I'll look into this.

dead-claudia avatar Aug 24 '19 07:08 dead-claudia