Posts

Inlined images in Next.js

Image
The slowest part of loading a web page is almost always user network. If you have small images like an app logo that you don't want to wait for on network, one tool in your toolbox is to inline these images using base64 encoding. This is how inlined images look in a browser: Desired usage Our goal is to be able to write the following if we want to have an inlined image: import logo from 'images/app-logo.inline.png' and the following for the regular URL (notice the .inline. part of the file name): import logo from 'images/app-logo.png' It can be later used as usual via: <Image src={logo}/> Implementation How do we do this in Next.js? We have to add url-loader to package.json and tweak next.config.js . // next.config.js module.exports = { // ... webpack: (config) => { // find the built-in loader const imageLoaderRule = config.module.rules.find( (rule) => rule.loader === 'n

Migration locks for TypeORM

Image
Schema migrations is a must-have functionality for any DB framework. TypeORM provides decent utilities for dealing with migrations, however having a decade of experience in Ruby on Rails I got really spoiled and take some features for granted. One of these features is locking a database while a migration going on so 2 processes running concurrently don't step on each other's toes. This is also important when you run migrations in Kubernetes before launching your app. I was really surprised to find out that this basic feature is not supported , so decided to implement it on my own. Implementation // typeormMigrationUtils.ts import { Connection, createConnection } from 'typeorm' import config from '../ormconfig' import CRC32 from 'crc-32' const MIGRATOR_SALT = 2053462845 async function withAdvisoryLock( connection: Connection, callback: () => Promise<void> ): Promise<boolean> { // generate a unique lock

Using image loader is Next.js

Image
Next.js has managed to kill off create-react-app and despite new rivals (in the face of Remix) is a de-facto way to start new React apps. One of the awesome features that Next.js and its platform Vercel provides is a way to automatically optimize images for different screens to make both user and developer experience much smoother. However, if your app has any non-trivial number of images that are generated by users you may soon end up visiting Vercel's limits page . Turns out that even on Hobby and Pro plans you are limited to 1000 and 5000 images per month, any overage is going to cost you dearly. At this point, you are going to start shopping for alternative image optimization solutions. You can either host your own via Thumbor or imgproxy or use one of the hosted solutions like Cloudinary . Regardless of what service you choose, it needs to be integrated into Next.js. After taking a look at Cloudinary as an example, even their free plan o

HTTP server in Ruby 3 - Fibers & Ractors

Image
This is part #2. Head over to part #1 to learn about HTTP in Ruby. Motivation Historically Ruby's been lacking in the concurrency department. Ruby has "native" threads (prior to 1.9 there were only "green"), which means there can be multiple threads controlled by an OS, but only 1 thread can be executed at a time, this is managed via Global Interpreter Lock (GIL). However, native calls and I/O calls can be executed in parallel. During an I/O call, a thread gives up control and waits for a signal that the I/O has finished. This means I/O heavy applications can benefit from multiple threads. In this article we are going to explore different concurrency modes for our HTTP server: Single-threaded Multi-threaded Fibers Ractors Single-threaded Let's start simple and see how a single threaded HTTP server could look like ( full code ): def start socket = TCPServer.new(HOST, PORT) sock

Ruby HTTP server from the ground up

Image
Getting something to work quickly is important when you are starting out, but if you want to become better at programming it's important to know a few levels below the abstractions you are used to be working with. When it comes to Web development it's important to know how HTTP works, and what better way to do that than go through baptism by fire and build our own HTTP server. How does HTTP look anyway? HTTP is plaintext protocol implemented over TCP so we can easily inspect what requests look like ( HTTP 2 is actually no longer plaintext, it's binary for efficiency purposes ). One way to look at request structure is to use curl with -v (verbose) flag: curl http://example.com/something -H "x-some-header: value" -v Outputs GET /something HTTP/1.1 Host: example.com User-Agent: curl/7.64.1 Accept: */* x-some-header: value And in response we get HTTP/1.1 404 Not Found Age: 442736 Cache-Control: max-age=604800 Content-Type:

Track Opened Emails In Rails

Image
Tracking opened emails is a technique that, if used responsibly, can provide utility to both you and your users. Here a few use cases where it makes sense to me: Appointment updates. If your appointment in a car dealership was rescheduled an email is sent. If the email is not read in the next couple of hours a repeat email can be sent or a CS agent may follow up with a call. Uber-style fulfillment, where contractors are notified of lucrative jobs available to them. If nobody claims a job, a CS agent can go through users who are known not to have read the email. Providing estimates to event organizers how many people are going to show up based a on number of opened emails. In this article, we are going to implement such a system for transactional emails using Rails and Postmark (a service that sends emails). We are going to use the Postmark gem . Usage First of all, let's see how the code usage of the tool we are building is going to look like

Turbocharge HTTP requests in Ruby

Image
The problem The slowest part in many applications is I/O, especially network I/O. We spend a lot of trying to make sure we reduce the number of calls and cache results of API calls to 3rd party services and resources. Imagine we want to get data from Rick and Morty API . In this article, we are going to speed up subsequent requests to this API by almost 4x times . The solution And yet there's a trick that even very senior developers and popular API library/clients forget about that can shave off precious time of your network calls built right into HTTP. Establishing an HTTP connection is very costly, especially if it uses TLS . This is a fixed price added to your HTTP calls that can be avoided by using keep-alive - a mechanism built into HTTP. According to Wiki : HTTP keep-alive, or HTTP connection reuse, is the idea of using a single TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new connection