[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)