Luxon: Making Luxon smaller

Created on 22 Nov 2017  路  20Comments  路  Source: moment/luxon

The Chrome debugger tells me that moment.min.js was 50.2 KB and that luxon.min.js is 90.2 KB. Is there anything we can do to make Luxon smaller for client-side usage?

I'm not primarily a JS developer, but it looks like Luxon is implemented using ES6/ES2015 modules? And so users might be able to use tree shaking to pull in only the parts of Luxon that they need? This could be helpful to document is so

date-fns is written in a function-per-file style, which makes it much easier to pull in just what you need and to end up with a much smaller binary. It also makes it easier to use with bundlers like rollup. Is there any chance that Luxon might consider a more functional style like date-fns?

needs thought

Most helpful comment

I want it to be smaller. A few thoughts:

  • The ES6 minified build is only 58K. So if you're into tree shaking you can start there.
  • Or start with the source and just do the compilation in your own toolchain. You should be able to get it a lot smaller because you can be way more aggressive with the obfuscation than I can with a public API.
  • Luxon is definitely not a modular design, so you'd have to tree shake at the method level. I'm eager to see what people would be able to do there.
  • The proper comparison with Moment would be with moment w/locales + moment-zones. Unfortunately the way Luxon is built would make it hard to separate those out.
  • I'm working on making the other builds smaller by removing some polyfills and cleaning up a few things. We'll see how small I can get it.
  • I'm considering moving Interval to its own separate project which would shave off a bunch of KB.

I'm going to leave this open so other people will see it.

All 20 comments

I want it to be smaller. A few thoughts:

  • The ES6 minified build is only 58K. So if you're into tree shaking you can start there.
  • Or start with the source and just do the compilation in your own toolchain. You should be able to get it a lot smaller because you can be way more aggressive with the obfuscation than I can with a public API.
  • Luxon is definitely not a modular design, so you'd have to tree shake at the method level. I'm eager to see what people would be able to do there.
  • The proper comparison with Moment would be with moment w/locales + moment-zones. Unfortunately the way Luxon is built would make it hard to separate those out.
  • I'm working on making the other builds smaller by removing some polyfills and cleaning up a few things. We'll see how small I can get it.
  • I'm considering moving Interval to its own separate project which would shave off a bunch of KB.

I'm going to leave this open so other people will see it.

There might be some low-hanging fruit here by improving the build.

  1. rollup-stream is using an older version of rollup - 0.49.3, released in September... since that time there's been a few improvements to it's tree shaking. i.e., right now asyncGenerator polyfill is being included in the bundle for some reason - it appears to be unused. Not the hugest improvement to get rid of it, (and tbh unsure if latest rollup would turf it properly)... that was just from a cursory glance at the bundle - there may be others in there.

  2. using loose mode in preset-env... there's a lot of for of loops which transpiles to be quite large.... with loose, it's a bit smaller. loose may not produce the same results across the build though, so a thorough testing would likely be required. I was able to shave 3kb off the minified bundles wit this syntax transpile making this change.

thanks @tswaters - I'll give those a shot

I switched to Babel loose (now in the git head but not released) and it did shave off a couple K. I haven't tackled the rollup-stream piece; if it someone wants to update that library for me and try it in Luxon, that would be a nice easy starter project.

I'm removing Gulp (see #151) and once I've done that I should have more flexibility in using the latest and greatest rollup.

An update:

