[HN Gopher] A whole website in a single JavaScript file ___________________________________________________________________ A whole website in a single JavaScript file Author : lambtron Score : 133 points Date : 2022-04-06 16:07 UTC (6 hours ago) (HTM) web link (deno.com) (TXT) w3m dump (deno.com) | jack_riminton wrote: | I don't think a simple, static site is a great example for an | entire framework | AaronO wrote: | What other kinds of examples would you like to see ? | | The goal was to showcase simple yet intuitive JSX + tailwind at | edge, we didn't elaborate on more advanced use-cases like | authenticated pages, API endpoints/forms, dynamic pages | (location, etc...) or parametric routes. | solitus wrote: | I'd love an example where the user updates some piece of | data. The update should be displayed right away to the user | and in a DB. | gherkinnn wrote: | This is great. | | I've been dabbling in Deno for a while now. Standard lib is | there. Testing is there. All the packages I'd ever want are | there. Linting, a strong style guide, and a documentation | generator too. | | And unlike other beasts, it feels so minimal and out of the way. | infiniteL0Op wrote: | onion2k wrote: | Tons of big websites use something quite similar to this for | their maintenance pages - pop a page of HTML in a JS function, | upload it to a Cloudflare worker, and attach that worker to a | wildcard route to catch everything on your domain temporarily | when you want users to see your maintenance page. It's a common | strategy that works well. | gtirloni wrote: | _> These are served using the serve function from the standard | library._ | | I guess Node.js could learn a lesson here. | binarymax wrote: | Demo was started by the original author of Node, and they took | lessons learned to this new platform. | | Also note that Deno is an anagram of node :) | yawnxyz wrote: | Wow that's cool. Would love to see a more "interactive" to-do or | "guestbook" site that shows how that side of things work. | | Also wondering if this can be done serverless-ly or requires | something always on? | ovao wrote: | > /// <reference no-default-lib="true"/>: Deno comes with various | TypeScript libraries enabled by default; with this comment, we | tell it to not use those, but instead only the ones we specify | manually. | | Interesting. I checked the docs on this and it's not quite clear | to me why this is needed in this case, or what the benefit is in | taking this approach. Is this strictly a build time optimization, | or is it necessary in this example? | lhorie wrote: | I mean, this is a "single file website" in the sense that | `<iframe src="https://google.com"></iframe>` is a "search engine | implementation in one line of code". | | The only semi-interesting thing here is that this demo pulls | dependencies from 3rd party registries via HTTP without an | explicit install step. It's really not that different than doing | regular Node.js development with a committed node_modules (hi, | Google), except that if node.land or crux.land go down, you've | lost your reproducibility. | | The thing about "familiar/modern techonologies" seem like | superficial vanity. A vanilla Node.js equivalent might look | something like this import {createServer} from | 'http' import {parse} from 'url' const route | = path => { switch (path) { case '/': | return home() case '/about': return about() | default: return error() } } const | home = () => `Hello world` // etc... | createServer((req, res) => { | res.write(route(parse(req.url))) res.end() | }).listen(80) | | Which is really not anything to write home about, nor an | intimidating monstrosity by any measure. Serving cacheable HTML | is really not rocket science, it simply does not require "the | latest and greatest" anything. | CreepGin wrote: | Now, add jsx and ssr to your example, deploy it, then compare | with the deno version in terms of performance, code length, and | dev time. | lhorie wrote: | Why? Just so you can tell another developer that there's a | compiler transpiling non-standard syntax into function calls | that concatenate strings at runtime? While the output HTML | that the user sees is exactly the same? That's exactly why | I'm calling out to be library vanity. My example _is_ SSR, | that 's literally the default baseline. It doesn't make a | very strong argument to imply my 5 min thing will somehow be | worse if only you get to decide what random garbage to add to | it to make the alternative look better. E.g. Make hegel types | work in the original and then let's talk loss of productivity | from arbitrary decisions. | | Deployment for a vanilla node.js thing is as simple as adding | `node index` as the entry point in your favorite provider | (because they all have node.js images these days), I've had | such a thing humming along for years. Again, it's really not | rocket science. | CreepGin wrote: | Different use cases. You equate SSR to just serving | strings. Others need to use jsx + SSR together (be it | personal preference or hard requirement). | | Imperative vanilla code vs Declarative components. Both | should have their place. | lhorie wrote: | SSR means server-side rendering. String-ness is | irrelevant (everything is a string as far as HTTP is | concerned). The difference is between serving HTML vs JS | for the purposes of generating a DOM tree. The article is | using nanossr specifically to server HTML, MPA-style. My | thing is using template string, which is what systems | like lit-html use for their flavor of "declarative | components" | | Whether one wants to squint at this and think of React is | neither here nor there. Svelte, for example, cannot | implement this website in this MPA format with only one | `.svelte` file, but I don't think it's necessarily more | verbose or slower to develop with than, say, Gatsby. | [deleted] | crowlKats wrote: | I wouldnt say an iframe and this are in any way shape or form | comparable. this is a "full-fledged" website. | | > except that if node.land or crux.land go down, you've lost | your reproducibility. | | Dependencies are cached. This is no different from if npm would | go down. | | > The only semi-interesting thing here is that this demo pulls | dependencies from 3rd party registries via HTTP without an | explicit install step | | Given that this seems interesting to you, it seems you haven't | heard of Deno (https://deno.land). It is not related to node in | terms of environment, its a new completely separate runtime. | | In regards to your node example, this is fairly different: the | dependency pulled in from deno.land is a wrapper around the | built-in http server, which does various error handling for you | and simplifies the usage. The router isnt a simple switch | statement either; its a URLPattern (the web's version of path- | to-regexp) based minimal router. Campring these to the node | built-ins isnt exactly a fair comparison I would say. | | Also on top of this, with node you need a configuration to get | typescript working, then you need a package.json, etc etc. | lhorie wrote: | Yes, I know what Deno is, and when I say "semi-interesting", | I mean I'm trying to find a silver lining to praise Deno for. | To clarify, the similarity is that this claims to be a | "single file" thing by importing the meat of the | functionality from elsewhere. Which is not really interesting | at all, because using batteries to make websites was already | a thing with PHP in the 90s. Or, as I mentioned, it's not | that different from just using express or path-to-regexp or | lodash or whatever in a typical Node.js setup. | | Caching dependencies is very different from general | reproducibility. Committing node_modules guarantees that the | app works even if the NPM registry were to implode. Try to | deploy your deno thing from a cold state (e.g. maybe you're | moving to a different AWS region or a different provider or | whatever) while there's a deno.land outage and it _will_ blow | up. I 'm actually curious what this caching story looks like | for large cloud fleet deployments. Hopefully you don't have | every single machine individually and simultaneously trying | to warm up their own caches by calling out to domains on the | internet, because that's a recipe for network flake outs. At | least w/ something like yarn PNP, you can control exactly how | dep caches get shuttled in and out of tightly controlled | storage systems in e.g. a cloud CI/CD setup using AWS spot | instances to save money. | | These deno discussions frankly feel like trying too hard to | justify themselves. It's always like, hey look Typescript out | of the box. Um, sure, CRA does that too, and it does HMR out | of the box to boot. But so what? There's a bunch of | streamlined devexp setups out there, from Svelte to Next.js | to vite-* boilerplates. To me, deno is just another option in | that sea of streamlined DX options, but it isn't (yet) | compatible with much of the larger JS ecosystem. </two-cents> | onelovetwo wrote: | > I wouldnt say an iframe and this are in any way shape or | form comparable. this is a "full-fledged" website. | | This is what's called an "analogy". | | But your other points are valid. | thunderbong wrote: | I don't think most of the people commenting here realize that the | entire site loads just fine with Javascript disabled. Essentially | this is HTML getting generated on the server. | | The fact that it is in Deno rather than PHP, Ruby or Python is | the point of the article. | abracadaniel wrote: | Thank you. Being unfamiliar with Deno, I was trying to figure | out what was loading the libraries when there was only one | request/response over the wire. I of course was making the | assumption that the single JS file was being run in the | browser, not on the server. | bachmeier wrote: | > Essentially this is HTML getting generated on the server. | | Not a web developer. How is this different from CGI or a | regular web server? This an honest question - I don't | understand the significance. | xcambar wrote: | it is not different. | | CGI is replaced by JS | | Apache/nginx is replaced by CDN | | web server is replaced by edge nodes (aka, glorified runtimes | automagically spread across many endpoints) | skybrian wrote: | Yes, everything old is new again. I just browsed the docs, | but it seems it's not so different, other than it's | automatically run on servers all over the world. Temporarily, | this is for free. Also, it automatically updates after | pushing a commit to GitHub, which seems nice. | xcambar wrote: | > Also, it automatically updates after pushing a commit to | GitHub, which seems nice. | | also not new, but you know that already :) | [deleted] | Dangeranger wrote: | Since a bunch of people are setting up a straw-man to criticize | this post for "not just serving plain HTML" I'll share my | opinions on this. | | Almost nobody is going to use Deno to serve a basic HTML site | with less than a dozen pages, they are going to use it to build a | monolith application to get content from a database, or a | service, then generate server-rendered pages, and also host an | API from the same codebase, or something similar. | | Setting up a monolith application means using something like | Ruby-on-Rails, Django, Spring, ASP.net, or rolling your own with | a Node.js backend serving a SSR front-end, or hydrating React | views. | | If you haven't experienced this already, you will come away with | one of two conclusions. | | 1. Wow, this is so much fun, as long as I stay on the happy path | of ... Rails ... Django ... ASP.net. | | 2. Wow, setting up all these moving parts really sucks' I'm | mostly writing configuration files, and then Googling the error | messages when I inevitably screw something up. | | What I think Deno is trying to do is make the process of getting | a server side rendered application with modern tooling running | with minimal ceremony, while still enabling the developer to | customize the system and build things that are not covered by the | documentation guides. In addition, their solution is one that can | be more easily hosted on edge servers than most other options out | there. | | I'm glad they are doing it, because it's a sorely lacking area of | modern web development. They only other people who are taking | this on in a meaningful way that I am aware of are Remix. I would | be happy for there to be more entrants into this field. | | Best of luck to everyone out there. | chrisco255 wrote: | There is no need to manually set up your own Node.js SSR | framework for React. Next.js exists, and is quite mature at | this point. Next.js is quite fun. Highly recommend it. | | The novel thing, for this, in my mind, is the edge hosting. | giantrobot wrote: | > Almost nobody is going to use Deno to serve a basic HTML site | with less than a dozen pages, | | Assumes facts not in evidence. People are already building | JavaScript monstrosities to serve entirely static blog content. | ramesh31 wrote: | >People are already building JavaScript monstrosities to | serve entirely static blog content. | | I think we just have to accept that that's how websites are | built now. It drove me nuts for a while, too. But modern JS | engines are blindingly fast, and 2-3mb of JS download (that | will be cached aggressively) is a non-issue for the vast | majority of users. | | I started talking to a junior developer the other day about | server side rendering in the days of Rails/PHP/etc. and he | looked at me like I was crazy. Couldn't even grasp the | concept. I think for better or worse this is where we are | headed. | Dangeranger wrote: | I would like to see web apps move in the direction of | server-side rendered static pages on initial load, and then | progressively hydrate the app with data from the back-end | on demand. | | Rails does this surprisingly well using Stimulus with web | sockets to mediate the exchange of events and data between | the client and server layers. | | Similar strategies are used in Phoenix Live View apps. | | Load static markup and data -> request more data if you | need -> send events and data to the server -> respond with | the new state to display if different than the client's | version. | MuffinFlavored wrote: | > monstrosities | | why do you have to sprinkle that snark + negativity in there? | it implies a toxic role of "you are superior" and "people who | use JavaScript to serve static blog content" are inferior. | | why can't we all just get along? especially in this tight- | knit programming community that is supposed to be full of | love and collaboration. in today's modern day of inclusion | and emphasis on mental health, you're spreading hate towards | people who use JavaScript to serve static blog content and | talking down to them. not every 2022 of you, in my opinion. | | let's work to get rid of the culture where you imply somebody | else's code project doesn't meet your standards, and that | since they wrote it, they are dumber than you for making poor | design decisions in your opinion. | FpUser wrote: | >"tight-knit programming community that is supposed to be | full of love and collaboration." | | Now you owe me a coffee and a monitor. | epolanski wrote: | While I don't like as well the tone of previous poster, I | think that any field should have a healthy dose of | "elitism" and "competition" and the previous user is right. | Dangeranger wrote: | Perhaps, but if your goal is to turn a pile of | markdown/aciidoc/rst files into a blog, there are better and | more purpose built tools for that. i.e. Jekyll, Hugo, Gatsby, | 11ty. | neogodless wrote: | In Firefox 98.0.2 / Windows 10, at the playground, the URL does | not reflect the route, and refreshing will display the hidden but | currently selected route, rather than the URL route. | | https://imgur.com/a/ZP95YcD | edent wrote: | > rendered dynamically, just in time, at the edge, close to the | user. | | HTML. You're serving HTML. | | Doesn't really matter that the server-side language is JS, PHP, | or BASIC. | chrisshroba wrote: | It matters to me as a developer who would choose a hosting | environment based on my familiarity with the language I have to | write in. | AaronO wrote: | Aaron from Deno here. Of course it's producing HTML as an | output, but the point is that you can use JSX and familiar | technologies like tailwind to dynamically generate that HTML at | edge vs client side. | | And unlike a pure static site, you can add API or form routes | donohoe wrote: | Oh. So you've reinvented PHP. Nice. | woojoo666 wrote: | Wow toxic much? PHP doesn't solve the same problems as JSX | lowwave wrote: | es6 is much more pleasurable to code than PHP. Check Little | Javascripter [0] | | [0] https://www.crockford.com/little.html | Dangeranger wrote: | This is a very lazy comment. I'm sure it makes you feel | smart, but it drags down the entire conversation, and | doesn't add anything of value. You seem very capable and | accomplished, so I'm confused why you would spend any of | your time to simply shit-post on someone who is trying to | build something of use to many people. | smm11 wrote: | zamadatix wrote: | Is there a particular advantage to how this is done here with | Deno or is this just an example of server side rendering being | possible in Deno? The latter is fine as I'm a fan of Deno :) just | missing why it's such a popular post (maybe more Deno fans?) | AaronO wrote: | It was mainly intended to be a "cute" example of the latter. | | Technically if you were doing this in Node, you would need at | least a package.json and would have to configure your TS/JSX | transpile, etc... | dmitrygr wrote: | "time to interactive: 1.0s / first content paint 1.0s" | | My man, let me introduce you to ... HTML. It has "time to | interactive" at 0.0 seconds and content paints instantly! | TheCoelacanth wrote: | No, not even remotely accurate. | | The browser still has to fetch and render the HTML. JS-heavy | sites do tend to be slower, but no site has a 0s TTI/FCP. | suprfsat wrote: | Report a bug in Lighthouse then. | e12e wrote: | I think it's actually much worse than that - it's a little | tricky to tell on mobile, but going from "stats" to "bagle" and | back again - looks like this mucks up the client side cache? | While one whole second is "90s slow" for a first render for a | static site - it's truly ludicrous for navigating back to an | already cached page? | | How are the cache control headers with this set-up - is there a | varnish or similar cdn/cache doing useful work (I'm assuming | not, more importantly I'm worried pointing something like | fastly at this will fail in caching static pages?). | zamadatix wrote: | The request headers have no-cache set. I assume this is | because it's in a live developer playground page instead of a | production deployment. | e12e wrote: | > I assume this is because it's in a live developer | playground page instead of a production deployment. | | Not how I read it - the first link is to a site deployed | via "deno deploy", the last one is a link to the same | content in a playground. | | >> Hosted on Deno Deploy, this little website is able to | acheive a perfect pagespeed score. Serviced from an anycast | IP address over encrypted HTTP from 29 data centers around | the world, the site is fully managed and will be available | indefinitely at zero cost. | | >> Everything mentioned here can be viewed on a playground. | | For what it's worth, the deployed site seems a little | snappier to me now on mobile - maybe I'm just less grumpy | after dinner... | e12e wrote: | Still, that's quite different from live editing static | files on disk - then you'd normally get cache and | invalidation (if-modified-since/304 etc). | lucacasonato wrote: | I think you might have misunderstood the blog post. It is | server-side rendering on the edge, shipping nothing more than | plain HTML/CSS to the browser. There is no client side JS *at | all* here. | ajcp wrote: | I understand the blog post, and the capability itself is | neat, but I'm having a hard time understanding the utility in | what they are showcasing from the actual example site[0]. | | As other posters have pointed out, why not do it in HTML from | the start? It's more simple and efficient than this -or any- | framework. Just drop the ol HTML file on your server and away | you go! | | I understand that the supposed "real" utility in this would | be when you want to do JS-y things in HTML (auth, API, hand | state, etc), but they don't show any of that on their | showcase site...so...yeah. | | 0. https://website-in-a-single-js.deno.dev/ | AaronO wrote: | I agree we could have elaborated on auth, API endpoints or | parametric routes (maybe a follow up !). | | But this example does showcase a few things you don't | typically get with a single vanilla HTML file: | | - JSX + reusable/shared components | | - Multiple URLs / pages | | - Tailwind | e12e wrote: | I actually think this is quite neat, but I am a bit | worried about caching. | | Someone mentioned rails, and rails have a lot of | facilities to set correct cache headers for assets (css, | js, images etc) _and_ for dynamic content (for logged | user in and /or for pages that are dynamic but public). | | If you're deploying static files via a vanilla web | server, you also get a lot of that for free, via the file | meta-data. | | I would expect a framework for publishing sites to | showcase a minimum of good caching (client cache, ability | to interact with a caching reverse proxy like varnish - | and/or a cdn). | ajcp wrote: | I get that after reading your blog post, so that's fair. | Maybe it's just a case of the magic trick that's missing | that third act. | | Clicking around with the Dev Console open and watching | the pages in Sources was enjoyable. | dmitrygr wrote: | The shown page could be served on 0.01 seconds if it | was...html. Or, if you MUST lob complexity at it, use a | static site generator... that generates...HTML | suprfsat wrote: | The demo is literally a static site generator that | generates HTML | andruc wrote: | You can see for yourself with the provided Pagespeed | metrics that the root document was served in around 30ms | (corresponding to TTFB). | | If you can elaborate on how statically-served HTML would | render orders of magnitude faster than server-sider- | rendered HTML with a similar response time, I'd love to | hear it. | dmitrygr wrote: | Unless the server runs at negative cycles per second, | more cycles means more time taken. Did i miss-math? | zamadatix wrote: | You've shown a way to add multiples of ~0.0000000003 | seconds to the time but haven't explained how the page is | going to go from .01 seconds to 1.0 seconds as a result | when TTFB is 0.03 seconds. | frosted-flakes wrote: | The shown page is HTML. It's a plain-old website that works | the same way websites have always worked: the page is | generated at request time, and HTML is served directly to | the client. It's not technically a "static" site because | the HTML is not cached ahead of time, but apart from the | fact that the whole back-end is a single JS file, there's | nothing special here. | zamadatix wrote: | Try playing around with the pagespeed link provided in the | article. You can see that in the default view the network | is set to slow 4G throttling with an RTT of 150 ms so it's | going to be impossible to get times like 0.01 seconds. Even | just loading https://x.com, a site that literally serves a | single character of content "x", gets 0.8 seconds. | tmp_anon_22 wrote: | This starts to make sense when you consider the self-flagellation | of a full server-side-rendering production setup that has existed | over the past decade, to the point many SPA products completely | give up on SSR - or nowadays throw themselves at the walled | garden of Vercel/Next.js etc to solve it for them. | n42 wrote: | I am not a fan of Vercel's strategy, but exactly how is the | open source and MIT licensed Next.js a walled garden? | colejohnson66 wrote: | It's not. Next.js works on any platform supporting Node, and | Vercel supports more than just Next.js. They support _dozens_ | of other frameworks.[0] They do promote Next.js on Vercel, | but they don 't stop you from using other systems. | | [0]: https://vercel.com/new/templates | sillysaurusx wrote: | Ever since Vercel killed `now`'s ability to serve an | index.html with `now .`, I stopped being a fan. That and | the pricing blunders have unfortunately pushed me away. | | On the other hand, https://docs.ycombinator.lol/ has been | running for years without me ever having to worry once, so | there's that. Maybe it's time to give them another try. | Rauchg wrote: | That never stopped working. Neither on the edge side (as | your live site indicates, which has been edge cached for | 109 days in San Francisco), or on the deployment site, as | the example below shows: | | Try it out: https://hi-there.vercel.app ^ | /tmp/ mkdir hi-there ^ /tmp/ cd hi-there ^ | hi-there/ echo '<h1>hi sillysaurusx</h1>' > index.html | ^ hi-there/ vc [...] Inspect: | https://vercel.com/rauchg/hi-there [690ms] | Production: https://hi-there.vercel.app [copied to | clipboard] [9s] | | In under 10s which includes the project setup and linking | prompts. The main difference is that `now` got shorter to | `vc` | | Happy to hear more feedback on pricing. Please reach out | to rauchg@vercel.com | sillysaurusx wrote: | Happy to hear that. It did, at one point -- I am quite | certain of this -- but that was years ago. | | I think it was in the transition between now and vercel. | Back then, `now` had some sort of requirement where it | only worked automatically if the folder had a | package.json file. A plain index.html file required | configuration. Delighted to see that this is no longer | the case. | | I'll give `vc` a shot. | | The pricing issues stemmed from the fact that I use | updown.io to monitor my domains. Since it pings them | every 15 minutes or so, and since vercel spins up servers | on demand, that means I was paying for essentially 24/7 | service, which was an unwelcome bill over what I signed | up for. Customer support gave a 50% refund, which I | appreciated, and I've downgraded to a free account ever | since. | grayrest wrote: | There's plenty of non-Vercel attempts at this and it's kind of | table stakes for frameworks hoping to get popular. There is a | push for server-first/MPA app development where SSR is assumed | to be the baseline. Remix [1], Qwik [2], and Marko [3] are in | that camp. I'm not sure about Remix but the other two have a | goal of authoring the entire app components but only sending | the JS needed for the parts that can change on the client. | | [1] https://remix.run/ [2] https://github.com/BuilderIO/qwik | [3] https://markojs.com/ | mavbo wrote: | This is great, I'm not sure why this is being misinterpreted so | much. Serving generated HTML from Node using Express many years | ago was also great at the time. You can still do that, but in my | experience the tooling is quite dated/fragmented and the | ecosystem+language has evolved significantly since then. | Nowadays, SSR+Node generally refers to front-end frameworks with | SSR capabilities (Next, Nuxt, SvelteKit, etc.) or generation of | static files. Building a dynamically server side rendered site | using TypeScript+JSX but without the issues of client side | frameworks, hydration, SPA routing, etc. sounds revolutionary, | even though it shouldn't(?) ___________________________________________________________________ (page generated 2022-04-06 23:00 UTC)