How to create giant memory leaks in AngularJS (and other client-side JavaScript)
This guide shows how to create an AngularJS application that consumes more and more memory until, eventually, the browser process crashes on your users.
Although this guide has been written for Angular 1 originally, most of the advice is relevant for all client-side JavaScript code.
How to observe memory consumption
To inspect the amount of memory consumed by your Javascripts in Chrome:
- Open an incognito window
- Open the page you want to inspect
- Press
Shift + ESC
to see a list of Chrome processes...
Jasmine: Mocking ESM imports
In a Jasmine spec you want to spy on a function that is imported by the code under test. This card explores various methods to achieve this.
Example
We are going to use the same example to demonstrate the different approaches of mocking an imported function.
We have a module 'lib'
that exports a function hello()
:
// lib.js
function hello() {
console.log("hi world")
}
export hello
We have a second module 'client'
that exports a function helloTwice()
. All this does is call hello()
...
Heads up: RSpec-Mocks' #stub_const will define intermediate modules that have not been loaded yet
The issue: You are using stub_const
to change a constant value for your test.
stub_const "SomeClass::CONST", 'test'
All of a sudden, tests fail with undefined method 'some_method' for #<SomeClass:0x00000000101433a8>
.
The reason
When using stub_const before the Class containing the constant has been loaded, a module is automatically created with the name.
Since RSpec does no autoloading, it will create a SomeClass
module by itself. This is arguably a good idea.
As a workaround, use stub_const
in your Rails specs li...
BigDecimal arithmetic in Ruby
Ruby comes with a class BigDecimal
which you can use for arbitrary precision arithmetic. You should use BigDecimal
instead of Float
whenever you care about rounding errors, e.g. whenever you are dealing with money.
You should remember these two rules when working with BigDecimal
values:
- When you add or multiply a
BigDecimal
with anotherBigDecimal
, the ...
sessionStorage: Per-window browser storage
All major browsers (IE8+, FF3.5+, Safari 4+, any Chrome) support sessionStorage
, a JavaScript storage object that
- survives page reloads and browser restores,
- but is different per new tab/window (in contrast to
localStorage
which is shared across all tabs).
MDN says:
The
sessionStorage
object is most useful for hanging on to temporary data that should be saved and restored if the browser is accidentally refreshed
Demo
Example usage:
Set default_url_options for entire Rails application
Instead of cobbling together default settings in several different places as the issues arise, you can define them application-wide.
Heads up: Capybara 3's text matchers no longer squish whitespace by default
Until Capybara 2, node finders that accept a text
option were able to find nodes based on rendered text, even if it spans over multiple elements in the HTML. Imagine a page that includes this HTML:
<div class='haystack'>
Hi!
<br>
Try to match me.
</div>
Even though the text is separated by a <br>
tag in the HTML, it is matched until Capybara 2 which used to "squish" text prior to the comparison.
# Capyabara 1 or 2
page.find(...
Firefox cancels any JavaScript events at a fieldset[disabled]
If you try to listen to events on elements that are nested inside a <fieldset disabled>
, Firefox will stop event propagation once the event reaches the fieldset. Chrome and IE/Edge will propagate events.
Since we often bind event listeners to document
this can be annoying.
You could solve it by...
- ...adding event listeners on elements themselves. Note that this is terrible when you have many elements that you'd register events for.
- ...adding event listeners on a container inside the
<fieldset>
, around your eleme...
Beware: Many browsers define window.event
Some browsers define window.event
, which will return a copy of the "current" event. However, this is not defined by the W3C. Most importantly, Firefox does not support it, neither do recent versions of IE.
You should completely avoid accessing the global event
and instead pass the event object around that the event handler receives. The easiest protection against accidentally accessing window.event
is just never naming the event event
, but e
or evnt
or so.
function brokenInFirefox() {
event.preventDefault(); // Break...
Heads up: network requests `Kernel#open` are not mocked with VCR
We usually rely on VCR and WebMock to prevent any real network connection when running our unit tests.
This is not entirely true: They are both limited to a set of HTTP libraries listed below (as of 2022). Direct calls to Kernel#open
or OpenURI#open_uri
are not mocked and will trigger real network requests even in tests. This might bite you e.g. in [older versions of CarrierWave](https://github.com/carrierwaveuploader/carrierwave/blob/0.11-stable/lib/carrierwave/upl...
subscript, superscript and line-heights
By default subscript (<sub></sub>
) and superscript (<sup></sup>
) tags are styled with vertical-align: sub
, respectively vertical-align: super
by most browsers.
However, without adaptations, this will probably break your line-heights.
A common suggestion is to style those two tags accordingly:
sup, sub {
vertical-align: baseline;
position: relative;
top: -0.4em; /* can be adapted according to preferences */
}
sub {
...
Linux: Running a single unique instance of command + arguments
run-one
is a wrapper script that won't run the given command while another instance of it is running. Is brings several utility commands that offer similar behavior.
NAME
run-one - run just one instance at a time of some command and unique set of arguments (useful for cronjobs, eg)
SYNOPSIS
run-one COMMAND [ARGS]
run-this-one COMMAND [ARGS]
run-one-constantly COMMAND [ARGS]
keep-one-running COMMAND [ARGS]
run-one-until-success COMMAND [ARGS]
run-one-until-failure COMMAND [ARGS]
...
How to update a single gem conservatively
The problem
Calling bundle update GEMNAME
will update a lot more gems than you think. E.g. when you do this:
bundle update cucumber-rails
... you might think this will only update cucumber-rails
. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.
In the example above updating cucumber-rails
will give you Capybara 2.0 (because capybara
is a dependency of `cucumber-rail...
Destructors for async Unpoly compilers
Usually, Unpoly compiler destructors are return
ed from the compiler function.
However, when using async
compiler functions, you can not register destructors via return
.
This will not work:
up.compiler('my-example', async (element) => {
await something
return function onDestroy() {
// ...
}
})
Instead, use up.destructor:
up.compiler('my-example', async (element) => {
await something
u...
Bookmarklet: cards Markup Link Bookmarklet
The cards editor has a feature "Cite other card" to create links to other cards in the same deck as mardown links.
If you want to reference a card from a different deck, this bookmarklet might be useful:
javascript:(function () {
const doAlert = () => { alert("Maybe not a makandra card?") };
let cardsPathPattern = /(\/[\w-]+\/\d+)-.+/;
if (window.location.pathname.match(cardsPathPattern)) {
let currentPath = window.location.pathname.match(cardsPathPattern)[1];
let title = document.querySelector('h1.note--title')?.textCon...
A modern approach to SVG icons
You have some SVG files you want to use as icons on your website. How would you embed them?
Common options are:
- Use them with an image:
<img src='path-to-icon.svg'>
- Embed them inline with
<svg>$ICON</svg>
- Embed them using CSS and
background-image: url(path-to-icon.svg)
or evenbackground-image: url(data:$ICON)
. - Build your own icon font.
All of these have drawbacks:
- Image and
background-image
do not allow to recolor the image using CSS. - Inline-
<svg>
are unnecessary work for the server and are...
Using path aliases in esbuild
In esbuild, you usually import other files using relative paths:
import './some-related-module'
import `../../utils/some-utility-module`
import `../../../css/some-css.sass`
This is totally fine if you import closely related files, but a bit clunky when you're trying to import some "global" module, like a utility module. When moving a file, your imports also need to change.
To get around this, esbuild support a mechanism first introduced in TypeScript called "path aliases". It works like this:
First, you create a file called `js...
Rails: Use STI in Migration
tl;dr
You should decouple migrations from models by embedding models into the migration. To use STI in this scenario you have to overwrite
find_sti_class
andsti_name
.
Tip
When possible, try to avoid STI in migrations by disabling it.
Example
Warning
This is more for the sake of I want to do it but I kno...
How to see how many inotify instances are used by each process
As a developer you may have many tools watching your project for changes: Your IDE, Webpack, Guard, etc. This is often done with an inotify watcher. If you have too many inotify instances you may run into limits of your operating system.
To find out which process is using them all up you can run:
sudo find /proc/*/fd/ -type l -lname "anon_inode:inotify" -printf "%hinfo/%f\n" | xargs grep -cE "^inotify" | column -t -s:
You will get a list like:
/proc/3753/fdinfo/7 1
/proc/3774/fdinfo/7 1
/proc/4034/fdinfo/12 14
/pr...
Colorful output for several linux command line tools: grc
Because colors improve readability so much.
On Ubuntu 18.04 you can install it with sudo apt install grc
From github:
For the impatient - try following commands:
grc netstat
grc ping hostname
grc tail /var/log/syslog
grc ps aux
Capybara: Testing file downloads
Download buttons can be difficult to test, especially with Selenium. Depending on browser, user settings and response headers, one of three things can happen:
- The browser shows a "Save as..." dialog. Since it is a modal dialog, we can no longer communicate with the browser through Selenium.
- The browser automatically downloads the file without prompting the user. For the test it looks like nothing has happened.
- The browser shows a binary document in its own window, like a PDF. Capybara/Selenium freaks out because there is no HTML docum...
Different ways to set attributes in ActiveRecord
Rails 5 / 6 / 7
Method | Uses Default Accessor | Saves to Database | Runs Validations | Runs Callbacks | Updates updated_at/updated_on | Respects Readonly |
---|---|---|---|---|---|---|
attribute= |
Yes | No | n/a | n/a | n/a | n/a |
attributes= |
Yes | No ... |
Diátaxis: A systematic framework for technical documentation authoring
The Diátaxis framework aims to solve the problem of structure in technical documentation. It adopts a systematic approach to understanding the needs of documentation users in their cycle of interaction with a product.
Diátaxis identifies four modes of documentation - tutorials, how-to guides, technical reference and explanation. It derives its structure from the relationship between them.
In Diátaxis, each of these modes (or types) answers to a different user need, fulfils a different purpose and requires a different appr...
How to use Parallel to speed up building the same html partial multiple times (for different data)
The parallel-gem is quite easy to use and can speed up rendering time if you want to render the same partial multiple times (e.g. for rendering long lists of things).
If your parallelized code talks to the database, you should ensure not to leak database connections.
Consider you want to render a list of groups with their members as json. You can use a partial for the rendering of group members, b...