Hacker News new | past | comments | ask | show | jobs | submit login
You may not need Moment.js (github.com/you-dont-need)
149 points by thunderbong on Sept 18, 2021 | hide | past | favorite | 128 comments



JS has been moving forward with a new Date/Time API called Temporal[1].

I haven't had a chance to use it myself, but a friend dropped Moment.js for it (I think to keep the browser from adjusting the date to the local time).

New APIs (and hence, Temporal) are the type of things that if you don't know about, you can easily miss and go straight to a library for.

[1]: https://2ality.com/2021/06/temporal-api.html


I tried to use Temporal just this past week, and I have to be honest… the spec and documentation are painful. I spent three full days with it and still don’t understand why it’s designed the way it is.

Other recent additions to stdlib have followed a fairly consistent pattern: design low level but with existing use cases and solutions in mind, explain the design in terms of migration path for library authors or in terms of usage comparisons to those libraries.

Temporal just has… a bunch of data types with very little in the way of explanation of what they are. And some of them are quite similar but have slightly different semantics and APIs to achieve the same thing.

It’s not entirely clear why most of the data types exist in the first place. Like, I don’t want a TimeZone class, and I don’t want multiple kinds of Instants. I want a Date, a Duration, and clear semantics about how they interact with each other and with time zones.

Anyway I ended up putting the work I was doing on hold because it became such a time sink, but when I come back to it I fully expect to look at my WIP stashes, and run screaming toward date-fns or whatever.

I mean no disrespect to the standards authors/contributors (in case any are reading), I’m sure standardizing anything to do with dates/times is even more challenging than anything else you deal with. I just… wonder if the low level design approach may have forced an unnecessary design in this case, and wish there was a somewhat more pragmatic approach for something end users and library authors alike routinely get wrong in subtle but important ways.


> I want a Date, a Duration, and clear semantics about how they interact with each other and with time zones.

I think at this stage the only libraries I've seen to manage this clearly are the ones that cleanly seperate the concept of "LocalDate[Time]" from "ZonedDateTime" (which is different to OffsetDateTime, which is only useful when backwards looking because offsets are subject to change in future, and so you should probably just use a Zoned variant). While people might appreciate the simplicity of a single DateTime class, it just leads to unclear handling in application code of where the conversions happening and confusion as to what's actually going on with time zones.


This could be addressed at least for the most common cases by making the API more explicit: if you want a non-zoned DateTime, you have to say so and accept its caveats. Otherwise you’re getting a (local by default) zoned DateTime and its TZ can be manipulated to accomplish other date/time math in a predictable way.

The mix of zoned/not is a valid use case but almost certainly a specialized one that shouldn’t be the core API.


> The mix of zoned/not is a valid use case but almost certainly a specialized one that shouldn’t be the core API.

I'm curious, where is this ever a valid use case? The idea of an unzoned DateTime doesn't make sense to me. I guess if you're building software that lives in orbit or on other planets?


My personal use case that I explain in the “just use UTC isn’t good enough” case: I take meds 2-3 times a day that are short acting and time sensitive. I need them at ~9am and ~1pm to function. Local time, wherever I am.

For the unzoned case I need my reminders to notify me at the same local time wherever I travel. For the mixed case I need to be able to apply local changes where the unzoned solution isn’t available.

These are ADHD meds, I have severe executive dysfunction and I depend on reminders for this. Traveling from Seattle to DC, this is literally the difference of whether I can function at all before lunchtime. Traveling further I might as well not go at all.


One use case is storing future events, as floating DateTime + location. This makes it possible to handle timezone rule changes, unlike storing a zoned DateTime on its own.

Another is when you treat the timezone and datetime separately. Imagine an internal app for conference room bookings with a form that lets you input a DateTime + office building (which some Ruby or whatever backend then uses to compute the localized time). The JS DateTime input library would deal with a non-localized DateTime only.


I want to wake up at 8:00 regardless of my timezone. I don’t want to wake up at “8:00 NYC” when I’m in Europe nor should I need to adjust the alarm every time I change timezone.


That’s a good case for an unzoned time data type - storing a time without an associated date or timezone. There are some scheduling use cases where such a type is useful - such as your alarm clock example, or suppose a chain of retail stores has standard opening hours of 9am-5pm regardless of the time zone the store is in.

But a combined datetime (both date and time) in an unspecified non-UTC timezone is far less useful. As I mentioned in another comment, there are some rare use cases where it is genuinely appropriate, but far more often if you give people such a type they’ll use it to store data in a single specific time zone, without being explicit about what that time zone is-which is a bad practice.


From a data modelling perspective, it's nice to have them. When your input/output data has unzoned datetimes, you need to model them somehow, and it's better to have a competent implementation than something hand-rolled. I agree that you should avoid them in greenfield designs, but I don't think that's sufficient reason to exclude them from libraries.


