spiffytech

Wherein I ponder and opine. YMMV.

Dokku has a Let's Encrypt plugin which works behind Cloudflare. There's just a little bit of chicken-and-egg setup involved.

Let's Encrypt needs to connect back to your server to validate ownership of your domain. You can't have Cloudflare's “full” TLS mode enabled when you're doing first-time validation, because in “full” mode Cloudflare will error out, failing to establish a TLS connection to your not-yet-TLS backend server.

You could disable “full (strict)” TLS mode in Cloudflare, but then you'll take all your sites down: Dokku does HTTP –> HTTPS redirects on all sites configured with TLS, and will thus reject the non-TLS inbound connections from Cloudflare's networks. Or more accurately, it'll receive an inbound HTTP request from Cloudflare's servers, return a redirect to HTTPS, which Cloudflare will pass on to the client, but the client is already at an HTTPS URL, so the client will enter an infinite redirect loop.

You can get around all this during first-time setup by disabling Cloudflare's proxying behavior on your domain while you get Let's Encrypt set up on Dokku. After it's set up, you can turn Cloudflare proxying on, and cert renewals should work fine, since Let's Encrypt validation checks routed through Cloudflare can still establish end-to-end TLS while your certs remain valid.

While at work I was upgrading graphql-code-generator, and found that the generated code no longer exports the type for a query node. Instead, the type of the whole query response was exported. But I had code that relied on having the node type available.

To solve this, I created a new type by reading attributes from deep in the response type.

interface Foo {
    bar: {
        baz: {
            zap: {
                zoop: number;
            }[];
        };
    };
}

type zoop = Foo['bar']['baz']['zap'][number]['zoop'];

If some of your properties are optional, you can use Required<T>. If they're possibly undefined, use Exclude<T, undefined>.

Recently, while building a simple Reddit clone, I wanted to lazy-load images and comments. That is, rather that loading all of the images and comments the instant I added a component to the DOM, I wanted to wait until the component was actually visible. This spreads out the impact of loading a page, both for the client and the server.

Read more...

I needed to create a bottom nav (like what's used in many mobile apps) in CSS. Here's how I did it.

Read more...

What are Sapper and Netlify CMS?

Sapper

Sapper is Svelte's answer to Next.js/Nuxt.js. It's a way of rendering Svelte code on the server so your site is compatible with JavaScript-free devices, and so it renders immediately instead of waiting for a JS blob to download, parse, and run.

Sapper ordinarily runs as a full server application, but using the sapper export command we can generate a static version of our site that we can host on Github Pages or, in this case, Netlify. That's a great way to have a very fast site that's free for small-to-medium traffic numbers.

Netlify CMS

Netlify CMS is as open-source content management system, meaning it's a way to create blog posts and web pages through a web page. Since it's from Netlify, the static site host, it's designed to work with static site generators like Hugo and Jekyll. We'll be adapting it to work with Sapper.

Read more...

I've been working on a project that uses GraphQL via Hasura. Using Subscriptions (real-time updates to queries) is a key feature for my project, but it's one that most of the simpler GraphQL client libraries don't support. That leaves me looking at heavyweight tools Apollo. Apollo is pretty complicated to configure (I'm paying for a lot of features I don't use), and it _strongly_ steers you towards React hooks for accessing data; I had to dig pretty hard to find the documentation for their language-agnostic client library. I've really come to believe data fetches shouldn't be represented declaratively, at least not the way React hooks handles it. The ergonomics are poor and the flexibility is low every time I try it.

So I went looking for a GraphQL client that could handle GraphQL subscriptions, which was simple to set up and worked great when used imperatively.

Read more...

Here is a minimal router for Svelte v3 using Page.js.

Whenever the route changes, Page.js sets a variable that holds the component that should be rendered for the route.

<script>
  import page from 'page';

  import Home from './views/Home.svelte';

  let route;
  let routeParams;

  function setRoute(r) {
    return function({ params }) {
      route = r;
      routeParams = params;
    };
  }

  page("/", setRoute(Home));
  page({ hashbang: true });
</script>

<svelte:component this={route} bind:params={routeParams} />