Today I Learned

Returning errors and data in a single graphql request

graphql,error-reporting

This is more of a reminder for myself than a TIL. In a graphql resolver, we can return data, null or an error.

If the queried field is null-able, we can return an error from the resolver for that field which will then show up in the errors property of the response and the response.data.<field> will be null.

For example —

// schema
type Query {
  random: Int!
  currentUser: User
}

type User {
  id: ID!
  email: String!
}

// resolvers (JS)
{
  Query: {
    random: () => Math.trunc(Math.random() * 10),
    currentUser: () => {
      return new Error('nope')
    }
  }
    
}

// query
query {
  random
  currentUser {
    id
    email
  }
}

// response
{
  "errors": [
    {
      "message": "nope",
      "locations": [
        {
          "line": 3,
          "column": 3
        }
      ],
      "path": [
        "currentUser"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": []
        }
      }
    }
  ],
  "data": {
    "random": 9,
    "currentUser": null
  }
}

If the queried field is non-nullable (with the ! symbol) in the schema, then returning an error will cause response.data itself to be null as we are trying to return null for a non-nullable field. The response.errors array will contain the returned error but unfortunately it won't tell us that response.data itself is null because we tried to return null for a non-nullable field, causing stuff to explode.

For example — if we change the currentUser: User to currentUser:User! in the schema, we get the following response —

{
  "errors": [
    {
      "message": "nope",
      "locations": [
        {
          "line": 3,
          "column": 3
        }
      ],
      "path": [
        "currentUser"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [...]
        }
      }
    }
  ],
  "data": null
}

response.data is null even though we did return a value for the random field.

Read more: https://github.com/zeusdeux/my-graphql-playground/blob/main/src/devServer.js#L168

Created at: Tue Aug 25 2020 12:22:57 GMT+0000 (Coordinated Universal Time)

Target the first letter of every word using CSS

web,css

#TIL about the ::first-letter pseudo element that applies styles to the first letter of the first line of a block-level element, but only when not preceded by other content (such as images or inline tables).

It useful and supported across all browsers going back to IE9!

Read more: https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter

Created at: Wed Jun 24 2020 11:25:18 GMT+0000 (Coordinated Universal Time)

Want an easier way of discerning what key triggered the keyboard event in your web app?

web

#TIL that one can access the value of the key that triggered a KeyboardEvent by using the event's key property such as keyboardEvent.key === "Enter" or keyboardEvent.key === "Meta". The browsers also make these names OS agnostic. For example, Meta is the windows key on windows PCs or the command key on Macs.

This can make adding some basic a11y to your fake buttons for example.

<div>
  {data.map(({ name, color }, i) => {
    const checked = currentColor === color

    return (
      <div
        key={i}
        onClick={doSomething}
        // a11y
        tabIndex={0}
        role="radio"
        onKeyDown={e => {
          if (e.key === "Enter" || e.key === " ") {
            setValue(name, color)
          }
        }}
        aria-checked={checked}
      >
        <input
          name={name}
          type="radio"
          value={color}
          checked={checked}
          readOnly
        />
        <div>
          <div></div>
        </div>
      </div>
    )
  })}
</div>

Here's a full list of key values.

Read more: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key

Created at: Wed Jun 24 2020 11:21:55 GMT+0000 (Coordinated Universal Time)

Handling an even on capture instead of bubble phase in React

react,javascript

This is going to be a tiny one — #TIL learnt about on<eventname>Capture which lets one add a handler for a the capture phase of <eventname>.

<button onClickCapture={() => console.log('triggered during capture phase!')}>Click me!</button>

Read more: https://reactjs.org/docs/events.html#supported-events

Created at: Wed Jun 24 2020 11:07:05 GMT+0000 (Coordinated Universal Time)

Wanna wreck your terminal for the lulz?

bash,readline,terminal

This is not really a TIL. I was fooling around in my ~/.inputrc to see what I could make readline(3) do in service of silly pranks.

Here's the simplest one I came up with —

echo 'RETURN: "\d"' >> ~/.inputrc
bash # or Control-X Control-r to reload ~/.inputrc
# try executing a command now 😂

This uses the key bindings feature of readline(3) to remap your enter or return key to delete. This tiny change renders your terminal unusable until you either remove that line from your ~/.inputrc or open your shell with readline support disabled (--noediting flag for bash).

Sometimes you just gotta have fun 🤷🏻‍♂️

EDIT: Here's one for free — echo alias {=} >> ~/.<shell>rc (e.g., .bashrc) and watch things go crazy 🙃

Read more: https://linux.die.net/man/3/readline

Created at: Sun Jun 14 2020 21:55:05 GMT+0000 (Coordinated Universal Time)

Developing a Deno project in Emacs

emacs,typescript,deno

So, I have been wanting to play with Deno ever since it hit 1.0. The lack of editor support for Emacs is what kept me at bay.

While I was researching how to get Deno to work with me editor of choice, I landed upon typescript-deno-plugin which is what the official Visual Studio Code Deno extension uses internally. Armed with this, I quickly popped over to the tide repo and opened an issue. Anantha was ridiculously fast to respond and suggested that I install the typescript-deno-plugin, set it up and see if it works as-is with tide.