Here is a rare, if potentially real use case: a university has campuses in multiple countries, maybe they have one in Europe, one in the Middle East and one in Asia. Some of their units are taught across all three campuses and have common exams. They try to hold the exam at as close as practicable to the same time, but they aren’t going to make students take it in the middle of the night - especially when students at another campus get to sit it during the daytime, that would be unfair. So they’ve scheduled it for 9am local time on 30 May 2022 - across all their operating time zones.

That said, these kind of scenarios are rare. A non-UTC datetime in an unspecified timezone is much more likely to be in some particular yet unspecified timezone, or even to be an incoherent mix of data from different time zones, than to be the one of these rare cases where having a constant local date and time across multiple time zones is actually useful.

Arguably, library designers should not attempt to cater for these rare use cases. Doing so is adding complexity which is far more often going to be a cause of harm (people using an unzoned datetime type when they shouldn’t) than a benefit


Somebody could probably build a tiny, more ergonomic library on top of the Temporal foundation. The original Date implementation made the mistake of trying to be too high-level as a language primitive, and we can see where that got us. I can definitely understand the authors not wanting to make the same mistake again; I think it's well and good for the platform primitives to favor being comprehensive and unopinionated over being ergonomic or easy to use.


> Somebody could probably build a tiny, more ergonomic library on top of the Temporal foundation

That’s my point. Most recent standards try to optimize for this. I would be surprised if you could based on my experience with the APIs. Maybe I’m not well enough versed to see how it would be written. But its design feels much more likely to be something where the native types are passed around or substituted. They’re not designed to interoperate with each other as far as I can tell.


It's awful, just like Date.

We have to keep using moment.js due to Highcharts, timezones and locales. It's quite easy to use if you're careful about mutating objects and the API is not brain damaged. We still use jQuery as well, it's a breath of fresh air compared to native Js APIs, except maybe fetch.

Go ahead and downvote, I couldn't care less. We can't keep changing our platform every time a new and hip way of doing things pops up.


Spending more time on time... Sad but somewhat hilarious.


Oh wow, someone finally took it serious. Everyone: visit the link if you didn’t yet. Abstract dates, durations, easy dmy math, mostly everyday developer-friendly. Dates are one of these computer topics that seem familiar (just like numbers in a floating point form) but are hard to operate on. And if the language’s core date/time library is poor man’s one, it’s better to not have it at all.


This looks great, covering about what I'd want from a modern date/time library, but threre seems to be a huge ommision: Is there seriously no way to format/parse dates and times based on arbitrary format specifications? C has functions for that! Why is JS so resistant to this crucial functionality?


Formatting (without "arbitrary format specifications") has been available for years:

- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

- https://caniuse.com/mdn-javascript_builtins_intl_datetimefor...

Parsing, however, is an entirely different topic. I assume the Temporal proposal authors learned from the Date.parse fiasco. To this day, there are browser inconsistiencies that make it largely unusable for anything else than the full-length ISO date format. Hence, it might be better to use a userland library that works consistently regardless of the browser (version). There are also some notes about parsing in https://tc39.es/proposal-temporal/docs/parse-draft.html:

> Temporal's approach to most operations—including parsing—is to encourage strong typing, e.g. Temporal.Instant.from vs. Temporal.PlainDateTime.from. A type-spanning "parse anything" API goes against that strongly-typed model.


Yes, it's always been possible to get some kind of string from datetimes, but I specifically care about specifying what string, same with parsing. "Just use a locale's default" might work if you're making a web app for clients who aren't picky, but using JS as a "serious" language it's a really big hole. There's plenty of formats that demand non-ISO date formats and I currently need to use a third-party library. I've gotten used to than in JS, but I was hoping a new take on dates will sort this out. Oh well, I'll have to just hope it makes it to v2: https://github.com/js-temporal/proposal-temporal-v2.


All good points. I completely agree.

Does using a JS backend like Node or whatever help ease this pain?

I've yet to dabble in that realm much, but I've always hated working with dates in JS and C# because of how each language handles dates differently. It's not the most annoying thing by any means, but it does slow me down on the occasion.


Temporal isn't fully stabilized yet. There's a polyfill, but it may still get breaking changes down the line. We're waiting on the polyfill to stabilize before switching.


How do they compare to Luxon?


they might get built-in https://caniuse.com/temporal? (https://tc39.es/proposal-temporal/docs/) (https://github.com/tc39/proposal-temporal)

> NOTE: Although this proposal's API is not expected to change, implementers of this proposal MUST NOT ship unflagged Temporal implementations until IETF standardizes timezone/calendar string serialization formats. See #1450 for updates.

it's basically already accepted. Stage 3 means it's basically ready for a preview implementation and stage 4 means passed for "official" ecmascript inclusion