```
./global-es6/luxon.min.js 56 KB
./es6/luxon.min.js 60 KB
./amd/luxon.min.js 68 KB
./global/luxon.min.js 68 KB
./cjs-browser/luxon.min.js 76 KB
./amd-filled/luxon.min.js 88 KB
./global-filled/luxon.min.js 88 KB
````

I still think we could do a lot better. For example, it's super weird that the global-es6 build is smaller than the non-global one? And why is the cjs-browser build like 8K bigger than the global one?

super weird that the global-es6 build is smaller than the non-global one

If you do a diff on the unminified variants it's really not that different, just inclusion of the iife and setting values on exports for the global one, and a simple export for the non-global one.

$ diff build/global-es6/luxon.js build/es6/luxon.js
1,3d0
< var luxon = (function (exports) {
< 'use strict';
<
5665,5674c5662
< exports.DateTime = DateTime;
< exports.Duration = Duration;
< exports.Interval = Interval;
< exports.Info = Info;
< exports.Zone = Zone;
< exports.Settings = Settings;
<
< return exports;
<
< }({}));
---
> export { DateTime, Duration, Interval, Info, Zone, Settings };

Looks like that's the minifier doing it's thing.... or, not doing it's thing as it were. babel-plugin-minify-mangle-names by default doesn't alter top-level names -- the non-global puts everything on toplevel so the minifier won't touch it. Add the following option to rollupMinify args should fix this:

        mangle: {
          topLevel: true
        }

before: 60924 build/es6/luxon.min.js
after: 53861 build/es6/luxon.min.js

why is the cjs-browser build like 8K bigger than the global one

Same problem applies to cjs-browser. The above change to minify opts fixes cjs-browser to be quite a bit smaller....

before: 75570 build/cjs-browser/luxon.min.js
after: 68004 build/cjs-browser/luxon.min.js

That helped a bunch:

./es6/luxon.min.js                      53K
./global-es6/luxon.min.js               53K
./amd/luxon.min.js                      67K
./cjs-browser/luxon.min.js              67K
./global/luxon.min.js                   67K
./node/luxon.min.js                     67K
./global-filled/luxon.min.js            88K
./amd-filled/luxon.min.js               88K

Thanks for all your work on this. It's wonderful to see the progress being made

I agree that splitting out Interval would be a great!

I also wonder if we need the formatting presets to be part of DateTime?

@benmccann thinking through this a bit more, I think this is the path forward for that stuff:

  1. Interval should stay in the main build, but we should check that it can be tree shaken out successfully with Rollup or Webpack. I think this should work fine, but I haven't tried it (by comparison, you couldn't use Interval and tree shake DateTime out because Interval depends on DateTime).
  2. I would also like to move the presets out to their own class and let them be tree-shaken too. That's a substantial breaking change, though. I think I'll release a 1.0RC1 in a few weeks, and we can slot that in.

Another possible ideas - maybe we could have a DateTimeParser and separate out the RegexParser and TokenParser stuff from the core DateTime class as well

That plausible for the token parser & formatter, but I suspect it would be a poor tradeoffs for the regex stuff

Howdy! We're looking into using Luxon, but the size has a nibbling a little as we could in theory reach the same with a stripped down moment js (+ importing locales).

Is there still energy towards driving this forward? Would love to help how I can!

Day.js seems to achieve a much smaller size then luxon with the same goals (immutable api familiar to moment js users), and looking into it they do it by breaking 'nice to haves' into plugins. Maybe Luxon could do that somehow? Push code heavy-but-not-core features into their own treeshakable modules/files?

@RichiCoder1 wow, I didn't know about dayjs but it totally worths investigating how they did achieve such a small footprint.

https://www.npmtrends.com/date-fns-vs-dayjs

(interesting: Day.js has a bit more stars but much less downloads)

It's a relatively young package from my understanding. Lots of ecosystem inertia to fight :)

@antoinerousseau

Moment.js created at 2012 / star count 40287
Luxton created at 2016 / star count 7794
Date-fns created at 2015 / star count 16563
Day.js created at 2018 / star count 18850

This ticket has devolved into people discussing other libraries. Going to close this.

See #498

Was this page helpful?
0 / 5 - 0 ratings

Related issues

farnoy picture farnoy  路  3Comments

icambron picture icambron  路  5Comments

icambron picture icambron  路  5Comments

jonathanborges picture jonathanborges  路  6Comments

pmcilreavy picture pmcilreavy  路  6Comments