{"id":13599366,"url":"https://github.com/tmcw/today-i-learned","last_synced_at":"2025-07-03T22:05:41.646Z","repository":{"id":66155159,"uuid":"119758908","full_name":"tmcw/today-i-learned","owner":"tmcw","description":"keeping track of things i never would have guessed but were true anyway","archived":false,"fork":false,"pushed_at":"2023-11-09T14:56:41.000Z","size":65,"stargazers_count":48,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-03T22:05:30.198Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tmcw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-01-31T23:59:34.000Z","updated_at":"2023-12-04T14:07:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"dc95d291-c5a6-4a99-9379-61dcbf31e83d","html_url":"https://github.com/tmcw/today-i-learned","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tmcw/today-i-learned","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmcw%2Ftoday-i-learned","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmcw%2Ftoday-i-learned/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmcw%2Ftoday-i-learned/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmcw%2Ftoday-i-learned/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tmcw","download_url":"https://codeload.github.com/tmcw/today-i-learned/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tmcw%2Ftoday-i-learned/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263410762,"owners_count":23462297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T17:01:02.971Z","updated_at":"2025-07-03T22:05:41.590Z","avatar_url":"https://github.com/tmcw.png","language":null,"funding_links":[],"categories":["Others"],"sub_categories":[],"readme":"# today i learned\n\nRunning list of little interesting things I learn. Uninteresting things not included. Not guaranteed to be interesting for all / any audiences.\n\n### Safari 10 and 11 don't _actually_ support let and const\n\nAll of the support tables are lying: Safari 10 and 11 parse let and const, but if you try to rely on their block scoping, they break.\n\nThe fix: enable the `safari10` option in uglify-es.\n\n### Firefox handles CSP `style-src` differently than Chrome\n\nIn Chrome, you can set style-src to just `somedomain.com` and it'll work. In Firefox, unless you set `unsafe-inline`, `style=\"\"` attributes will break.\n\n### Monospace is only as monospace as its character set\n\nLet's say you have a monospace-formatted table, so all the `|` should align. If any value in any column includes a character that isn't supported by the monospace font, the table won't be aligned. Example:\n\n```\n| h |\n| 🚀 |\n```\n\n### git is case sensitive, but if you're on a Mac, your file system isn't\n\n`git status` will show a moved file on a case-sensitive system, but not here.\n\n```\n~/tmp/example〉git init .\nInitialized empty Git repository in /Users/tmcw/tmp/example/.git/\n~/tmp/example〉touch Hi\n~/tmp/example〉git add Hi\n~/tmp/example〉git commit -m \"First\"\n[master (root-commit) c09565f] First\n 1 file changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 Hi\n~/tmp/example〉mv Hi hi\n~/tmp/example〉git status\nOn branch master\nnothing to commit, working tree clean\n```\n\n### rgba and hsla isn't actually necessary\n\nIn CSS Color Module 4, [rgba and hsla](https://drafts.csswg.org/css-color/#rgb-functions) are officially 'legacy' - you can add an alpha component without adding the `a` to either - just use `rgb()` and `hsl()` always.\n\n### Browser search is not literal and equates certain characters\n\nIf you're in _extreme pedant mode_ and want to find any place where you've typed an errant `'` instead of a curly `’`, and you use Google Chrome's built-in search, you'll be surprised to see that - it matches both, regardless of which character you type. Apparently the search aliases certain common characters, because there are more people who would be upset about some quote-containing search to _not_ return results based on typographical pedantry than people who would want to search for non-curly quotes only.\n\n### The default google analytics tracking snippet is sort of wrong\n\n```html\n\u003c!-- Google Analytics --\u003e\n\u003cscript\u003e\nwindow.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;\nga('create', 'UA-XXXXX-Y', 'auto');\nga('send', 'pageview');\n\u003c/script\u003e\n\u003cscript async src='https://www.google-analytics.com/analytics.js'\u003e\u003c/script\u003e\n\u003c!-- End Google Analytics --\u003e\n```\n\nSpot the weirdness. Well: if you have some script that's sync or that's async but loads _before_ google analytics, and that script changes the page location, then the first page that's tracked is not the page URL that's loaded. We throw in a\n\n```js\nga(\"set\", \"page\", location.pathname + location.search);\n```\n\nTo make sure the first-page-location-loaded is tracked.\n\n### console.log ain't sync\n\nOkay, I knew this one before, but it's always good to remember: console.log isn't sync. If you console.log something and then immediately modify the thing, console.log is likely to show the modified version, not the version at the time of the `console.log` call. Beware.\n\n### smartypants isn't always right\n\nThere are some tough cases in English punctuation: see [this issue in the marked repository](https://github.com/markedjs/marked/issues/166):\n\n\u003e I won't do it 'cause I don't want to.\n\nThis should have:\n\n* won’t\n* 'cause\n* don’t\n\nThe commonplace smartypants option isn't smart enough to parse that, but implementations like [markdown-it](https://github.com/markdown-it/markdown-it) and Medium's online editor can do very advanced quote formatting.\n\n### content-type is a weird attack vector\n\n\u003e An attacker could upload a specially crafted JPEG file that contained script content, and then send a link to the file to unsuspecting victims. When the victims visited the server, the malicious file would be downloaded, the script would be detected, and it would run in the context of the picture-sharing site.\n\n[Here's one blog post](https://blogs.msdn.microsoft.com/ie/2008/07/02/ie8-security-part-v-comprehensive-protection/). It's weird, because before even if you declared a content-type, IE would still try to auto-detect a content type, and might re-interpret the file as something different. So you serve a file that contains JavaScript-looking content, but with an `image/jpg` mime-type, IE would treat it as a script. So they:\n\n- stopped sniffing image/ content\n- let you turn sniffing off\n\n### along with the set-cookie http header, there's a historical set-cookie2 header\n\nhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie2\n\nIt's just weird, that's all.\n\n### content-type does matter in the case of worker destinations\n\nhttps://fetch.spec.whatwg.org/#should-response-to-request-be-blocked-due-to-mime-type?\n\nSo, like - usually you can fetch anything into anything, but if you're doing something like a Paint Worklet or a WebWorker, and the thing you're fetching has an image or CSV mime type, it's blocked.\n\n### Body 'consume methods' really do consume the thing\n\nhttps://fetch.spec.whatwg.org/#body-mixin\n\nexample\n\n```\nlet resp = await fetch('https://unpkg.com/propel@3.2.0?meta');\n[await resp.json(), await resp.text()];\n```\n\nThis breaks! What `.json()` and `.text()` do internally is that they consume a _stream_ of the body, and like other streams, you can only consume it once.\n\n### reassigning the `eval` function to another variable name changes its behavior\n\nIn code review, I came across\n\n```js\nconst compile = eval;\n```\n\nAnd wondered why we were renaming it. Almost everywhere in JavaScript, reassigning one variable to another name has no effect. That is [not the case with eval: renaming eval makes it turn into an _indirect_ eval call](http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope).\n\n### The 'externally resolvable promise trick'\n\nI should have written this one down a while ago, it's something that I learned from Mike's code:\n\n```js\nlet resolve;\n\nlet myPromise = new Promise(_resolve =\u003e { resolve = _resolve });\n\n// now you can resolve that promise remotely\nresolve();\n```\n\nIt sort of inverts Promises, in a way, freeing you from relying on the resolve/reject methods only being called from inside its function.\n\n### Equality with NULL in Postgres is not at all what I expected\n\nI spent an hour debugging a simple query and got Jeremy to help and we both were stuck, until I re-read the [Postgres documentation about comparison operators](https://www.postgresql.org/docs/9.1/static/functions-comparison.html): and, here's how it works:\n\n- (7 = NULL) = NULL\n- (7 != NULL) = NULL\n\nNULL, in Postgres, propagates. Any comparison with NULL always yields NULL. I ended up switching to the new `IS DISTINCT FROM` comparison instead of simple `=` comparisons.\n\n### Bolded lists should have non-bold commas, italic lists should have italic commas\n\n\u003e _Apples, oranges,_ and _bananas_\n\nVersus\n\n\u003e **Apples**, **oranges**, and **bananas**\n\n[This from Elements of Typographic Style](https://en.wikipedia.org/wiki/The_Elements_of_Typographic_Style).\n\n### My default 'alphanumeric' regular expression is deficient\n\nI often write\n\n```js\n/A-Za-z/\n```\n\nBut if I want to really cover all the bases, I should write\n\n```js\n/A-ZÀ-ÿa-z/\n```\n\nOtherwise accented words break the regex.\n\n### Postgresql does not respect the order of results in a CTE\n\nIf you have a CTE in Postgresql:\n\n```sql\nWITH something AS (SELECT …)\n\nSELECT * from something\n```\n\nThe order of `something` is **not** necessarily preserved. It uses the CTE as an optimization but you cannot depend on it. Instead, you’ll need to re-sort, or expose an integer that can be sorted, like\n\n```sql\nROW_NUMBER () OVER (${orderClause}) AS rn\n```\n\n### Postgres allows duplicate columns\n\nLike\n\n```sql\nSELECT 1 as a, 2, as a;\n```\n\nThis gets tricky because most postgres bindings exposed row objects as objects, so the value is just the last duplicate-named column.\n\n### Running list of words I encounter in books:\n\n- Death and Life of Great American Cities\n  - Contretemp: minor diagreement\n  - Automat: coin-operated/automated restaurant\n  - Inveigle: to win over with flattery\n- Petrel: a shearwater-like seabird\n- Nekton: a plankton-like sea creature\n- Israel\n  - Kippah: another word for yarmulke\n- Deicide: the killing of a god\n- Amanuensis: a literary or artistic assistant\n- Lachrymose: prone to weeping\n- Sangfroid: composure and coolness\n- Stevedore: a longshoreman or dockworker\n- Hillock: a small hill or mound\n- Cynosure: a center of attention\n- Janissary: a devoted follower\n- Ex parte: one-sided, from one side\n- Soupcon: a small portion\n\n### `hidden` attribute\n\nThere's an HTML attribute called `hidden` that simply hides elements:\n\n```\n\u003cdiv hidden\u003eThis is hidden!\u003c/div\u003e\n```\n\n### You can use `vidir` to rename multiple files\n\nIt's part of the [moreutils](https://joeyh.name/code/moreutils/) package that you can install with homebrew, and you just run `vidir` in a directory, change the names, and exit your editor and everything is saved.\n\n### The spread operator in JavasScript (`...`) is pretty dangerous in lots of scenarios.\n\nFor example:\n\n```js\nconst x = Array.from({ length: 1000000 }, (_, i) =\u003e i)\nconst y = [];\ny.push(...x);\n```\n\nThis code crashes, because `...x` creates an arguments object that's too big. That triggers `RangeError: Maximum call stack size exceeded` and crashes. Avoid `...` for values of unknown length. This does notably **only relate to function calls**, like `.push()`. Using spread in an array, like `[...x]` doesn't trigger the same issue.\n\n## Postgres sorts strings _very_ differently than JavaScript\n\nPostgres does proper locale-based sorting, whereas JavaScript just compares characters by default. You can change the intricate behavior of string sorting by specifying a [COLLATE](https://www.postgresql.org/docs/current/collation.html) option.\n\n## Postgres is one-indexed!\n\nRemember this - the one indexed languages that you'll actually encounter - SQL, Lua, R.\n\n## Dynamic imports in Deno are fetched ahead of time\n\nIt's not going to work if you try and profile the `import()` call - Deno does static analysis to find dynamic imports before running the script.\n\n## 1fr in CSS grid layouts is kind of a footgun\n\nSee [preventing a grid blowout](https://css-tricks.com/preventing-a-grid-blowout/) for details, or this quick fix:\n\n```css\ngrid-template-columns: minmax(0, 1fr) 300px;\n```\n\nThe thing is, `1fr` I always thought behaved like 100%, but it doesn't - it won't shrink as much as an element with `100%` because the minimum width is `auto`, not 0. The same goes for flex items, which is why I've often found that `min-width: 0` is helpful when flex elements are misbehaving and not shrinking.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftmcw%2Ftoday-i-learned","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftmcw%2Ftoday-i-learned","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftmcw%2Ftoday-i-learned/lists"}