Considering moment.js says[0] you should actively consider alternatives instead of it, I can't disagree. But I do like the breakdown of what to use when instead!

[0] https://momentjs.com/docs/#/-project-status/


In fact, Moment’s post links to the OP here.


the breakdown is not complete, for example I needed to pull in a new library to get the localized first day of the week with Luxon (this differs based on locale)

Also I really don't recommend dayJS, its documentation is crap (for example this is the documentation of its timezone plugin: https://day.js.org/docs/en/plugin/timezone ) and is full of serious bugs that its developer does not respond to: https://github.com/iamkun/dayjs/issues

Also the code style is really concerning too: https://github.com/iamkun/dayjs/issues/1598


I worked on an app that was centered around scheduling a recurring future event in, if you needed to, an arbitrary (not necessarily the user's) timezone, about a little over a year ago and we had to ditch Dayjs due to timezone bugs. Luxon was our choice and it did the job.


There's nothing wrong with mutable objects, in fact I've always preferred them. I hope making everything immutable is a fad that passes.


I'm pretty comfortable declaring that creating a mutable-by-default date, string, or number library is a mistake. I'm not on the make-all-the-things-immutable train but making dates mutable is a painful mistake that Java painfully worked through with JSR-310, the new date and time library.

Part of the problem is that moment would both mutate the underlying object and return the object.

    const a = moment()
    const b = a.add(1, 'second')
Both b and a are now the same object. I've lost a few hours to the design choice.


It’s just a matter of RTFM I guess, the a.add() method returns “a” so that you can chain methods on the same object without creating a new object on every method call.

Else: a.add(1, ‘second’).add(1, ‘day’).subtract(2, ‘minute’) would create 3 more objects that are not needed. Creating a new moment object is expensive, it happened to me to work with a lib that grew exponentially slow when using above N dates because they where constantly recreating moments instead of using them wisely so creating a new one on every operation would be quite bad.

That’s why the method .clone() exists, so you can declare that explicitly:

    const a = moment()
    const b = a.clone().add(1, ‘second’)
PS: don’t take RTFM as an offense, I just happen to like it a lot and we use it frequently at work, I don’t mean to be disrespectful towards you :)


I think the problem there is more one of library design than specifically a mutable object problem.

If `a` is mutated by the `.add()` method, then it should probably return void rather than returning a copy of the object.

Is the immutable DX still better in this specific example? Probably. But the above at least would help developers avoid the major footgun with mutability.


Spent several hours debugging that one a couple of years ago