So I did that and guess what, it Just Works™️!

Here's a working example.

Read more: https://github.com/zeusdeux/deno-emacs-test

Created at: Thu May 28 2020 19:11:32 GMT+0000 (Coordinated Universal Time)

So you want project specific checker/linter chain using flycheck in Emacs?

emacs

#TIL that one can evaluate forms in .dir-locals.el using eval. When combined with funcall this can let us execute a custom lambda when Emacs finds a .dir-locals.el in the directory tree of the current file.

First off, .dir-locals.el is one way of defining directory tree specific values for variables. Therefore, it can be used to define values for variables such as prettier-js-command, compile, etc for a project by placing a .dir-locals.el file in the root of your project.

I wanted to use this to make sure that I enabled the css-stylelint linter for only one work project. I didn't want flycheck to execute that linter on any files outside of that one work project.

To do so, I combined the buffer local variables strategy as described in my previous TIL in combination with .dir-locals.el, eval and funcall.

Initial setup

To achieve this, in my emacs init file, I first instructed flycheck to add css-stylelint checker to typescript-mode and js-mode.

(flycheck-add-mode 'css-stylelint 'typescript-mode)
(flycheck-add-mode 'css-stylelint 'js-mode)

I then chained css-stylelint after typescript-tide and javascript-eslint.

(flycheck-add-next-checker 'typescript-tide 'css-stylelint)
(flycheck-add-next-checker 'javascript-eslint 'css-stylelint)

Following that, I decided to disable the css-stylelint checker by default so that it can be enabled on a per project basis. To do so, I first checked if css-stylelint is already in flycheck-disabled-checkers. If not, I first push css-stylelint into flycheck-disabled-checkers and I make the return value of that call the default value of flycheck-disabled-checkers.

(unless (memq 'css-stylelint flycheck-disabled-checkers)
  (setq-default flycheck-disabled-checkers (push 'css-stylelint flycheck-disabled-checkers)))

With this is place, all I have to do is make flycheck-disabled-checkers buffer local so that any project can override it. And the ones that don't will have css-stylelint checker disabled.

(make-variable-buffer-local 'flycheck-disabled-checkers)

Project specific checker toggle

In the root of my work project, I added an empty .dir-locals.el.

In here, what I wanted to do was renable the css-stylelint checker as this codebase uses it. To do so, I combined eval pseudovariable and funcall which calls a function with given args and returns the called function's returned value (same as Function.prototype.call in JavaScript for example). These two in combination with a lambda are enough to do literally anything! Below is the resulting code which says, when typescript-mode is enabled for a file in this project, enable css-stylelint in that file as a checker for that mode using flycheck.

((typescript-mode . ((eval . (funcall (lambda ()
                                        (message "Enabling css-stylelint")
                                        (when (memq 'css-stylelint flycheck-disabled-checkers)
                                          (setq flycheck-disabled-checkers
                                                (remq 'css-stylelint flycheck-disabled-checkers)))
                                        (when (memq 'css-stylelint flycheck--automatically-disabled-checkers)
                                          (setq flycheck--automatically-disabled-checkers
                                                (remq 'css-stylelint flycheck--automatically-disabled-checkers)))))))))

And just like that, we get the right setup for our project without infecting our global setup.

Linked to "Read more" is the answer that set me down the path that helped me discover this solution for my usecase.

Read more: https://emacs.stackexchange.com/questions/21955/calling-functions-in-dir-locals-in-emacs

Created at: Thu May 28 2020 18:37:59 GMT+0000 (Coordinated Universal Time)

Making variables buffer local by default in Emacs

emacs

#TIL of a function called make-variable-buffer-local in Emacs that lets us mark a variable as buffer local such that any subsequent attempt to set the variable will make it local to the current buffer at the time. This is extremely useful for project specific variables such as prettier-js-command, disable a flycheck checker for a project by making flycheck-disabled-checkers buffer local, etc.

This works especially well with setq-default which sets the default value of a buffer local variable. This default value is used when a buffer local value for the variable is not provided.

Example:

press C-x C-e at the end of each line to execute in a elisp-mode buffer such as scratch

;; in buffer 1
(defvar var-1 'a)
(make-variable-buffer-local 'var-1)
(message "var-1 in buffer 1 is %s" var-1) ;; "var-1 in buffer 1 is a"
(setq var-1 'b)
(message "var-1 in buffer 1 is %s" var-1) ;; "var-1 in buffer 1 is b"

;; in buffer 2
(message "var-1 in buffer 2 is %s" var-1) ;; "var-1 in buffer 2 is a"

;; back to buffer 1
(setq-default var-1 'omg)
(message "var-1 in buffer 1 is %s" var-1) ;; "var-1 in buffer 1 is b"

;; back in buffer 2
(message "var-1 in buffer 2 is %s" var-1) ;; "var-1 in buffer 2 is omg"
(setq var-1 'new-value)
(message "var-1 in buffer 2 is %s" var-1) ;; "var-1 in buffer 2 is new-value"

;; finally, back in buffer 1 the value of var-1 remains unchanged
(message "var-1 in buffer 1 is %s" var-1) ;; "var-1 in buffer 1 is b"

Read more: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Buffer_002dLocal.html#Creating-Buffer_002dLocal

Created at: Thu May 28 2020 18:13:19 GMT+0000 (Coordinated Universal Time)

Custom git subcommands

git

#TIL that one can add their own git subcommands in a fairly easy manner.

It is as easy as making an executable that prefixed with git-<your cmd name> and placing it somewhere in your $PATH. git will automagically pick it up and use it when you call git <your cmd name> ... and pass the arguments to it!

Hot dang that's 🔥!

Read more: https://blog.sebastian-daschner.com/entries/custom-git-subcommands

Created at: Wed May 20 2020 13:01:57 GMT+0000 (Coordinated Universal Time)

New `lh` CSS unit!

css

#TIL that CSS now has lh units. 1lh is equivalent to total computed line height. So you can size something according to the text it sits next to!

Read more: https://css-tricks.com/lh-and-rlh-units/

Created at: Tue May 19 2020 11:44:47 GMT+0000 (Coordinated Universal Time)

Directory local variables in emacs and *risky* variables whitelisting

emacs

#TIL of a nicer way to whitelist local variables that emacs considers risky.

Why does emacs consider them as risky? Well because in emacs, variables can contain expressions that are evaluated and these expressions can contain arbitrary code which can be malicious. Or, some variables (e.g., load-path) can change where packages, etc are loaded from and that can effectively give a malicious user full access to your emacs instance and potentially call into your OS. Scary stuff! 👻

Anyway, I ran into this when using .dir-locals.el to define a custom value for prettier-js-command variable. This variable was marked as risky by emacs which meant that whenever I opened a buffer that used this variable, emacs would prompt me asking if I really want to update the value of this variable to what's specified in my .dir-locals.el. While this is well intentioned, it was kinda annoying.

To override it, I initally looked at safe-local-variable-values but that wouldn't work since I didn't know the value of prettier-js-command upfront. I mean, that's why I used a .dir-locals.el to define it for the tree rooted at the dir that contained my .dir-locals.el. I wanted to instead only enforce that the value of prettier-js-command, if a string, then don't mark it as risky.

I was made aware of safe-local-variable by this answer on stackoverflow. To make it work, I added the following to my init file and I was off to races!

(put 'prettier-js-command 'safe-local-variable #'stringp)

Read more: https://emacs.stackexchange.com/a/18785/5403

Created at: Tue May 19 2020 11:38:24 GMT+0000 (Coordinated Universal Time)

Have a function with properties on it in TypeScript? Function types to the rescue!

typescript

#TIL about function types in TypeScript! It's a fancy word for an interface that has a call signature.

For e.g.,

const computeNthFibonacciNumber: MemoizedFn = (n: number) => {
  computeNthFibonacciNumber.memo = computeNthFibonacciNumber.memo[n] ?? []
  
  if (typeof computeNthFibonacciNumber.memo[n] === 'number') {
    return computeNthFibonacciNumber.memo[n]
  }
  ...
  // calculate expensive result
  ...
  
  // memoize the result
  computeNthFibonacciNumber.memo[n] = result
  return result
}

interface MemoizedFn {
  (n: number): number
  memo?: number[]
}

Here computeNthFibonacciNumber.memo now has the type number[] | undefined. It's marked as an optional as we define memo in the body of the function. If memo wasn't marked as optional, we'd have to define to after the function expression as shown below —

const computeNthFibonacciNumber: MemoizedFn = (n: number) => {
  computeNthFibonacciNumber.memo = computeNthFibonacciNumber.memo[n] ?? []
  
  if (typeof computeNthFibonacciNumber.memo[n] === 'number') {
    return computeNthFibonacciNumber.memo[n]
  }
  ...
  // calculate expensive result
  ...
  
  // memoize the result
  computeNthFibonacciNumber.memo[n] = result
  return result
}
computeNthFibonacciNumber.memo = [0, 1] // first to numbers in the sequence

interface MemoizedFn {
  (n: number): number
  memo: number[]
}

This is the same pattern React.FC type uses.

Read more: https://www.typescriptlang.org/docs/handbook/interfaces.html#function-types

Created at: Thu Mar 26 2020 18:59:56 GMT+0000 (Coordinated Universal Time)

Removing Exif data from images

terminal,images,exif

#TIL that the wonderful ImageMagickthe image handling swiss army knife — ships with mogrify which can be used to remove Exif data from images.

Why remove Exif data? Short answer — privacy.

To use mogrify to remove Exif data from an image, first install imagemagick and then run the following incantation in your terminal —

mogrify -strip original.jpg

This will remove Exif data from original.jpg and save the modified file under the same name i.e., original.jpg in the case of this example.

Read more: https://superuser.com/questions/335489/how-to-strip-exif-info-from-files-in-osx-with-batch-or-command-line/335504#335504

Created at: Mon Mar 23 2020 13:06:00 GMT+0000 (Coordinated Universal Time)

Package entry points in node

javascript,node

#TIL that package entry points can be specified in another way other than the "main" property in package.json. It is the "exports" property.

Not only does it let you re-map entrypoints into your package —

// ./node_modules/es-module-package/package.json
{
  "exports": {
    "./features/": "./src/features/"
  }
}

// otherFile.js
import feature from 'es-module-package/features/x.js';
// Loads ./node_modules/es-module-package/src/features/x.js

it also lets you allow for conditional exports using the "import" and "browser" sub keys —

// ./node_modules/pkg/package.json
{
  "type": "module",
  "main": "./index.js",
  "exports": {
    "./feature": {
      "import": "./feature-default.js",
      "browser": "./feature-browser.js"
    }
  }
}
  • "default" - the generic fallback that will always match. Can be a CommonJS or ES module file.
  • "import" - matched when the package is loaded via import or import(). Can be any module format, this field does not set the type interpretation.
  • "node" - matched for any Node.js environment. Can be a CommonJS or ES module file.
  • "require" - matched when the package is loaded via require().

This can be seen used quite well in preact

Note that "." export will define the main entrypoint for your package and will take precedence over the "main" property.

Read more on this using the link below as it has a lot of other use-cases that I haven't described here (such as fallback targets 😱)

Read more: https://nodejs.org/api/esm.html#esm_package_exports

Created at: Wed Mar 11 2020 17:26:59 GMT+0000 (Coordinated Universal Time)

Visualizing unicode tables

fonts,web

#TIL about a website that visualizes unicode tables.

I came across it while subsetting a font for my blog using the awesome Font Squirrel webfont generator's expert mode.

I wanted only the Basic Latin unicode table and to visualize the table, I ended up on https://unicode-table.com.

Just seconds later though, I realised that Font Squirrel itself shows the subset. Oh well 🤷🏻‍♂️

Read more: https://unicode-table.com/en/#spacing-modifier-letters

Created at: Sun Jan 19 2020 12:27:10 GMT+0000 (Coordinated Universal Time)

How to get a union of types contained within an object type in typescript?

typescript

#TIL I learnt about some more typescript-fu that lets us disjoin or blow up an object to get a union of objects that each have one key from the main object. My english prowess is failing me right now so let me show what I mean with an example.

Say we have the following type

interface Person {
  name: string
  age: number
}

Now say we want the type { name: string } | { age: number } from it. We can do so by defining a type that accepts the Person interface and "blows it up" into unions.

type Unionize<T extends object> = {
  [P in keyof T]: { [Q in P]: T[P] }
}[keyof T]

type Members = Unionize<Person> // type Members = { name: string } | { age: number }

Hot dang!

This and a lot more await you in the wonderful utility-types library by Piotrek Witek.

Read more: https://github.com/piotrwitek/utility-types/blob/master/src/mapped-types.ts#L360

Created at: Sat Jan 18 2020 18:02:48 GMT+0000 (Coordinated Universal Time)

SSR + react-spring - hooks

javascript,web,react,animation

#TIL that if you use one of the render prop methods from react-spring such as transition, it will render nothing when the react application is rendered on the server. I found this out the hard way when I noticed that the performance score for my TILs page had dropped from 95+ to anywhere between 29-45. Using react-spring with my SSR-ed app basically nullified the impact of server side rendering and converted it to a fully client side app in terms of behaviour.

Note to self: react-spring is awesome but be aware of its and any other library's inter-op with ReactDOMServer.renderToString. ☠️

Read more: https://github.com/react-spring/react-spring/issues/435

Created at: Sun Jan 12 2020 13:23:12 GMT+0000 (Coordinated Universal Time)

Sorting strings with help from the platform

web,javascript

#TIL about String.prototype.localeCompare() which is purpose built to help sorting a collection of strings!

e.g.,

const a = 'réservé'; // with accents, lowercase
const b = 'RESERVE'; // no accents, uppercase

console.log(a.localeCompare(b));
// expected output: 1
console.log(a.localeCompare(b, 'en', {sensitivity: 'base'}));
// expected output: 0

Read more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

Created at: Fri Jan 10 2020 12:34:43 GMT+0000 (Coordinated Universal Time)

Multiple fields in mutations in GraphQL

graphql,web

#TIL that a GraphQL mutation can contain multiple fields just like in a query. With one clear distinction though. While GraphQL queries run in parallel, mutations run serially in top down order.

For e.g., say we have the following request —

mutation {
  increment(by: 10)
  decrement(by: 5) {
    num
  }
}

In the above request, num will incremented by 10 first and then decremented by 5.

Read more: https://graphql.org/learn/queries/#multiple-fields-in-mutations

Created at: Thu Jan 09 2020 09:56:26 GMT+0000 (Coordinated Universal Time)

Working with query string of a URL

web,javascript

#TIL about URLSearchParams which gives developers methods to manipulate the query string of a URL. It can be initialized using any query string. For e.g.,

const queryParams = new URLSearchParams(document.location.search)
const queryParams = new URLSearchParams('q=web+platform')
// etc

We can then manipulate the query string using getter, setters, etc. For e.g.,

queryParams.set('q', 'someother non-URL safe character 😱')
queryParams.get('q', 'someother non-URL safe character 😱')
queryParams.getAll('repeated-query-param') // gets all the values associated with the given query parameter
// and many more

To get a URL safe string we can either use the returned object (queryParams) in a string context or call .toString() on it.

For e.g.,

const queryParams = new URLSearchParams('q=omg 😱')

window.history.pushState({}, '', `${document.location.origin}?${queryParams}`)

Read more: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

Created at: Tue Dec 31 2019 21:39:04 GMT+0000 (Coordinated Universal Time)

GraphQL subscriptions

graphql,javascript

#TIL that the values returned by the async iterator returned by subscribe function for a Subscription field, should return objects of the same shape as the field it is defined on.

Makes no sense right? Let's look at an example.

Let's say we have the following type definition.

const typeDefs = `
  type Subscription {
    getNumber: Int!
  }
`

Now, let's define an iterable that returns an async iterator. (Click here for more on iterators, generators, etc). We can do so by either making a plain object as shown on MDN or we can use the new async function * syntax.

Let's use the latter.

async function generateNumbers*() {
  let x = 1
  if (x < 5) {
    yield x++
  }
  return 5
}

Now let's define the resolver for our type definition using generateNumbers.

const typeDefs = `
  type Subscription {
    getNumber: Int!
  }
`
const resolvers = {
  Subscription: {
    getNumber: {
      subscribe: () => generateNumbers() // this call returns an async iterator generated from the iterable which GraphQL iterates on interally, takes the value when available and yields that as the value of the async iterator it itself returns for a subscription query
    }
  }
}

This setup, when used with a GraphQL server, doesn't work and even throws in certain implementations. That's because, the lack of a resolve function next to subscribe above is internally converted to the following as per the GraphQL spec.

const resolvers = {
  Subscription: {
    getNumber: {
      subscribe: () => generateNumbers(),
      resolve: (root) => root.getNumber // aka the default resolver in GraphQL which is used when no resolve function is provided
    }
  }
}

The error should now be clear. Our async iterator yields integers, instead of an object of shape { getNumber: Int! } as specified by the type definition. The values yielded by our async iterator as passed as the root value to the resolve function. This along with the default resolve function is what causes the error to occur as root value has no getNumber property.

The fix, therefore, is simple. We update generateNumbers to yield an object of that shape. All together, a working setup using a default resolve functionlooks like below.

const typeDefs = `
  type Subscription {
    getNumber: Int!
  }
`
const resolvers = {
  Subscription: {
    getNumber: {
      subscribe: () => generateNumbers()
    }
  }
}
async function generateNumbers*() {
  let x = 1
  if (x < 5) {
    yield {
      getNumber: x++
    }
  }
  return { getNumber: 5 }
}

This is what it looks like when used with apollo-server (the schema is generated by @zeusdeux/serverless-graphql.

gql subscription til

Notice that the output stops at 4 even though we finally return { getNumber: 5 }. This tells us that return value of the async iterator is discarded by GraphQL.

Finally, we can return anything from the async iterator and shape it how we want using its neighbouring resolve function as the value returned by the iterator is passed as the root value to its resolve sibling.

This means we can fix the same issue in a second way. The code below shows another approach to fix it using a custom resolve function next to the subscribe function.

const typeDefs = `
  type Subscription {
    getNumber: Int!
  }
`
const resolvers = {
  Subscription: {
    getNumber: {
      subscribe: () => generateNumbers(),
      // the root value is the number as returned by generateNumbers
      // when we return it as is, we get the overall shape of 
      // { getNumber: root (which is a number) } as the resolve
      // function is nested inside a field named getNumber.
      resolve: (root) => rootValue
  }
}
async function generateNumbers*() {
  let x = 1
  if (x < 5) {
    yield x++
  }
  return 5
}

Fin.

PS: The delay in the GIF is introduced synthetically by my code to show that values are indeed being subscribed to and emitted over time.

Read more: https://www.apollographql.com/docs/graphql-subscriptions/subscriptions-to-schema/

Created at: Mon Dec 30 2019 20:36:29 GMT+0000 (Coordinated Universal Time)

graphql/utilities is cooooool!

javascript,web,graphql

#TIL (well day before), I learnt about graphql/utilities which is a brilliant package for all low level GraphQL needs.

Specifically, I love its buildSchema function that takes a string type definition, parses it and returns a GraphQLSchema object. This is great as this object is supported by packages such as apollo-server.

This has been the core of my package, serverless-graphql which lets you execute GraphQL against any API without the needs of a graphql server in between.

Read more: https://graphql.org/graphql-js/utilities/

Created at: Sat Dec 28 2019 05:59:27 GMT+0000 (Coordinated Universal Time)

Leave certain imports as-is if you're authoring a JavaScript library

javascript,npm,web,node

#TIL that, when authoring a JavaScript library, leave certain imports as-is. Don't include their code in your final bundle as it can cause weird bugs if the consumers of your library also are dependent on one of your dependencies. This leaves the consumer's dependency tree with potentially many different version of the same package which can wreak havoc!

When I say certain, I mean certain. Things like lodash, etc are usually fine. But bundling up a framework (e.g., react, vue, etc) or lower level packages (e.g., graphql, etc) as a part of your library are a bad idea for reasons mentioned above.

As an alternative, declare those packages as peerDependencies!

Read more: https://github.com/zeusdeux/use-is-in-viewport/blob/master/package.json#L33-L35

Created at: Sat Dec 28 2019 05:56:27 GMT+0000 (Coordinated Universal Time)

Group commands in bash/zsh/etc for profit!

bash,npm

#TIL that one can group commands in bash and bash-like shells using {...}. This is very useful when used in things such as npm scripts to guard certain operations.

For example:

{
  ...
  "scripts": {
    "check-peer-deps": "[[ -d node_modules/graphql ]] || { echo 'Maybe install the peerDeps?'; echo; exit 1; }",
    "build": "npm run check-peer-deps && npm run build"  
  }
}

Read more: https://stackoverflow.com/a/3822649/1727349

Created at: Sat Dec 28 2019 05:32:55 GMT+0000 (Coordinated Universal Time)

npm link caveat

npm,node,javascript

#TIL about an interesting caveat of npm link due to how the node resolution algorithm works.

Say you have a library libA at path ~/libA and a project myApp that consumes libA at path ~/myApp. Now say that you want to test myApp with a local version of libA to see if things work fine before cutting a release or maybe even a beta/alpha.

One way you can do so is by cd-ing into ~/libA and running npm link. Following this you cd into ~/myApp and run npm link libA to (sym)link ~/myApp/node_modules/libA to your local ~/libA. You run myApp, it all works fine and you're a happy cat.

Now say libA has a peer dependency on graphql (or any package). This means that the consumer of your library must install graphql in their application. So we go into ~/myApp and run npm install graphql. Now you run the application as always but, oh no! myApp fails to run! The logs on the screen say that libA was looking for graphql but didn't find it!

We sit/stand/lie there, flabbergasted. I mean, we did everything right, no? We installed the graphql peer dependency in ~/myApp as instructed. So what gives?

Well, turns out, we got bit by a small lack of understanding on our part combined with the module resolution algorithm of your favourite bundler/node/what have you.

When we run npm link libA in ~/myApp, ~/myApp/node_modules/libA is (indirectly) symlinked to our local ~/libA. Now, when we run ~/myApp and the libA import/require is encountered, the file given by the main key in ~/libA/package.json is loaded. Say that it maps to ~/libA/dist/libA.umd.js. This file, in turn, tries to import/require graphql. To do so, node or your bundler, does the look up roughly as follows:

  1. Check if graphql is a core module. Nope, it isn't. Go to next step.
  2. Look for graphql in ~/libA/dist/node_modules. Found it? No? Ok, next step then.
  3. Look for graphql in ~/libA/node_modules. It isn't there either since it's a peer dependency and isn't automatically installed when we run npm install in ~/libA.

This process continues, one directory higher in the hierarchy at every step till it gives up and ends.

But, Mudit, why not just install the peer dependency in ~/libA using npm install graphql --no-save and move on with our lives? Well, that defeats the purpose Jimmy, that's why!

In anycase, you might have noticed that all the look ups are happening relative to ~/libA, not ~/myApp where we already did install graphql. This is due to the fact that npm link creates symbolic links! And that's the root cause, Jimmy! Due to the fact that npm link libA creates a symlink inside ~/myApp/node_modules (indirectly) to ~/libA, the module resolution algorithm (correctly) uses the real location of libA for the look up of graphql.

This had me scratching my head for a bit and hopefully it helps someone else out there.

Read more: https://nodejs.org/dist/latest-v12.x/docs/api/modules.html#modules_all_together

Created at: Sat Dec 28 2019 05:25:13 GMT+0000 (Coordinated Universal Time)

Want to grab a union from an object type in typescript?

typescript

As a part of working on a project, I needed a way of getting a union of all the values an object could have in typescript. Turns out there's a weird way to do so using infer and some other typescript voodoo.

To read how and to try it out, visit it on codepen.

Read more: https://github.com/zeusdeux/ts-playground/blob/master/gettingUnionFromObjectType.ts

Created at: Fri Oct 18 2019 12:18:58 GMT+0000 (Coordinated Universal Time)

Want to crash safari 13.0.x?

web,css,macos

#TIL that one can cause safari to hang and crash by styling a select box in a very specific manner.

The interaction of text-rendering: optimizeLegibility and -webkit-appearance: none on a select box causes Safari to hang up, beach ball and everything!

More in the codepen link!

Read more: https://codepen.io/zeusdeux/pen/NWKJzPJ

Created at: Thu Sep 26 2019 12:38:42 GMT+0000 (Coordinated Universal Time)

Generating n pseudo-random bytes using openssl

security,openssl

#TIL that one can generate n pseudo-random bytes and encoded it using any supported encoding scheme (e.g.,base64, hex, etc) using the mighty openssl cli!

For example, openssl rand -base64 64 will output a base64 encoded 64 pseudo-random bytes of data. But this usually contains newlines.

What if we want to use this to generate a password and don't want those newlines? Well, openssl cli to the rescue again! We can generate pseudo-random bytes and pipe it to openssl enc!

Example: openssl rand 64 | openssl enc -A -base64 where -A as per the man page is — If the -base64 option is set, then base64 process the data on one line

Read more: https://linux.die.net/man/1/sslrand

Created at: Wed Aug 28 2019 14:16:15 GMT+0000 (Coordinated Universal Time)

Internet Assigned Numbers Authority (IANA)

http,rfc,IANA

# TIL that one can find all the HTTP status codes and their corresponding normative sections in the RFCs they come from in the IANA registry! No more having to look at stackoverflow when confused while having to choose between a 400, 422 or a catch all 500 for example!

Here's a bonus — HTTP Method Registry

Read more: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

Created at: Tue Aug 20 2019 14:07:22 GMT+0000 (Coordinated Universal Time)

A tale of obsoleted RFCs

http,rfc

#TIL that RFC 2616 aka the one that defined HTTP/1.1 protocol was obsoleted by many as are listed in its first header section. One such RFC that made a part of RFC 2616 obsolete is RFC 7231 which updated some of the semantics of HTTP/1.1.

Read more: https://tools.ietf.org/html/rfc7231

Created at: Tue Aug 20 2019 14:05:13 GMT+0000 (Coordinated Universal Time)

Order of overrides in .eslintrc matter

javascript,tools

#TIL that if you have, for e.g., rule overrides for files that match src/**/*.js & src/folder/**/*.js, the order in which they appear in the config will determine the final rules for those globs.

Read more: https://gist.github.com/zeusdeux/31467d8c69602ac38859af0e39457255

Created at: Fri Jul 26 2019 14:05:33 GMT+0000 (Coordinated Universal Time)

Catastrophic backtracking in regular expressions

performance,regular-expressions

#TIL about Catastrophic backtracking in regexps that can potentially bring down your service as it happened in the case of Cloudfare. Be mindful of your repetition op usage!

Read more: https://www.regular-expressions.info/catastrophic.html

Created at: Mon Jul 15 2019 13:53:05 GMT+0000 (Coordinated Universal Time)

Set default apps in macOS with EASE!

software,tools,macos

#TIL about RCDefaultApp, a wonderful blast from the past! It adds a pane in the System Preferences app to set defaults for pretty much anything on macOS. brew cask install rcdefaultapp ftw!

Read more: https://apple.stackexchange.com/questions/261881/set-default-mail-client-without-adding-mail-account

Created at: Tue Jul 09 2019 09:16:30 GMT+0000 (Coordinated Universal Time)

Semigroups and monoids ftw!

category-theory,functional-programming

#TIL that any function of type a -> a is a monoid under function composition with the identity value of the identity function. I.e., given ∘ is fn composition, (f ∘ f) ∘ f = f ∘ (f ∘ f) and f ∘ id = id ∘ f where id is the identity fn: id(a) = a

Read more: https://twitter.com/muditameta/status/1137828272501399552?s=21

Created at: Sun Jun 09 2019 21:50:58 GMT+0000 (Coordinated Universal Time)

Create a docker container without starting it with docker-compose

docker

#TIL that you can create a docker container without starting it using docker-compose up --no-start <service name>. This is handy when all you really want to do is copy some artifacts from the built image onto the host filesystem (in CI or locally).

Read more: https://github.com/zeusdeux/docker-playground

Created at: Thu Mar 28 2019 11:24:21 GMT+0000 (Coordinated Universal Time)

Removing the passphrase from an RSA private key

docker,openssl

#TIL: Run openssl rsa -in locked.pem -out unlocked.pem to remove the passphrase from the input key! It's great for testing docker builds locally that require an ssh key for example. And yes, you'll be prompted for the passphrase when you run that cmd.

Read more: https://www.openssl.org/docs/manmaster/man1/rsa.html

Created at: Wed Mar 27 2019 22:15:09 GMT+0000 (Coordinated Universal Time)

docker-compose run

docker

#TIL that docker-compose run doesn't map the ports if your docker-compose.yml specifies a ports key. It's by design.

Read more: https://github.com/docker/compose/issues/1259

Created at: Wed Mar 27 2019 13:15:31 GMT+0000 (Coordinated Universal Time)

Variable fonts ftw!

web,css

#TIL about variable fonts which can declare attributes that can be manipulated by the user to change how the font looks when rendered! Try them on v-fonts!

Read more: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide

Created at: Sun Mar 03 2019 20:44:23 GMT+0000 (Coordinated Universal Time)

HideShow mode for code folding in emacs

javascript,emacs

#TIL about HideShow mode that's built into emacs as of Emacs 20. It enables syntactic hide/show of code blocks & supports many langs such as JS, C, Java, Lisps, Python, etc. Use: Enable hs-minor-mode in your buffer & then hit C-c @ C-c to toggle blocks

Read more: https://www.emacswiki.org/emacs/HideShow

Created at: Fri Mar 01 2019 14:27:06 GMT+0000 (Coordinated Universal Time)

LD_PRELOAD for profit!

c

#TIL about LD_PRELOAD env var that let's one load shared objects or libs before loading the C runtime lib. In essence, you can use it to provide your own definition of functions that override those provided by other libs. E.g., provide your own malloc.

Read more: https://jvns.ca/blog/2014/11/27/ld-preload-is-super-fun-and-easy/

Created at: Tue Jan 22 2019 11:40:50 GMT+0000 (Coordinated Universal Time)

Sum types with never in Typescript

functional-programming,typescript

#TIL that a sum type that has never resolves to a type that has no never in it. For e.g. let x: string | never // type -> string. This is the trick used to implement Exclude simply as type Exclude<T, U> = T extends U ? never : T! More in the link

Read more: https://bit.ly/2CPMbPo

Created at: Sat Jan 05 2019 17:37:42 GMT+0000 (Coordinated Universal Time)

Toggling hidden items in Finder

macos

#TIL that, as of macOS Sierra, you can toggle hidden files visibility in Finder by pressing CMD + Shift + .

No more executing defaults write ... in the terminal!

Read more: https://ianlunn.co.uk/articles/quickly-showhide-hidden-files-mac-os-x-mavericks/

Created at: Fri Jan 04 2019 15:38:33 GMT+0000 (Coordinated Universal Time)

Querying for face being used by character under cursor in emacs

emacs

#TIL that you get info about the char under the cursor in emacs by using the chord C-u C-x =. The prefix arg, C-u, is what gives the details & is a neat way to find out the face you need to modify to change how something (e.g., keyword) is displayed.

Read more: https://stackoverflow.com/a/22951243/1727349

Created at: Wed Jan 02 2019 23:37:35 GMT+0000 (Coordinated Universal Time)

Custom shell bindings that work everywhere*?

terminal,readline

#TIL that you can bind custom actions (fns, macros or strings) to custom keybindings by leveraging Readline and its init file, .inputrc. For e.g: "\ev": "code .\n" will open current folder in vscode when you press alt/option+v in your shell.

Read more: https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File-Syntax.html#Readline-Init-File-Syntax

Created at: Wed Jan 02 2019 22:28:41 GMT+0000 (Coordinated Universal Time)

Tired of typing out the same bit of data that you want to POST using curl?

curl,http

#TIL that one can get curl to read a file and POST its contents to the given URL by appending the file name with the @ character. For example:

curl -X POST -d @myfile.json -H 'Content-Type: application/json' https://foo.bar.in/baz

Read more: https://curl.haxx.se/docs/manpage.html#-d

Created at: Wed Jan 02 2019 22:13:38 GMT+0000 (Coordinated Universal Time)

Scroll two buffers together in emacs you say?

emacs

#TIL that you can scroll all your buffers in unison by enabling a built in minor mode called scroll-all-mode. My use case was to visually diff a file and its refactored counterpart. Invoking it again disables it & returns you to normal scroll behaviour.

Read more: https://stackoverflow.com/a/18092297

Created at: Wed Jan 02 2019 14:11:24 GMT+0000 (Coordinated Universal Time)

Express.js and named capture groups 🙅🏻‍♂️

javascript,web,regular-expressions,node

#TIL that Express.js (version 4.16.4 as of writing this) does not work with the new named regex capture groups in JS. It breaks with a confusing and weirdly un-googleable error. Not only that, you have to wrap the whole regex into a non-capturing group.

Read more: https://github.com/zeusdeux/til.mudit.xyz/blob/master/now-dev.js#L43

Created at: Thu Dec 27 2018 22:50:17 GMT+0000 (Coordinated Universal Time)

How to disable Sentry integration in dev?

javascript,node,error-reporting

#TIL learnt that to disable Sentry integration (in dev or so), you can pass anything false-y as the value for options.dsn to the Sentry.init(options) function.

ಠ_ಠ

The good thing is that this works in apparently all their clients!

Read more: https://github.com/getsentry/sentry-symfony/issues/38#issuecomment-271825703

Created at: Thu Dec 27 2018 22:37:30 GMT+0000 (Coordinated Universal Time)

Sentry nodejs package isn’t modelled to be used serverless-ly

javascript,node,error-reporting,serverless,lambda

#TIL that @sentry/node buffers exceptions your app sends to sentry.io and sends 'em over the wire async. This fails with lambdas as they cease to exist after responding. The work around is await-ing on Sentry.getCurrentHub().getClient().close(2000)

Read more: https://github.com/getsentry/sentry-javascript/issues/1449

Created at: Wed Dec 26 2018 22:43:01 GMT+0000 (Coordinated Universal Time)

HTTP2 Server Push on CDNs that support it

web,performance,http2

#TIL that one can enable HTTP2 Server Push on CDNs that support it by using the Link http header. E.g., Link: </css/custom.css>; as=style; rel=preload, </img/favicon.ico>; as=image; rel=preload.

Read more: https://www.smashingmagazine.com/2017/04/guide-http2-server-push/

Created at: Sun Dec 16 2018 16:40:21 GMT+0000 (Coordinated Universal Time)

HSTS preload list

web,security,https,hsts

#TIL about the HSTS preload list maintained by google. It prevents all browsers that respect this list from connecting to page in the list using an insecure protocol like http. Your website can qualify if it sets the Strict-Transport-Security header.

Read more: https://hstspreload.org

Created at: Sun Dec 16 2018 16:40:00 GMT+0000 (Coordinated Universal Time)

Epoch based computer time

time,software

#TIL about different epochs used by software. Specifically win32/64 epoch of January 1, 1601 (UTC). The FileTime struct holds time elapsed in 100 nanosecond intervals since January 1, 1601 (UTC). Why? "it was chosen to make the math come out nicely".

Read more: https://en.wikipedia.org/wiki/Epoch_(reference_date)#Notable_epoch_dates_in_computing

Created at: Sun Dec 16 2018 16:39:41 GMT+0000 (Coordinated Universal Time)