Today I Learned
Faster git commands
gitgit maintenance
keeps repository data optimized by running scheduled background tasks. This in turn speeds up almost all bread and butter git commands such as pull
, rebase
, fetch
, etc.
Enable auto maintenance:
git maintenance start
Manually trigger maintenance — useful for the first run:
git maintenance run
Read more: https://git-scm.com/docs/git-maintenance
Created at: Tue Feb 13 2024 09:38:51 GMT+0000 (Coordinated Universal Time)
Testing sentry integration in prod
javascript,sentryIf sentry has been initialized as its docs state, then we can hae the following hack to trigger and error on demand in prod and verify if sentry captures it and sends it to its servers.
The work around simply adds a button on screen that throws an error when clicked. To use, go to the route you are testing on prod, open the dev console and run the following code —
button = document.createElement('button')
button.onclick = () => {
throw new Error('woops!')
}
button.textContent = 'Throw error'
document.body.prepend(button)
Upon clicking 'Throw error', if the error shows up in your sentry project, you can sleep easy knowing your sentry setup works!
Read more: https://mudit.xyz
Created at: Thu Aug 04 2022 09:41:43 GMT+0000 (Coordinated Universal Time)
Squaring numbers below 50
mathTIL a trick to square any number below 50 in my head.
For example, to square 48
- first subtract it from 50 i.e., 2
- then we subtract that result from 25 to get the first two digits of the square i.e., 23
- next we square the result of step one to get the last two digits of the square i.e., square(2) = 04
Thus giving us the square of 48 as 2304!
Read more: https://youtu.be/uY-u1qyRM5w?t=15m14s
Created at: Tue Dec 29 2020 23:02:55 GMT+0000 (Coordinated Universal Time)
Returning errors and data in a single graphql request
graphql,error-reportingThis 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>
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,javascriptThis 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,terminalThis 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,denoSo, 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™️!
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"
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 ImageMagick — the 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.
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
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
.
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:
- Check if
graphql
is a core module. Nope, it isn't. Go to next step. - Look for
graphql
in~/libA/dist/node_modules
. Found it? No? Ok, next step then. - 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 runnpm 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?
typescriptAs 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.
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)