I think the Dev Tools in Chrome might have changed since (I don't use Chrome anymore), but we had issues maybe 5 years ago when hovering over momentjs watch statements in the debugger kept on mutating the underlying data. That was fun.


I like to say that mutable state is to software as moving parts are to hardware (https://kristiandupont.medium.com/mutable-state-is-to-softwa...).

It's not always the best (or even an) option, but it does spare you some concerns.


Mutability introduces an entire class of bugs and is slower to execute. If don't mutate something, it's almost always frictionless and better to make it immutable.

There is tooling around immutability and a whole host of compiler optimizations. The resultant code is far less error prone.

Do you feel the same way about static typing?


Immutability may enable compiler optimizations, but it also requires copying things around or applying clever tricks so performance isn't too bad.

There are times for immutability, and times for mutability. You have to be careful for different things.


No. Proper theology demands that you must go with the latest react trend and discard everything else until they change their mind again and generate a ton of blog posts teaching you what was rejected a couple of years ago.


It’s not so straightforward as “it’s slower to execute”. Often excessive copying of immutable objects instead of mutating them means code is slower, especially in JavaScript.


It's interesting to me that programming language designers basically always get date/time libraries wrong, and it takes multiple tries to get it right. Just look at the atrociousness of the original java.util.Date and Calendar APIs, and then there was joda-time, and finally that was rolled into the core java.time package. JS is similar, the core JS Date object has many of the same problems as java.util.Date, and so we now have multiple attempts at getting a sane date/time library.

Curious, are there other languages where people feel this date/time mess does not exist?


Rust - because it doesn't have date and time in the standard library!

I believe the standard library developers knew date/time was cursed, so punted on it. There is a minimal set of types and functions to allow the bare minimum of system calls etc:

https://doc.rust-lang.org/std/time/index.html

But you have to bring in one of a few crates to do anything else.


At least with this way, you don't have to hang on to bad ideas and specs for eternity. A bad crate can easily be swapped out for a better one and future developers won't have to remember which is the good date functions.


chrono is the defacto standard. As with all good modern datetime libs (see also Noda Time, the new java.time), it takes liberal inspiration from Joda Time, which IMO has pretty much set the template for a robust datetime library.


Yep! Most examples in the Rust cookbook[0] use chrono[1].

But note that before Chrono there were other time libraries; one of them was called time[2] - and IIRC it was created from code removed from Rust's stdlib std::time[3]. It eventually proved to be the best decision: designing a good API is a hard effort, and any design was prone to have mistakes and warts.

Chrono provides interoperability with both std::time and the time crate. It acknowledges other datetime crates that it was inspired, like datetime-rs[3] which itself was inspired by Joda time.

[0] https://rust-lang-nursery.github.io/rust-cookbook/datetime.h...

[1] https://crates.io/crates/chrono

[2] https://crates.io/crates/time

[3] https://github.com/depp/datetime-rs


There's an actual joda implementation as well. See https://www.npmjs.com/package/@js-joda/core


Golang went with the bizarre decision of using a specific timestamp as a template for date format strings. So in Go, instead of having to remember impossible things like "%Y stands for year" and "%H is a two-digit hour", I simply need to recall that the canonical time is Monday, January 2nd 2006 at 15:04:05.


To be honest for me it is much easier to memorise %Y and friends then this special date. I feel like this canonical date is easier to write documentation for but harder to use.


I was pretty sure tdeck was being sarcastic, but I might be wrong.


Completely agree. It's one of those ideas that seems clever but is a huge pain to use.


In JavaScript you actually use `Intl.DateTimeFormat`[1] to format datetimes, which takes in a pretty descriptive configuration object with keys such as `month: "short"`, `hour: "2-digit"`, and `hour12: true`.

This is missing in the OP explainer, so I created a PR[2].

1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

2: https://github.com/you-dont-need/You-Dont-Need-Momentjs/pull...


And it fills a completely different usecase to arbitrary date formats. For one, there's no parsing. And you have to make do with what the browser provides with no guarantee of stability.


OK, I'm not a Go programmer so was struggling to figure out what was going on, until reading that the "canonical" date for formatting is essentially:

01/02 03:04:05PM '06 -0700

I actually think that's a really good idea. Sure, it may easier to remember "YYYY-MM-DD" than "2006-01-02" at first, but I think it helps a lot in many other cases, e.g. you don't need to remember what is exactly meant by MM and MMM and MMMM, you could just create your format string as "January 2, 2006" or "Jan 2, 2006".


Never realized that, I guess because nobody writes timestamps in "month, day, time, year, zone offset" order.


It’s almost impossible not to get it wrong. Most developers don’t even understand the full scope of the problem (and it’s probably impossible to!).

Even devs with good defensive programming instincts make entirely wrong assumptions because the problem is so vast and complicated. For instance I remember repeatedly explaining to a previous team that we couldn’t treat all of Michigan’s locality outside of its 4 Central Time counties as America/New_York because America/Detroit is governed differently. This was hard to communicate even as I dug up the relatively recent history of TZ changed in MI.

Their eyes collectively glazed over as I tried to explain the complexity of DST in Arizona—the state doesn’t observe DST, most of the reservations do, but some don’t.

I have no idea how library authors are supposed to deal with this. Language authors are more likely to be able to defer to expertise, but even then it’s obviously not going to produce great results. And by and large library authors will depend on the quirks and bugs of the host language.

I agree this is a particular sore spot across the field. I think it’s something that would especially benefit from a cross-environment design.

As in: start with the existing ISO standards, which are good. Determine an appropriate level of abstraction that suits low level platforms, and coordinate higher level abstractions as warranted. I anticipate the XKCD comic, but this is a case where the problem is generally equal-bad for everyone involved and it wouldn’t hurt to try.


haha having had to deal with developer glazeover from DST implications before I suspect we’re not alone. One may accept the inevitable failures that are implicit with the naive date time representation and possibly get a MVP going, but it’s not really more expensive/time consuming to kick the can down the road and hide the inevitable failures behind an interface. The latter requires you to be explicit about the functionality you expect from a date/time value. This means you need a[0] a way to distinguish the type of value it is by the ways you expect to use it...

In data modeling I hide such things behind a foreign key to create a distinct domain. E.g. “PersonBirthDate”, “StartedAt”, “ValidAfter”, “AvailabilityInterval", “FiscalQuarter”, and “ExpiresBy” are all different representations, possibly also distinct by the source entity, and all treated as a distinct domain. Further I’ll often add UDTs and database functions/procedures to help assure integrity (and possibly quality, not always possible of course). Sum Types are unpleasant to model in RDBMS and descendants of such.

[0] a pun, HHOS. <https://en.wikipedia.org/wiki/Yoneda_lemma>


I think the Elixir DateTime API is really clean and well designed. The key was letting libraries explore the problem and surface the right interface, before baking it into the standard library. It does mean it took a long time for this to land but I'd say it was worth it. Learning from the failures of others also certainly helped.


.NET has always had a simple to work with date time API. At least compared to other languages it feels a lot cleaner.


.NET had DataTime which took user's local time zone into account by default. So .NET introduced DateTimeOffset where you can specify time zone.

but by then, DateTime was used in a lot of places, for eg: and .NET Sql Server driver mapped datatime against DateTime (instead of DataTimeOffset)

yeah, .NET has these issues too. and I have not even gone into DateTime Culture!


Rust's Chrono lib is outstanding. Clean API, and works how you expect. This is the only lang I've used that has a good 'default' DT lib. It can compile with `no_std`, ie embedded targets.

Whoever can wrap this in WASM and expose a JS API will be a hero.


JS’s Date is broken because it was based on Java’s broken Date iirc


I implemented a date time library for JS a few years ago and took heavy inspiration from java.time. My conclusion is that the time zones are the hardest part of the whole thing. Time zones are defined by political entities that doesn’t give two cents about implementing them. Also there is a huge variance in their details so just because you understand time zones in X country, don’t assume that knowledge is universal. Some of my favorites are timezone changes at midnight, so 1159>1am, meaning some days lack a midnight. Also some Muslim countries switch back to normal time for Ramadan, which means up to 4 changes in a single year.

Also anyone trying to sell “Midnight GMT” as a date only format is in for a world of trouble down the line.


Plus the historical changes in timezones and dates. Not only are they bonkers, but they're bonkers in different ways depending on the year.


If you get a chance read through the IANA Timezone date base files. It has all sorts of interesting tidbits related to this.


I'm genuinely interested in learning more about the problems that midnight-GMT-as-date-only can lead to. It's used on a project I currently work on. Do you have a link or can you spare a few minutes to explain?


Generally you end up with some “apply offset” code that tries to convert between an date time and a date by applying the timezone offset. This generally works but is full of edge cases. For example on days with DLS changes the offset is not the same throughout the day, so you need extra logic to figure out what is the correct offset. Also most code is usually only tested in the dev’s timezone. So you can write code that works in a negative offset but has bugs in positive offsets or vice versa.

Another issue is the mental burden of knowing when a time stamp is supposed to be a date or a date time. You cannot write a reliable method to differentiate them because there will be valid date times that are exactly at GMT midnight.

Fundamentally dates and date times (instants) are different. Christmas is December 25th in Australia and the USA. But the instants that those time zones experience that date are different. People forget this and will try to treat the GMT midnight as a date time, when it should be a date.


How come the js-joda library is never mentioned in discussions about javascript date/time libraries? its API is perfect and it has been around forever. but instead the community seems to keep inventing more and more new datetime libraries. i don't understand why js-joda seems to be ignored

https://js-joda.github.io/js-joda/


For me it’s the size. From their own site js joda states it’s “small” at 43 kB minified and compressed

I’ve routinely worked with date-fns and found it is usually 20KB or less


date-fns does not support time zones, so it's not really comparable.

(Although it looks like `js-joda` doesn't contain the time zone database, for that you also need `@js-joda/timezone`, and the IANA TZ DB as generated by `moment-timezone`. Oh boy!)


Past related threads:

You Don't Need MomentJS - https://news.ycombinator.com/item?id=20508166 - July 2019 (23 comments)

You Don't Need Moment.js - https://news.ycombinator.com/item?id=17990859 - Sept 2018 (85 comments)


At my workplace, we have a node.js service that solves Vehicle Routing Problems, which are very computationally intensive. When we profiled it, it was spending ~30% of its time on moment.js - mostly constructing lots of moment objects just to do simple things like get UTC-now. We replaced it with native node APIs and got an ~30% speedup.

So yeah, +1 on "be careful about using moment.js in performance sensitive/critical code".


For a couple of years now, date-fns(https://date-fns.org/) has been the de-facto go to library for managing Dates in Javascript.


How is it any better or worse than Luxon? (I only ask because Moment recommends Luxon as is "spiritual successor", so I never bothered to evaluate date-fns. Should I?)


You definitely should. date-fns is similar to the lodash/ramda, in the sense that it's a bag of functions which handle dates. This makes it very easy to compose different date handling situations.


No good if you need to convert between time zones, IME.


What's the state of cached ES module imports?

The ultimate goal is, your <script>s are modules, and import their dependencies from a common CDN like unpkg. The browser will cache the import, so that large common imports are rarely actually fetched. Dependencies would have their own cached dependencies as well (although this would sharply decrease efficiency without extra coordination between client / server for bulk fetching).

This would significantly reduce MB-large JavaScript files because most of that code is shared general libraries. Even if you use a huge library like core.js with no tree shaking, it's no longer an issue, as long as many others are also using core.js.

I do know that module scripts can import from remote sites, and unpkg with the experimental '?module' resolves imports in unpkg modules to other unpkg modules. I also know that browsers are very good at caching modules. I doubt browsers are smart enough to bulk fetch multiple unpkg dependencies in one request.

Does anyone have more experience with, in general, trying to cache large JavaScript imports?


> The browser will cache the import, so that large common imports are rarely actually fetched.

Cross site caching is dead. Safari hasn’t supported it in years and Chrome recently dropped it as well. It’s better to hold all assets on your domain to avoid TCP and TLS overhead.

Here’s a blog post with more details about Chrome’s change: https://www.stefanjudis.com/notes/say-goodbye-to-resource-ca...


Looks like Firefox also made it the default in January with version 85.

https://developer.mozilla.org/en-US/docs/Web/Privacy/State_P...


Even before the current rules partitioning cache by domain, has the promise of those cached scripts ever paid off? Even when every website would use just jQuery, everyone had a different version, getting it from a different CDN, etc...


Look, sometimes we need to tell ourselves stories to make ourselves feel better about the amount of Javascript we're making people download to access our blogs.


Probably not. A few requests surely got cached, but the vast majority likely did not. jQuery has its own official CDN URL so that probably had a chance at being deduplicated.


> I doubt browsers are smart enough to bulk fetch multiple unpkg dependencies in one request.

https://github.com/WICG/import-maps/issues/209


Moment.js is a steaming pile. surprise mutations, not having separate date and time types (I've heard JS devs beef on this, but there are many cases where using a datetime as a date or time causes subtle errors), and bloated download size.


I remember my only interaction with someone in 2015 where they said "use moment" for something really trivial, it was a friend of a friend and he was a snarky arrogant snob. I don't remember exactly what I said other than being super passionate against it because it just complexified simple solutions because people weren't willing to read the documentation on how to use the builtins.

I even wrote the solution on a scrap of paper I had in about 20 seconds.

It was everything I hated about the dev community; some insistence on using hip and popular stuff that's poorly suited to a problem and being snarky and elitest snobs whenever anyone claims they are being trend following fashionistas and not doing any actual engineering. Same thing is going to happen to reactjs unless it pivots hard to being something dramatically different (which it keeps doing).

When a tool makes easy things hard and hard things impossible its days are numbered regardless of how fancy and popular it looks

He worked at some really well funded place, the kinds that spend enormous money to create products people hate. Holding the position against the grain when it's appropriate is necessary for the progress of the craft but my word is it a lonely place sometimes


Established projects using Moment.js a lot might have a hard time migrating to something else. Quite unfortunate because there are now much nicer / better optimized libraries/APIs out there today like date-fns, the new Temporal API, Luxon, etc.

For those still stuck with Moment, it's worth exploring means to reduce the impact on bundle sizes. I wrote about that a while ago: https://dsebastien.net/blog/2020-07-12-removing-moment-js-lo...


Day.js is basically a drop in replacement, and is 97% smaller. You still need to regression test, but imho it's one of the highest impact ways to spend a few hours if you care at all about performance.


Yep, indeed there are ways to migrate, but it's not necessarily easy. For instance in my last project, we used moment-timezone, and integrated other libraries such as https://github.com/urish/ngx-moment to format date/times in component templates. Of course it's possible to move away from that, but it would take time away from more useful work.


Ya, but testing dates and times is very hard. It’s easy to miss something.


True. But in this case the regression testing is mainly for if you miss an import, since some of the formatters require plugins. Fortunately if that happens it will be fairly obvious since iirc there will be random letters in the middle of the time string.


Shameless plug: if you’re looking for natural language date parsing, check out Sherlock.js - https://github.com/neilgupta/Sherlock

Otherwise, definitely try native APIs first for straightforward date manipulation.


Are there any good date/time libraries or utils for TypeScript that prevent you from mixing up variables with different units? E.g. mixing up integer timestamps vs integer durations in seconds vs integer durations in milliseconds.


You're asking for opaque types. This is kinda possible in typescript but you can only approximate it unfortunately.

You may also want to consider a branded type, which can be useful but a little less strict.


I’ve spent way too much time trying to perfect this technique and the best solution (until TS has nominal types, which I think they’re looking at for 4.5) is branding, with a private declared class field that’s optional and always never. Eg

    declare class _MySpecialPrimitive {
      private mySpecialPrimitive?: never;
    }

    type MySpecialPrimitive = number & _ MySpecialPrimitive;
Combined with type guards (which you can conditionally execute at runtime), you can narrow overly broad structural types safely, eg:

    const isMySpecialPrimitive(val: unknown): val is MySpecialPrimitive => /* anything that produces a boolean */
(And you can use assert guards in a similar way, but I find they make it easier to treat them as a noop)


I should add another way I tried to approach this that would be less Type System Theater was Symbols and runtime assignment of brands, eg

    const MySpecialPrimitiveBrand = Symbol('mySpecialPrimitive')

    const val = Object.assign(prevVal, { [MySpecialPrimitiveBrand]: doesntMatter })
Yeah, don’t do that unless you want to destroy every language facility that depends on reference equality checks. It boxes your primitive and breaks the world.


Libs provide something out of the box to do this, e.g. `ts-essentials` provides `Opaque`, so you just write `type DateString = Opaque<string, 'DateString'>`


Their version is essentially my Symbol approach, but only in the type system. This does work, but it has the disadvantage that the type and runtime don't match. It’s certainly better than most Brand types which tend to rely on strings, but I prefer not to expose public properties which don’t exist.

The class/private approach has the advantage of hiding the extra property from everything except the type checker.


I've build a library to do that (based on various known techniques) in [1]; it's also combined with validation based on zod. I would say it's usable but of course having true nominal type support in TypeScript would be way better.

For complex types it also disallows spreading to prevent circumventing validation. However, errors are often not has human readable as one would like them to be.

[1]: https://github.com/renke/vo/tree/master/packages/vod


I'd be interested, in what constitutes a performance sensitive web application... is it a full fledged 3D game renderung thousands of time strings per second? Or .... ?


In this case the article seems to be concerned about library size. 72kb vs 3kb is a real difference.


Loading and parsing all those KB of JS for a mobile website is almost a non-starter for publishers, who are now under the gun to shed as much page weight as possible to have a hope at SEO traffic going forward. Also, for people using outer reaches of the mobile web, it can cost up to $50 / GB USD - it seems cruel to cost them $0.05 to use a convenience function. For me, I was working on a serverless node.js function that needed to be able to minimize startup and execution time to control costs. It took a bit of extra work to use js Date, but using Moment literally doubled my cost to run the function.


Is this sarcasm? I wish publishers gave a damn about page weight. I’m sure some big names do, but most don’t, and it’s easy to see if you open any monetized website at all.


Page speed has long been a search ranking factor, but as Google News is now allowing non-AMP pages in the News Carousel with the requirement that they pass all 3 Core Web Vitals checks. This has forced a lot of search-dependant, ad-driven publishers to reevaluate their priorities and get better at page speed and UX. I led an effort to do so at an enterprise publisher, so I'm looking at it from that lens where we dropped lots of 3rd party libraries, services, and underperforming ads. You're right that many sites simply don't care. Google delayed their full rollout of what was expected to be a requirement in June 2021. When it is fully in effect, you probably won't be seeing super ad heavy sites ranking in mobile search as much. Sites that live off of social traffic may continue not to care.


lots of enterprise apps. You can end up with date calculations that don't actually take that long, but just enough to make users on slow systems go 'its broke i can't do my job, it's ITs fault'.


These days facebook.com could be considered as one.


What’s wrong with doing everything on the backend in epoch time then treating display to humans as a rendering + localization problem?


Latency


I love the approach. I would love to see a good quality "You don't need jQuery" out there; people talk about that, but I never found something to tell what to use instead and why, just generic "use JavaScript for DOM manipulation" (fair) and "use one of the alternatives for AJAX" (which one?).

Is there anything like this planned for "You don't need"?


The Ajax alternative is fetch, the native browser API which has excellent polyfills for the server which enable JavaScript to be isomorphic and dynamic to users and search engines. Basically your code will run as expected on the client or server, so fully rendered pages can be served - even if it needs to call an API to populate content.

https://youmightnotneedjquery.com/ Is this the kind of thing you were mentioning? Maybe it’s been a while, but if you Google “you don’t need jquery” you’ll find plenty like this and it seems to explain well enough.


The post-jQuery native browser APIs that were added to support those use-cases are querySelector for querying the DOM and fetch for AJAX (assuming you don't need the X part).


> assuming you don't need the X part

I have never actually had to deal with XML from the backend but if I had to, I guess I would await on `response.text()` from `fetch()` and then with an instance of `DOMParser()` call `parseFromString(xml, "application/xml")` and then query the resulting XML tree with `querySelector` et.al.


'You may not need javascript' is a repo I'd like to see.


It already exists, but it’s mostly about hacks that aren’t very accessible, like using checkboxes to simulate interactivity.


I really prefer using the <details> element for showing/hiding various content. It works amazingly well, and you can also hide the small triangle with some css. Much better than all those checkbox solutions that you see recommended all the time. But for some reason, nobody ever uses it.


I think details did in fact replace many of those checkbox hacks, but people also say it’s still the wrong tool for accordions and such, which confuses me.


not yet but maybe one day we can leave the 90s behind


You don't need all those small libs but apparently React is mandated in every shop now... the JS community is a joke.

Where is the "you don't need React" website/repo again?


People don't use React because the magnitude of managing the view update code is so large and/or complicated that diffing a reified DOM tree in toto is superior (I've seen it used for an app that consisted of a few screens with some text and a button each), its become standard so everyone learns one interface and development is normalized across shops. This has the benefit of a flourishing component ecosystem.


> its become standard so everyone learns one interface and development is normalized across shops

An industry using the exact same framework (for a time, it never lasts) doesn't make that framework a "standard". jQuery was also "a standard" by the same logic.

edit: I'm talking about web standards here, which is the DOM is part of. After the inane amount of hate jQuery got with hit pieces, JS developers were quick running to an even more intrusive and bloated framework that certainly was not "vanilla JS" either, the irony is somehow lost somewhere...


A standard choice, rather than run by a standards committee


You don't need React, just like you didn't need jQuery, just like you didn't need AngularJS. None of these are standards in anyway but only jQuery was problematic? Just no...


The dominance of React or Angular is largely a function of Facebook and Google having more powerful marketing machines and resources than John Resig.


JQuery solved a problem that was very real when we adopted it. But that problem doesn’t exist anymore, since browsers extended and refined their API.

However, isomorphic HTML generation/templating and state management are still unsolved from a browser native perspective.


Yes, thank you


True but also the amount of code React requires (even putting the library itself aside) is ridiculous. I’m working on a React project (but not directly on React) and the file length for ridiculously-basic stuff is mindboggling. Vue and Svelte are much saner.


I was wondering if you would mind being a bit more specific about your criticism towards React and the JS community?

If you know React well, it seems like there are things that everyone can learn from or think about. Would you use vanilla JS or other frameworks and why?


The sentiment is that none of this mess should be necessary - why isn’t all of this well-trodden functionality (like Redux/Reflux (not React) for state-management, for example) built-in to browsers now? Why do we have JS build-processes at all? Why can’t browsers cache modules and scripts (by hash?) indefinitely instead of falling victim to the browser cache and privacy gods?


libc/win32 doesn't have any of that either, you're supposed to use frameworks for that.


There is a historical reason for this. The strategy is to enable extensions via JS that rely on lower level, general APIs.

JS frameworks aren’t cruft, or a mess, they are artifacts of the intended path to enable highly flexible extensibility.


Built into which browser? And who's going to build it in?

This is a real "where's my flying car" kind of argument.


It's what happens when no one group controls the "open" web, and instead you have different advertising & services giants competing for the future of human information exchange. Blame Netscape for hurriedly shimming in a shitty language in the 90s and jumpstarting a war among the digital cartels.

Microsoft wants TypeScript and abandoned .Net dominance. Google failed with AMP. On the backend, Facebook's HHVM saw limited adoption, and node.js took over, even surpassing PHP in developer mindshare. So streamlining the front & backends was inevitable. Angular 2 was so bloated that it made React seem simple, and by the time Vue et al came around, React had so much inertia and community support that it was harder for them to gain traction. Apple checked out completely, Mozilla is still fighting the good fight but losing more ground every year, so now it's really just Facebook building on top of Google...

For what it's worth, the nightmarish toolchain is slowly getting better, with ES6 modules, dynamic imports, Web Components, service workers, and the such. NPM is also slowly improving, and semver has done wonders for maintaining library compatibility. Frameworks-on-top-of-libs like Next.js bring some much-needed boilerplate and tooling to React and generally make the whole experience both quicker and far more tolerable (you rarely have to edit tooling configs, and webpack/babel are invisibly handled for you). Not to say it's ideal -- far from it -- but people are definitely working on streamlining the developer experience. And from the UX side there is a lot of optimization and tree-shaking work happening too, to try to shrink down the ultimately delivered package sizes.

That's not to say React is right for every project. It's just the most popular, so easy to hire for and easy to collaborate on. Every vendor provides React demo code or readybuilt components and hooks, vs having to write your own for every trivial API use case. It's a real time-saver, and the closest thing to a de-facto standard the web dev world has had since jQuery was pronounced dead (RIP).

But hey, the JS ecosystem at its worst now is at least still better than having to choose between Flash, ActiveX, Java, and VRML. At least it all compiles down to JS. Or at least it did until WebAssembly (cry)...

In a way, JS is a victim of its own success. Reminds me a lot of the Linux ecosystem, where there are always 10,000 ways to do something depending on your particular distro and package manager and shell and window manager, yet never a single "best practices" way. There are a million ways to do anything in JS/TS/CoffeeScript/ECMAScript/React/Vue/Svelte and none of the come close to the relative orderliness of, say, PHP or the .Net stack. I'd say it's what happens when you do design-by-committee, except it's not, because JS is more like design-by-retrospective, and only after years or decades of suffering do best practices emerge from popular use and bubble up eventually into ECMA proposals, only to be largely ignored by Apple and so require polyfills (thanks, Safari).

Which is all to say, yes, it's still hard to work with and has room for a lot of improvement. The community at large is working on a lot of those problems, slowly but surely, while being constrained by the will and pacing of the behemoths. Maybe in 20 years' time things will be better... but who are we kidding.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: