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 + ESCto 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
BigDecimalwith 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
localStoragewhich is shared across all tabs).
MDN says:
The
sessionStorageobject 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.
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]
...
Destructors for async Unpoly compilers
Usually, Unpoly compiler destructors are returned 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...
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_classandsti_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...
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...
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...
Automated "git bisect" will make your day
So you're hunting down a regression (or just a bug) and want to use git bisect to find out when it was introduced? Smart kid.
If you have a shell command ready to reveal if your current state is good or bad, you can have git do most of the work for you.
Using git bisect run <your command> you can tell git that your command will reveal the issue; git on the other hand will use the return value of that call to decide if the state is good or bad.
...
Jasmine: Creating DOM elements efficiently
Jasmine specs for the frontend often need some DOM elements to work with. Because creating them is such a common task, we should have an efficient way to do it.
Let's say I need this HTML structure:
<ul type="square">
<li>item 1</li>
<li>item 2</li>
</ul>
This card compares various approaches to fabricating DOM elements for testing.
Constructing individual elements
While you can use standard DOM functions to individually create and append elements, this is extremely verbose:
let list = document.createElement('...
Advantages of using appname.daho.im:3000 over localhost:3000
Running rails server will start a local server that you can access via http://localhost:3000.
When you are working on multiple web apps, they will likely set cookies with generic names on localhost. This is annoying, since you will sign out your current user whenever you switch to another app.
A better way is to use our own daho.im service. All daho.im subdomains resolve to your local IP (127.0.0.1). That means you can use a different hostname for different apps, and you will stay logged in in each app:
http://foo-ap...
Capybara: Execute asynchronous JavaScript
Capybara provides execute_script and evaluate_script to execute JavaScript code in a Selenium-controlled browser. This however is not a good solution for asynchronous JavaScript.
Enter evaluate_async_script, which allows you to execute some asynchronous code and wait until it finishes. There is a timeout of a couple of seconds, so it will not wait forever.
Use it like this:
page.evaluate_async_script(<<~JS)
let [done] = arguments
doSomethingAsynchronous().then(() => {
done() // call this to indicate we're done
})
J...
Always disable autocomplete for date pickers
When we write a form with date fields, we often use graphical data picker like Rome to get a consistent calendar popup on all browsers.
When you integrate a date picker popup, remember to also set autocomplete="off" on the text input that opens the calendar on click. Otherwise the autocomplete suggestions will cover the calendar box and make it unusable:
If you are using a tool like Unpoly you might want to set autocomplete="off" i...
How to simulate limited bandwidth in Google Chrome and Firefox
Your development machine is usually on a very good network connection.
To test how your application behaves on a slow network (e.g. mobile), you can simulate limited bandwidth.
Chrome
- Open the dev tools (Ctrl+Shift+I or F12) and switch to the "Network" tab
- In the row below the dev tool tabs, there's a throttling dropdown which reads "Online" by default.
- Inside the dropdown, you will find a few presets and an option to add your own download/upload/latency settings.
Firefox
- Open the dev tools (Ctrl+Shift+I or F12) and switc...
Fast Navigation Tips In Dev Tools
Hide/Show Drawer
You can press Escape to show/hide the drawer.
Fast Navigation with Command Menu
Use Ctrl + Shift + p to open Command Menu, where you can switch to different panels, toggle settings etc.
Reorder DevTools panels and Drawer tabs and combine them by moving them up and down to and from the Drawer.
Right click on any tab and then choose Move to top / Move to bottom
Change DevTools layout from auto to always horizontal or vertical.
Click on Settings > Preferences > Panel Layout, Choose between Horizontal / Ve...