[HN Gopher] Show HN: Auto-generate vanilla JavaScript alternativ...
___________________________________________________________________
Show HN: Auto-generate vanilla JavaScript alternatives for jQuery
methods
Author : alokdubey007
Score : 115 points
Date : 2021-09-06 12:59 UTC (10 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| franciscop wrote:
| I made a tiny jQuery alternative a while back called Umbrella JS:
| https://umbrellajs.com/
|
| Seeing methods like addClass in "replace-jquery", I'm not fully
| satisfied. I could make Umbrella JS tiny (1/2 of the alternative
| listed elsewhere in the thread, Cash, and 10% the size of jQuery)
| because of heavy method reusal. For instance, in Umbrella JS
| addClass is just: u.prototype.addClass =
| function () { return this.eacharg(arguments, function
| (el, name) { el.classList.add(name); });
| };
|
| In "replace-jquery" you are already depending on `this.`, so why
| not making a couple of useful utils? Right now it is more
| verbose, and doesn't accept e.g. an array of classes or classes
| as arguments: addClass(classNames = '') {
| this.each((el) => { classNames.split('
| ').forEach((className) => {
| el.classList.add(className); }); });
| return this; }
|
| Cash JS's addClass (which is hidden behind toggleClass(cls,
| true)) is nice, it's bigger BUT that's because it's 3
| implementations at once (addClass, removeClass, toggleClass). It
| properly uses a method to getSplitValues, which is very helpful
| and flexible: fn.toggleClass = function ( this:
| Cash, cls: string, force?: boolean ) { const classes =
| getSplitValues ( cls ), isForce = !isUndefined (
| force ); return this.each ( ( i, ele ) => {
| if ( !isElement ( ele ) ) return; each ( classes, (
| i, c ) => { if ( isForce ) { force
| ? ele.classList.add ( c ) : ele.classList.remove ( c );
| } else { ele.classList.toggle ( c );
| } }); }); };
|
| And I will spare you all jQuery's implementation, which is huge,
| but it can be seen here:
|
| https://github.com/jquery/jquery/blob/main/src/attributes/cl...
| gunapologist99 wrote:
| Does `cash` support jQuery-style `.ajax`?
|
| When you consider replacing `$.ajax` with fetch, you'll quickly
| found out that fetch is severely lacking with regards to:
|
| * handling cookies,
|
| * HTTP status codes (404, 403, etc),
|
| * CORS,
|
| * and even just simply readability when dealing with JSON.
|
| jQuery's ajax (and its aliases like $.GET) handle all of these
| (edge cases? are these really edge cases?!) with aplomb, so you
| don't have to worry about it.
|
| This is the issue with all of the jQuery alternatives, even
| cash (which does look pretty awesome); you start using them,
| and then development hits a halt because you suddenly realize
| that you actually need something that jQuery already does quite
| nicely, and has done so, quietly and politely, for more than a
| decade.
| shrew wrote:
| I'm genuinely curious to know what you find severely lacking
| in fetch compared to $.ajax.
|
| - handling cookies
| fetch('https://example.com', { credentials: 'include' })
|
| - HTTP status codes
| fetch('https://example.com').then(response => {
| if (response.ok) { // Response is 200-299
| } if (response.status === 404) {
| // Status code specific handling } });
|
| - CORS fetch('https://example.com', { mode:
| 'no-cors' });
|
| - JSON handling
| fetch('https://example.com').then(response =>
| response.json()).then(json => { // Do something
| with a parsed JSON object });
|
| I've used all of the above patterns regularly for several
| years now and never found any of them particularly cumbersome
| and certainly not lacking feature wise. If async/await syntax
| is available to you, it's even more succinct than the Promise
| style above.
|
| With that said, I've not used $.ajax in anger for a good long
| while so I may be missing out, particularly as I note there
| have been API changes in newer versions of jQuery. Are there
| some specific use cases that you've found fetch to be
| particularly inept in dealing with?
| fabiospampinato wrote:
| Cash's maintainer here. I think needing $.ajax is a fairly
| niche thing (like ~nobody using vue/react/svelte is asking
| for a jQuery-like ajax function, the world moved to fetch),
| and it's not something that you'd suddenly stumble upon
| either.
| franciscop wrote:
| Umbrella JS' creator here, I fully agree with that
| statement. You'd normally use something like Axios/Got/etc
| for a reusable API interface for API-heavy interfaces, and
| for simple cases it's not too complex to add e.g.
| `credentials: 'include'` for cookies.
| fabiospampinato wrote:
| Cash's maintainer here. I really don't think anybody can
| squeeze 50% out of the 6kb min+gzip code that make up Cash,
| quite a bit of thought went into squeezing as many bytes as
| possible out of it. (while still preserving a large degree of
| compatibility with jQuery, support for many methods and support
| for partial compilation)
|
| Your comparison isn't quite fair, our toggleClass function does
| a lot more than a simple addClass, and writing it this way
| lowers in fact the total min+gzip size.
|
| I'd be pretty impressed if you can shave just 1kb out of those
| 6kb to be honest.
| franciscop wrote:
| Agreed! Not a fair comparison either way; if I compare Cash'
| addClass then it doesn't really "do anything" besides call
| the other method, so I'd say the toggleClass is
| representative of _the 3 methods together_, so 1/3rd? It's
| nice code :)
|
| Shaving off 1kb out of 6kb of optimized GZIP code is probably
| impossible unless you missed something important.
|
| I also went deep into optimizing Umbrella JS, it does a lot
| less than Cash so hence it's a lot smaller as well; but I
| went so far as comparing the GZIP output of calling `for ()`
| vs `forEach`, etc:
|
| https://medium.com/@fpresencia/understanding-gzip-
| size-836c7...
|
| That's why I am not concerned of repeating e.g. `function()
| {}` (instead of the, back then, experimental () => {}) many
| times, since with gzip in my experience that gets all totally
| abstracted out.
|
| Edit: edited the original, explaining that Cash it's doing it
| nicely!
| 22c wrote:
| > but I went so far as comparing the GZIP output of calling
| `for ()` vs `forEach`, etc
|
| AFAIK Google Closure Compiler [1] does similar things
| automagically.
|
| [1] https://github.com/google/closure-compiler
| mynegation wrote:
| From the first glance it replaces the jquery calls to some $utils
| implementation of the same methods. I guess final bundle contains
| only methods in $utils that are actually used in the code base,
| but it looks like re-implementation of jquery subset. Would not
| just using jquery with tree-shaking achieve similar effect? (not
| a JavaScript expert, so sorry if it is a dumb question).
|
| Maybe another advantage of this is that new implementations
| target runtime version that is new enough to avoid most of the
| feature-checking and shims? Would be great if README addressed
| those questions.
| fabiospampinato wrote:
| jQuery is not tree-shakeable because it uses a chainable API.
| Like you don't import `toggleClass`, you access the
| `toggleClass` property of a jQuery instance, so it can't be
| tree-shaken off automatically.
|
| Even if somebody made a bundler plugin for doing the heavy work
| jQuery can only be partially compiled with whole modules
| excluded, you can't exclude individual methods (e.g. you can't
| just remove `toggleClass`, you have to remove also `addClass`,
| `removeClass` etc.).
|
| FYI I maintain a jQuery alternative that supports being
| partially compiled with individual modules turned off, but it
| requires manually listing them:
| https://github.com/fabiospampinato/cash
| timostamm wrote:
| Tree shaking works well when you have ESM imports / exports.
|
| jquery is/was usually loaded into the global scope. There is no
| standard way for tree shakers to deduct which parts of the
| library you are using.
|
| Yes, browser APIs have matured significantly since jquery was
| new and such a library doesn't add much value anymore.
|
| I agree it would be great if the README gave a bit more
| background. Whoever is looking to migrate away from jquery will
| be aware of the background though (and will likely appreciate
| this tool).
| hardwaresofton wrote:
| An old classic worth referencing if you're wondering whether you
| need jQuery (or any alternatives like UmbrellaJS[0] or Cash[0]):
|
| http://youmightnotneedjquery.com/
|
| [0]: https://umbrellajs.com/
|
| [1]: https://github.com/fabiospampinato/cash
| rubyist5eva wrote:
| I ditched this kinda manual DOM manipulation nonsense with
| mithril components+streams years ago and never looked back.
| fabiospampinato wrote:
| I maintain an alternative to jQuery called Cash [0], this looks
| cool! If you are interested in joining forces OP it'd be cool to
| have this capability in Cash itself. IMO that'd be the best of
| both world because this feature is cool and useful, and Cash's
| methods are most probably closer to jQuery's, better tested and
| there are more of them available (76 vs 44).
|
| For example, your `on` method [1]:
|
| - Doesn't support event delegation.
|
| - Doesn't support event namespaces.
|
| - Doesn't support receiving an argument mapping events to
| callbacks like jQuery also can.
|
| - It seems to have subtle bugs, like the way the events string is
| split makes so that double consecutive spaces in it (which can
| happen as a result of a typo) will result in listening to the
| empty string event. Basically: 'foo bar'.split ( ' ' ) => ['foo',
| '', 'bar'] (there are two spaces between foo and bar).
|
| The `on` method we are using in Cash [2] is a lot more convoluted
| than that. On one hand it requires more bytes, but on the other
| the chances of it behaving exactly like jQuery's are much higher.
| In fact we can also run jQuery's test suite with Cash to spot
| issues.
|
| Feel free to ping me if you are interested in joining forces.
|
| [0]: https://github.com/fabiospampinato/cash
|
| [1]: https://github.com/sachinchoolur/replace-jquery#on
|
| [2]:
| https://github.com/fabiospampinato/cash/blob/master/src/even...
| snet0 wrote:
| "I made a tool to remove a library"
|
| "Would you like to integrate that tool into my library?"
| fabiospampinato wrote:
| Kinda accurate, but as soon as you realize that "tool" is
| basically another name for "library" it makes sense. Like OP
| replaced code with code at the end of the day, who cares if
| you call it "library" or "tool" or something else.
| sachinneravath wrote:
| Sure, Cash is super cool. I wrote this library for my personal
| use. As I was repeating the same work on multiple projects.
| While removing jQuery dependency, the hardest part was finding
| the jQuery methods in the existing project and writing the
| alternative vanilla js methods without making much changes in
| the codebase. Yes, I agree with you the events part needs to be
| improved and well documented. (It actually supports
| namespacing.) I fixed most of the things in
| https://github.com/sachinchoolur/tiny-events.js and need to
| make the changes here as well.
|
| My intention was not to build another JavaScript utility
| library. I just wanted to make my JavaScript libraries jQuery
| independent.
| labster wrote:
| Seems pretty cool. The only Cash design decision I'm doubting
| is $().append not accepting plain text. I get the reason why,
| but the alternative is ugly. Maybe add an appendText method, or
| a utility $.textNode?
|
| I'm kind of assuming the underlying philosophy of the project
| is to make DOM manipulation as easy as in jQuery but smaller by
| removing seldom needed safeguards and relying on modern browser
| selectors. I'm okay with the additional footguns but think it
| should still preserve easy, concise syntax.
| fabiospampinato wrote:
| That's kind of a mistake of the library IMO, but changing
| that requires pushing a major release and I'm not sure if
| it's worth asking everybody to update their code to align
| that with jQuery at this point.
| manigandham wrote:
| Vanilla JS refers to Javascript that uses native browser methods
| instead of relying on a library. This is just replacing jQuery
| with another library constructed on the fly, but there are
| already minimal and modern alternatives with the jQuery API like
| zepto and cash.
|
| 1) https://github.com/fabiospampinato/cash 2)
| https://github.com/madrobby/zepto
| laurent92 wrote:
| Actually, VanillaJS is now a library. It can be downloaded in
| 0KB, or 25KB gzipped. Not to be confused with "Vanilla JS". It
| comes with the famous "Math" library that Google and Strip use,
| for 0KB additional.
|
| http://vanilla-js.com/
| q-rews wrote:
| This. There's zero sense in using 1:1 replacements of jQuery
| nowadays since jQuery already has a slim version.
|
| If you want to drop jQuery, you have to rethink the code.
| fabiospampinato wrote:
| Cash's maintainer here. IMO it could be worth for some use
| cases to use a replacement for jQuery, for the record Cash is
| ~75% (~20kb minified and gzipped less) smaller than jQuery
| Slim, that isn't/shouldn't be a rounding error for many use
| cases.
| vmception wrote:
| These are good points, people are more so taking issue with
| the title.
|
| I was expecting a tool that just tells me how to do
| something in Javascript - without any library - that I
| would be tempted to use just include jQuery for.
|
| Instead I'm presented with a library.
|
| I expected the comment sections to be talking about how
| AI/ML crowdsourced code aggregators keep messing up,
| instead I'm reading about a simple additional convenience
| library that a contractor wrote for themselves, and
| described wrong.
| ape4 wrote:
| I'm going to keep jQuery for a while. Its not so big and even
| though native js has "caught up" in places jQuery is still more
| compact.
| q-rews wrote:
| People are confused about what vanilla JavaScript means. If
| you're replacing jQuery for another loose library you're just
| fooling yourself and wasting time doing it.
|
| This is akin to all those StackOverflow answers suggesting to use
| `any` for every TypeScript problem they encounter.
| simondotau wrote:
| It's worth remembering that jQuery is a ~30kb "cost" for the end
| user. Once upon a time, that was a lot. And it was entirely
| prudent to question its necessity on the basis of load times and
| bandwidth consumption.
|
| But now we live in a world where many common web pages have over
| 1000kb of resources on them. And nobody blinks an eyelid.
| Wowfunhappy wrote:
| > And nobody blinks an eyelid.
|
| But maybe they should?
|
| Like, I agree that if your web page loads a full MB of
| Javascript, eliminating JQuery should be the least of your
| concerns; it's a drop in the bucket, so optimize elsewhere. But
| web pages _really_ shouldn 't be loading 1 MB of Javascript in
| the first place.
|
| It's so nice when I come across a website that's actually slim,
| I can really feel the difference...
| manigandham wrote:
| Unfortunately this kind of thought process is what leads to
| pages with megabytes of JS. Every byte matters.
| simondotau wrote:
| But it isn't a one-way street. Using jquery can eliminate the
| need for other, lengthier blobs of code. In fact that's
| exactly what this "vanilla JavaScript alternative" does.
| sanitycheck wrote:
| But, we didn't used to have megabytes of JS on pages back
| when everyone used jquery.
|
| I think what leads to pages with megabytes of JS is when
| people automatically assume that all projects must be a SPA
| built on one the popular everything-but-the-kitchen-sink
| frameworks.
| mkoryak wrote:
| This is especially true because now instead of all your
| dependencies using jQuery, they are each implementing a small
| subset of jQuery on their own.
|
| The problem you thought you solved was actually made
| exponentially worse when those dependencies dependencies also
| rewrote some jQuery using different native methods
| fabiospampinato wrote:
| I'm not sure I buy this argument, one can't just say that ~30kb
| isn't a lot because 30 is a number perceived as low, would 30kb
| be justified for a library that allows you to toggle a class on
| a node? Of course it wouldn't, you need to measure what you are
| getting for 30kb.
|
| I don't buy the second part of the argument either, you can
| load a 1000kb image on a blog post and that won't have nearly
| the same effect as loading 1000kb of JS. The JS needs to be
| parsed and executed and maybe the site doesn't even work
| without it, the image can probably be rendered progressively,
| can be decoded in another thread, nothing is really waiting on
| it to load, and if it doesn't load at all it's not the end of
| the world anyway.
|
| With ~4kb you can have Preact, is jQuery Slim (~26kb) giving
| you ~6.5x times as much value as Preact really? Maybe it is,
| probably not.
|
| For some context I maintain a ~6kb rewrite of a subset of
| jQuery (https://github.com/fabiospampinato/cash), which IMO is
| much better value proposition for many use cases.
| sanitycheck wrote:
| Not just 1000kb.
|
| netflix.com (which doesn't even do anything): 1.6MB
|
| CNN: 3.4MB
|
| NYT: 4.1MB
|
| Guardian: 5.7MB
|
| IGN: 69.5MB
|
| I still use jquery when I'm targeting ancient devices. Some of
| them still run Presto. Performance is fine, file size is fine -
| and drastically smaller than any of the sites above!
|
| (I can see why one might not want jquery as a dependency of a
| dependency though.)
| beebeepka wrote:
| I used to work on low power/ancient devices running presto or
| blink. Performance was much better on opera 12.80 or so.
|
| At some point I had to support an outside team working on
| external application running inside ours.
|
| These guys used jQuery in ways it shouldn't be used when
| performance is an issue. Had to spend a few hours reducing
| their code to mostly CSS and just a tiny bit of honest to god
| js that even presto can understand and render.
|
| Point is, it's really easy to overuse and that can have an
| effect on performance, even on presto
| sanitycheck wrote:
| We may know the same devices - designed to run Flash Lite
| acceptably then made to just barely support HTML/JS with
| heroic engineering efforts later. Nobody believes how slow
| they are until they try.
|
| I think if someone queries the DOM a lot on these things,
| especially in response to keypresses, they're in trouble
| whether or not they're doing it with jquery.
| t0astbread wrote:
| Are you sure you weren't loading a video on IGN?
| Ardren wrote:
| Yep, looks like it's a video.
|
| But it's auto-preloaded and playing even when not
| visible...
| Lurkars wrote:
| I first thought that it replaces jQuery with vanilla, but it
| replaces jQuery functions with other functions? With this point
| of view using the term vanilla would mean that there is no
| difference to jQuery, because in the end jQuery is also written
| in vanilla? Or do I get something wrong here?
| codingdave wrote:
| This is more like tree-shaking jQuery into just the pieces you
| need from it, so you aren't loading up the full library when
| you are only using 20% of it.
| dheera wrote:
| Maybe there should be a jQuery Nano with just the most
| commonly used methods.
| sverhagen wrote:
| That seems fodder for endless debate, does it not?
| warpspin wrote:
| With all the people replacing jQuery manually in their projects,
| you have to wonder whether the summed up costs of everyone
| running their own replacements is not larger than jQuery itself,
| once you use 3 or 4 such libraries :D
| SOLAR_FIELDS wrote:
| It's been awhile since I've worked in the frontend space, but
| even 5 or 6 years ago if you were using a pretty popular hosted
| CDN of JQuery with a pretty recent version there was a pretty
| good chance it was already cached on the end user's device when
| they hit your site. There's always a lot of talk about Jquery's
| size but I wonder how many users don't even notice because
| they've already got it on their system.
|
| There's also of course the added cost of executing the library
| on the site but I'm guessing V8 and other JS engines have
| optimized the hell out of that too as to make it pretty
| negligible in terms of time difference.
| JZumun wrote:
| Modern browsers partition caches by site nowadays - at least,
| Chrome started doing it last year[0], and Firefox followed
| soon after I think [1]. That means there's no longer any
| caching benefit for multiple websites using jQuery - each
| site will download and cache it separately.
|
| [0] https://developers.google.com/web/updates/2020/10/http-
| cache...
|
| [1] https://developer.mozilla.org/en-
| US/docs/Web/Privacy/State_P...
| SOLAR_FIELDS wrote:
| Interesting. Reading Mozilla's justification it does make a
| lot of sense, however it is kind of unfortunate to lose
| something that was pretty beneficial in terms of
| performance because of some bad actors. It's not really
| viable to maintain a whitelist of trusted libraries either,
| and doing so would create a whole new class of problems.
|
| Ideally CDN's are powerful and ubiquitous enough these days
| that at least when you have the end user going and asking
| for JQuery from Cloudflare or whoever the CDN probably has
| a very fast location right next to them distance wise and
| that data should get over the wire pretty dang quickly.
| It's still another performance hit though since you know at
| least the first time on the site they have to go and get it
| and if you are hosting your own stuff it might make more
| sense to just webpack everything together and hand it off
| to the CDN instead of having something like JQuery be on
| its own. Less overhead for opening another network request
| and all that.
| Etheryte wrote:
| While this is technically interesting, I can't help but ask what
| the benefit of this is? Instead of using a library that's battle-
| tested and well documented you'll now have to maintain an ad hoc
| replacement with unknown unknowns. Cutting down your bundle size
| is a good goal, but this feels like much too steep of a tradeoff.
| mkoryak wrote:
| There is a trend in web dev right now to stop using jQuery
| because reasons. These reasons make sense if you use a
| framework and sometimes need to venture outside of it.
|
| The problem is that the reasons are not often understood and
| then a tool like this comes along and now we can easily replace
| jQuery with a worse API adapter. Hooray!
| byteface wrote:
| I do feel the move against jquery comes from people that
| surpass it, which seems a shame. They had to use it once.
| It's like burning the rope for the people behind. Many low
| level users don't care about 30kb to get the $ shorthand as
| it's a habit they've had for a decade. It's funny almost to
| see the hoops people jump through not to use it. Like having
| a point to prove and not being able to prove it. Hey look,
| you can replace jquery with these 10 unmemorable esoteric
| steps.
| cormacrelf wrote:
| The repo says it is for lightGallery, which is trying to
| offer a framework-agnostic lightbox component. Modern JS
| setups simply don't play nice with jquery.min.js, and it's a
| big download and hard to slice up. This helps folks reuse
| more old work like lightGallery. That's a pretty good reason,
| almost the best possible reason to build this, I think.
|
| How it will likely be used is a different matter -- if you're
| a company trying to hire young devs and don't like to admit
| you have any legacy tech in the stack, then this is HOT code
| right now. Same if you need some bullshit targets to hit
| before the end of the quarter. Get on it!
| masklinn wrote:
| > There is a trend in web dev right now to stop using jQuery
| because reasons.
|
| One reason is that a lot of jquery's bulk is compatibility
| concerns or BC in edges, if you decide that you don't support
| old jQuery (mis)behaviour, older APIs, older browsers, ...
| you can probably slim it down a fair bit.
|
| A bunch of utilities you can also probably do without e.g.
| your jQuery.map, animations stuff, ... jQuery is
| progressively deprecating more and more things, but it's a
| harder sell to actually remove them.
| mkoryak wrote:
| Like I said, all the reasons for removing jQuery are valid,
| but only in the context of the codebase where they are
| given.
|
| You wouldn't want to remove jQuery from an app that is used
| by IE9.
|
| People end up hearing the reasons and don't stop to think,
| hey does this actually apply to my code? What are the trade
| offs for that 30k of code?
|
| Many just end up rewriting what jQuery did in a non
| reusable way that contributes to code bloat and bad
| readability.
| Deukhoofd wrote:
| I guess it might be useful as a first step if you want to
| reduce your dependencies on jQuery. First use this so you can
| drop the dependency, then slowly replace the functions you're
| using.
| yawaworht1978 wrote:
| Is there anything like this for react, Vue etc?
|
| Now that would be a milestone.
| t0astbread wrote:
| Shouldn't that be handled by tree-shaking?
___________________________________________________________________
(page generated 2021-09-06 23:01 UTC)