6 ms·
TinyJS – Shorten JavaScript QuerySelect with $ and $$
- gregoriol 2y ago[flagged]
- deleted 2y ago[deleted]
- yu3zhou4 2y agoLike jQuery but for 2024?
- NetOpWibby 2y agoI dig it
- wackget 2y agoThat would just be jQuery.
- tbeseda 2y agoYep. jQuery 4.0 is in it's second beta[0] and seems to clock in at 27kB. And the "slim" version is <20kB. [0] https://blog.jquery.com/2024/07/17/second-beta-of-jquery-4-0-0/ https://blog.jquery.com/2024/07/17/second-beta-of-jquery-4-0...
- adhamsalama 2y agojQuery? What are you, five? We use jjQuey.
- NetOpWibby 2y ago> This README was generated by ChatGPT Damn good README. Also, good library.
- hombre_fatal 2y agoToo wordy yet doesn’t even explain the tag part of the API. It just shows up in an example. A readme should be more reference / show and less drivel.
- EMM_386 2y agoI do believe I've seen something like this under another name. Using "$" to shorten JavaScript? That seems a lot like jQuery. > This README was generated by ChatGPT You don't need AI to explain this one.
- synergy20 2y agoThis is the whole code: (() => { const assignDeep = (elm, props) => Object.entries(props).forEach(([key, value]) => typeof value === 'object' ? assignDeep(elm[key], value) : Object.assign(elm, {[key]: value})) const tagNames = ['a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'base', 'bdi', 'bdo', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'cite', 'code', 'col', 'colgroup', 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', 'main', 'map', 'mark', 'meta', 'meter', 'nav', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'script', 'section', 'select', 'small', 'source', 'span', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr' ].forEach(tag => window[tag] = function(...args) { const props = typeof args[0] == 'object' && !(args[0] instanceof HTMLElement) ? args.shift() : null const elm = document.createElement(tag) props && assignDeep(elm, props) elm.append(...args.map(a => typeof a == 'string' ? document.createTextNode(a) : a)) return elm }) window['$'] = selector => document.querySelector(selector) window['$$'] = selector => Array.from(document.querySelectorAll(selector)) })()
- synergy20 2y agowindow['$'] = selector => document.querySelector(selector) window['$$'] = selector => Array.from(document.querySelectorAll(selector)) is really what I want to have
- iudqnolq 2y agoI'm quite fond of a little helper like so: createElement({ className: 'p-2 flex justify-end', contents: createElement({ tag: 'img', src: '/os-logo-maps.svg' }), }); I got the idea from Lea Verou's blissfuljs. When you're creating a bunch of nested elements it comes in handy.
- 123yawaworht456 2y agomay I ask what's the point of `const tagNames =`? removing it would make no difference, as far as I can tell - just make sure the previous line ends with a semicolon (or add it at the same line as the opening square bracket)
- hoten 2y agoWell, it's polluting the global window scope with all those helpers. That's a reason to never use this imo. There are plenty of other jquery-lite helper libraries out there. 95 percent the utility with hardly any cost in terms of script size. Converting querySelectorAll to an array is honestly most of the benefit of these libraries.
- spankalee 2y ago> Converting querySelectorAll to an array is honestly most of the benefit of these libraries. Now that NodeList is iterable, I don't even know that converting to an array is that useful anymore. [...document.querySelector('div')] is pretty easy. Iterator.from(document.querySelector('div')) too (doesn't work yet in Safari).
- xPaw 2y agoYou don't need to convert querySelectorAll to an array, you can directly iterate it, or use forEach.
- meow_catrix 2y agoNot if you want to map or reduce it.
- smusamashah 2y agoYes, exactly. The first two statements have no use in the last two lines that this library is for. Or may be I don't understand Javascript much.
- alexjplant 2y agojQuery II: The Quickening! I recently built a toy Golang SSR project using Zepto, a jQuery-like library, and felt like I was 17 again (**EDIT: it's unmaintained - don't use it). Also of note is that "Highlander II" takes place in the year 2024 [1]. It's a sign! Everything old is new again! `$` is immortal! [1] https://en.wikipedia.org/wiki/Highlander_II:_The_Quickening https://en.wikipedia.org/wiki/Highlander_II:_The_Quickening
- deleted 2y ago[deleted]
- no_wizard 2y agoZepto is unmaintained, which isn’t good for security issues or bugs, unfortunately. jQuery proper is both maintained and has actively been working on a 4.0 release and still gets security and bug fixes
- alexjplant 2y agoThanks for bringing this up. Edited my OP - there's no impression as such on their front page and it seemed fairly ergonomic. My bad on that one.
- franciscop 2y agoI also created almost 10 years ago Umbrella JS, which is a tiny jQuery replacement but with more array-like arguments in the functions: https://umbrellajs.com/ https://umbrellajs.com/ https://www.bennadel.com/blog/4184-replacing-jquery-110kb-with-umbrella-js-8kb.htm https://www.bennadel.com/blog/4184-replacing-jquery-110kb-wi...
- luismedel 2y agoIIRC, I used Zepto with Phonegap around ~2012. What a blast from the past. "There can be only one"
- CSSer 2y agoCalling those $ and $$ selector helper functions new is a bit disingenuous. They’ve been present as Chrome dev tools shortcuts for years. Let alone JQuery, I’ve also spent years seeing little articles about this neat trick on everything from medium to dev.to. I recommend the author remove that or note inspiration from the README to avoid detracting from the rest of the work. I realize there’s more here than the traditional document.querySelector.bind(document) assignment.
- wackget 2y agoI'll just leave this here: https://www.youtube.com/watch?v=Uo3cL4nrGOk https://www.youtube.com/watch?v=Uo3cL4nrGOk
- deleted 2y ago[deleted]
- henriquez 2y agoYou didn’t need a library to do this. Just alias document.querySelector and document.querySelectorAll to something shorter. Polluting the global namespace with functions to document.createElement on every possible html tag is not a good idea.
- tomp 2y agoWhy would this make any sense? const myDiv = div( {id: 'container', className: 'my-class'}, h1('Hello World'), p('This is a dynamically generated paragraph.') ); document.body.appendChild(myDiv); That's completely unnecessary these days with template strings. It's gonna be much faster as well to use browser's native parsing. const div = document.createElement('div'); let text = 'This is a dynamically generated paragraph'; div.innerHTML = ` <div id="container" class="my-class"> <h1>Hello world</h1> <p>${text}</p> </div> `; document.body.append(...div.children); Keep it simple!
- franciscop 2y agoOne big difference and why I've been experimenting with JSX[1] is that in that example, if the `text` comes from an untrusted source it can lead to XSS, which TinyJS prevents (I checked)! [1] https://x.com/FPresencia/status/1838176000267452704 https://x.com/FPresencia/status/1838176000267452704
- wruza 2y agoEven if it comes from a trusted source, you usually want a good distinction between html interpolation and just-text chunks.
- spullara 2y agoyou should probably worry about untrusted data in text and use a tagged template function that sanitizes its inputs for insertion in html.
- deleted 2y ago[deleted]
- nikeee 2y agoYou can use tagged template functions to escape `${text}`. The result is pretty close to lit-html [1]. [1]: https://lit.dev/docs/v1/lit-html/introduction/ https://lit.dev/docs/v1/lit-html/introduction/
- dpweb 2y agoIf ya don't want to do includes, ` window.$ = document.querySelector.bind(document) window.$$ = document.querySelectorAll.bind(document) `
- qingcharles 2y agoThanks, this is the more useful bit of the code to me. edit: how about this so you can use array functions too when you need? window.$ = document.querySelector.bind(document); window.$$ = document.querySelectorAll.bind(document); window.$$$ = (selector) => Array.from(document.querySelectorAll(selector));
- deleted 2y ago[deleted]
- janalsncm 2y agoI’ve been doing this for years. Lightweight but still saves me a ton of time.
- mendyberger 2y agoCode is actually tiny. Impressive! You could make it even smaller by removing all the element names, and just have it be passed in as an argument. Would also reduce the amount of functions you need to declare, though function count is likely not a problem for modern JS engines. Anyway, great job you did there!
- emmanueloga_ 2y agoI use this: export const $ = document.querySelector.bind(document); export const $$ = document.querySelectorAll.bind(document); When using TypeScript the types for querySelectorAll are a bit hairy to map but by defining the consts like above the types "just work". for (const tag of $$<HTMLParagraphElement>("p")) ... I don't use Array.from in the result of $$ because sometimes creating an Array is not necessary. The NodeList returned can be iterated directly or converted to an array later if really needed: [...$$("p")].map(p => ...) Since I use TypeScript I lean on TSX for building HTML. I use preact's render-to-string package to convert it to a string [1]. --- 1: https://github.com/preactjs/preact-render-to-string https://github.com/preactjs/preact-render-to-string
- cies 2y agoYou're a wizzard! JS keeps amazing me. It reminds me of Perl somehow. If Perl and Lua had a child, with some browsers APIs sprinkled on top.
- jufitner 2y agoSomeone will fork this with proper ES modules and no window clobbering.
- akira2501 2y agoI've been using this for years: const $id = new Proxy({}, { // get element from cache, or from DOM get: (tgt, k, r) => (tgt[k] || ((r = document.getElementById(k)) && (tgt[k] = r))), // prevent programming errors set: () => $throw(`Attempt to overwrite id cache key!`) }); It's nice to be able to refer to elements by property name, so: <div id="thing"></div> Is reachable with: $id.thing And, since the underlying structure is just an object, you can still enumerate it with Object.keys, which can sometimes be a useful debugging aid and general catalog of accessed elements. Anyways.. Proxy is a wildly underappreciated and used class in JavaScript.
- nattaylor 2y agoIf you like brittle things, the id attribute is already made into an attribute on the window for legacy reasons Edit: My tone may have indicated that parent's solution was brittle. It's not!
- akira2501 2y agoThe id attribute can take on values that are already present or reserved in window. "fetch", "opener", etc.. The reason to have a separate system that correctly calls getElementById() is to avoid this issue. So, it's actually a _less_ brittle mechanism that doesn't rely on legacy mechanisms and lacks the surprises that come with that.
- nattaylor 2y agoSorry, I didn't mean to suggest your solution was brittle -- I actually quite like it and want to adopt it! But I do think the legacy browser behavior with the ID attribute as window properties is very brittle for the reasons you suggest
- akira2501 2y agoMy fault, I tend to "rapid fire" sometimes. Yours was next to another reply on the identical subject and that caused me to mistake the meaning of the comma in your sentence. Reading it more slowly, I see it now, and, thank you!
- gvx 2y agoWith that name I'd expect a tiny implementation of JavaScript.
- tbeseda 2y agoI was just reading about this https://porffor.dev https://porffor.dev > Porffor is a unique JS engine/compiler/runtime, compiling JS code to WebAssembly or native ahead-of-time.
- dang 2y agoRelated: Show HN: Tiny JS – A Tiny JavaScript Library for Easy DOM Creation - https://news.ycombinator.com/item?id=41462817 https://news.ycombinator.com/item?id=41462817 - Sept 2024 (4 comments) Show HN: A better way of writing HTML via JavaScript? - https://news.ycombinator.com/item?id=41451559 https://news.ycombinator.com/item?id=41451559 - Sept 2024 (9 comments)
- im_nullable 2y agoBased on the readme this is a subset of jQuery primarily targeted at creating dom nodes. Kind of cool if this is what you need.
- atum47 2y agoHi everyone, author here. Let me know if you have any questions.
- SahAssar 2y agoThe title ("TinyJS – Shorten JavaScript QuerySelect with $ and $$") seems to be about these two lines: window['$'] = selector => document.querySelector(selector) window['$$'] = selector => Array.from(document.querySelectorAll(selector)) The other part is a small & naive (and I mean that in the best way) DOM abstraction. I think the discussion here seems to be about one or the other, not the thing as a whole.
- sublinear 2y agoSheer pollution. Never in anything I deploy to production.
- coolThingsFirst 2y agoPls no, im tired boss
- benabus 2y agoI remember when we would throw this into our utilities.js scripts back in like 2007. We didn't have querySelector yet, though. We'd also walk to school with no shoes, in the snow, uphill, both ways.
- gmac 2y agoReminds me of some simple tools I used years ago when CoffeeScript was big: https://github.com/jawj/affogato/blob/master/functions.coffee https://github.com/jawj/affogato/blob/master/functions.coffe... Nowadays I tend to use Mithril instead, because immediate-mode UI is so much less hassle than retained-mode: https://mithril.js.org/ https://mithril.js.org/
- 1GZ0 2y agoI wrote my first jQuery lite selector clone a bit ago, any feedback would be appreciated, especially since I don't see the need to separate out querySelector & querySelectorAll ``` const $ = (param) => { if (typeof param === "string" || param instanceof String) { const elm = document.querySelectorAll(param); return elm.length > 1 ? elm : document.querySelector(param); } else { return [param].length === 1 ? [param][0] : [param]; } }; ```