MoreRSS

site iconThe Practical DeveloperModify

A constructive and inclusive social network for software developers.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of The Practical Developer

Unnesting Scalar Subqueries into Left Outer Joins in SQL

2025-12-23 23:46:35

Relational databases treat your query as a declarative description of the desired result and select the most efficient execution plan. They may rewrite the query—for example, by transforming subqueries into joins and vice versa—so the database, not the developer, manages this complexity.

Historically, PostgreSQL has had fewer planner transformations than many commercial databases. As an open-source project, it favors simpler code that promotes contributions and good SQL design, while commercial vendors can justify more complex planning logic when it helps revenue-generating customers in reducing their optimization efforts. PostgreSQL does not maintain a global shared plan cache, so most queries are planned per execution. This encourages keeping planning overhead low. The only exceptions are when using prepared statements, functions, or other situations where a plan can be generic, retained and reused. Transformations open more access paths, potentially improving execution plans, but at the cost of higher planning time.

AWS recently added these kinds of transformations to Amazon Aurora PostgreSQL (APG) to optimize queries with a correlated subquery in the projection:

Without this transformation, projection expressions are evaluated per row, which at best yields nested-loop–like performance. By pushing the subquery down so it runs before the projection, more efficient join algorithms can be used. Amazon Aurora is a proprietary fork of PostgreSQL, and its improvements are not contributed upstream, so this feature is not available in PostgreSQL. Nonetheless, examining the transformation Aurora implements can inspire similar manual rewrites of queries. I’ll use the example from the AWS blog post to show how to rewrite the query more efficiently. It is important to understand the transformation carefully to ensure it does not change the results.

Here is the DDL and DML to create the same example as AWS's article:

-- Clean up from previous runs

DROP TABLE IF EXISTS outer_table;
DROP TABLE IF EXISTS inner_table;

-- Outer table (like customers)

CREATE TABLE outer_table (
    id  SERIAL PRIMARY KEY,
    a   INT,
    b   INT
);

-- Inner table (like orders)

CREATE TABLE inner_table (
    id  SERIAL PRIMARY KEY,
    a   INT,
    b   INT
);

-- Insert data into inner_table:
--   10,000 rows, 'a' cycles from 1..100, 'b' random 0–999

INSERT INTO inner_table (a, b)
SELECT
    1 + mod(gs - 1, 100),
    floor(random() * 1000)::int
FROM generate_series(1, 10000) AS gs;

-- Insert outer_table:
--   First 25K rows: a = 1..100 repeated

INSERT INTO outer_table (a, b)
SELECT
    1 + mod(gs - 1, 100),
    floor(random() * 1000)::int
FROM generate_series(1, 25000) AS gs;
--   Next 25K rows: unique a = 101..35100
INSERT INTO outer_table (a, b)
SELECT
    gs + 100,
    floor(random() * 1000)::int
FROM generate_series(1, 25000) AS gs;
-- Gather statistics
ANALYZE outer_table;
ANALYZE inner_table;

I've set up an Aurora Serverless database to test it by enabling the transformation parameter and running the query, displaying the execution plan:

SET apg_enable_correlated_scalar_transform = on;

explain (analyze , verbose, costs off)
SELECT outer_table.a, outer_table.b
       , (SELECT AVG(inner_table.b)
          FROM inner_table
          WHERE inner_table.a = outer_table.a
) FROM outer_table
;
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Hash Left Join (actual time=4.904..15.740 rows=50000 loops=1)
   Output: outer_table.a, outer_table.b, (avg(inner_table.b))
   Inner Unique: true
   Hash Cond: (outer_table.a = inner_table.a)
   ->  Seq Scan on public.outer_table (actual time=0.016..2.968 rows=50000 loops=1)
         Output: outer_table.id, outer_table.a, outer_table.b
   ->  Hash (actual time=2.985..2.986 rows=100 loops=1)
         Output: (avg(inner_table.b)), inner_table.a
         Buckets: 1024  Batches: 1  Memory Usage: 13kB
         ->  HashAggregate (actual time=2.930..2.960 rows=100 loops=1)
               Output: avg(inner_table.b), inner_table.a
               Group Key: inner_table.a
               Batches: 1  Memory Usage: 32kB
               ->  Seq Scan on public.inner_table (actual time=0.016..0.637 rows=10000 loops=1)
                     Output: inner_table.id, inner_table.a, inner_table.b
 Query Identifier: -2382945993278526738
 Planning Time: 2.439 ms
 Execution Time: 23.322 ms
(18 rows)

I've added the verbose option to explain because it is important to see all elements of the rewritten query. Here, with the transformation, (SELECT AVG(inner_table.b) FROM ... WHERE ... ) has been transformed to (avg(inner_table.b)) over a Hash Left Join to the deduplicated (HashAggregate) inner table.

It is the equivalent of:

explain (analyze , verbose, costs off )
SELECT outer_table.a,  outer_table.b
       , agg.avg_b
FROM outer_table
LEFT JOIN (
    SELECT a, AVG(b) AS avg_b
    FROM inner_table
    GROUP BY a
) AS agg
ON outer_table.a = agg.a
;
                                              QUERY PLAN
------------------------------------------------------------------------------------------------------
 Hash Left Join (actual time=4.469..16.534 rows=50000 loops=1)
   Output: outer_table.a, outer_table.b, agg.avg_b
   Inner Unique: true
   Hash Cond: (outer_table.a = agg.a)
   ->  Seq Scan on public.outer_table (actual time=0.011..3.124 rows=50000 loops=1)
         Output: outer_table.id, outer_table.a, outer_table.b
   ->  Hash (actual time=3.804..3.806 rows=100 loops=1)
         Output: agg.avg_b, agg.a
         Buckets: 1024  Batches: 1  Memory Usage: 13kB
         ->  Subquery Scan on agg (actual time=3.733..3.778 rows=100 loops=1)
               Output: agg.avg_b, agg.a
               ->  HashAggregate (actual time=3.732..3.765 rows=100 loops=1)
                     Output: inner_table.a, avg(inner_table.b)
                     Group Key: inner_table.a
                     Batches: 1  Memory Usage: 32kB
                     ->  Seq Scan on public.inner_table (actual time=0.004..0.668 rows=10000 loops=1)
                           Output: inner_table.id, inner_table.a, inner_table.b
 Query Identifier: -3523129028670016640
 Planning Time: 1.361 ms
 Execution Time: 19.674 ms
(20 rows)

This looks simple, but SQL can be weird and not all aggregation functions have the same semantic with the absence of values. If there are no rows from the inner table, AVG() returns a NULL, like the correlated subquery would return in the absence of rows. However, if a COUNT() was used instead of AVG() it would be different, as a subquery still returns no rows but a COUNT() would return 0.

I test the automatic transformation on Aurora with a COUNT():

explain (analyze , verbose, costs off)
SELECT outer_table.a, outer_table.b
       , (SELECT COUNT(inner_table.b)
          FROM inner_table
          WHERE inner_table.a = outer_table.a
) FROM outer_table
;
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Hash Left Join (actual time=2.319..13.332 rows=50000 loops=1)
   Output: outer_table.a, outer_table.b, COALESCE((count(inner_table.b)), 0)
   Inner Unique: true
   Hash Cond: (outer_table.a = inner_table.a)
   ->  Seq Scan on public.outer_table (actual time=0.012..3.003 rows=50000 loops=1)
         Output: outer_table.id, outer_table.a, outer_table.b
   ->  Hash (actual time=2.302..2.304 rows=100 loops=1)
         Output: (count(inner_table.b)), inner_table.a
         Buckets: 1024  Batches: 1  Memory Usage: 13kB
         ->  HashAggregate (actual time=2.255..2.268 rows=100 loops=1)
               Output: count(inner_table.b), inner_table.a
               Group Key: inner_table.a
               Batches: 1  Memory Usage: 24kB
               ->  Seq Scan on public.inner_table (actual time=0.003..0.640 rows=10000 loops=1)
                     Output: inner_table.id, inner_table.a, inner_table.b
 Query Identifier: 6903753335662751945
 Planning Time: 1.267 ms
 Execution Time: 15.219 ms
(18 rows)

Now the VERBOSE option shows COALESCE((count(inner_table.b)), 0) to transform a NULL into a zero, in order to match the COUNT semantic.

Here is the equivalent query if you want to do the transformation manually:

explain (analyze , verbose )
SELECT outer_table.a,  outer_table.b
       , COALESCE(agg.cnt_b, 0) AS cnt_b
FROM outer_table
LEFT JOIN (
    SELECT a, COUNT(b) AS cnt_b
    FROM inner_table
    GROUP BY a
) AS agg
ON outer_table.a = agg.a;

                                                                  QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Hash Left Join  (cost=208.25..1110.53 rows=50000 width=16) (actual time=2.556..77.785 rows=50000 loops=1)
   Output: outer_table.a, outer_table.b, COALESCE(agg.cnt_b, '0'::bigint)
   Inner Unique: true
   Hash Cond: (outer_table.a = agg.a)
   ->  Seq Scan on public.outer_table  (cost=0.00..771.00 rows=50000 width=8) (actual time=0.012..3.183 rows=50000 loops=1)
         Output: outer_table.id, outer_table.a, outer_table.b
   ->  Hash  (cost=207.00..207.00 rows=100 width=12) (actual time=2.532..2.534 rows=100 loops=1)
         Output: agg.cnt_b, agg.a
         Buckets: 1024  Batches: 1  Memory Usage: 13kB
         ->  Subquery Scan on agg  (cost=205.00..207.00 rows=100 width=12) (actual time=2.485..2.509 rows=100 loops=1)
               Output: agg.cnt_b, agg.a
               ->  HashAggregate  (cost=205.00..206.00 rows=100 width=12) (actual time=2.484..2.497 rows=100 loops=1)
                     Output: inner_table.a, count(inner_table.b)
                     Group Key: inner_table.a
                     Batches: 1  Memory Usage: 24kB
                     ->  Seq Scan on public.inner_table  (cost=0.00..155.00 rows=10000 width=8) (actual time=0.006..0.679 rows=10000 loops=1)
                           Output: inner_table.id, inner_table.a, inner_table.b
 Query Identifier: 4982770911819576582
 Planning Time: 0.151 ms
 Execution Time: 80.622 ms
(20 rows)

You need COALESCE with COUNT in the manual join rewrite because of how SQL aggregates behave: unlike other aggregates, COUNT returns 0—not NULL—when there are no rows.

Aurora PostgreSQL’s apg_enable_correlated_scalar_transform shows how the planner can rewrite correlated subqueries in the SELECT list into join-based aggregates, replacing per-row subqueries with set-based aggregation and hash joins for much better performance.

Even if you don’t use Aurora in production, you can spin up a small Aurora Serverless instance to validate your manual rewrites. Enable the parameter and compare the execution plan to your PostgreSQL version. The plans should match, with one structural difference: the manual version’s grouped subquery is wrapped in a Subquery Scan, which is expected in hand-written SQL.

For aggregates like AVG(), the rewrite preserves semantics with no extra changes. For COUNT(), wrap the join output in COALESCE(..., 0) so it behaves like the original correlated subquery when no rows are found.

By understanding these transformations and their semantics, you can reproduce Aurora’s optimization in upstream PostgreSQL and gain similar performance benefits while keeping full control over correctness.

Title: Understanding Memory Management in Programming: A Comprehensive Guide

2025-12-23 23:41:31

Title: Understanding Memory Management in Programming: A Comprehensive Guide

Introduction:
Memory management is a crucial aspect of programming that often goes overlooked and yet plays a significant role in the performance and stability of software applications. In this blog post, we will delve into the basics of memory management, explore common memory management techniques, and provide practical examples to help you understand how to optimize memory usage in your code.

Key Takeaways:

  1. Understanding the basics of memory management in programming
  2. Different memory management techniques and their pros and cons
  3. Practical examples to illustrate memory management in action
  4. Tips for optimizing memory usage in your code

Basics of Memory Management:
In programming, memory management refers to the process of allocating and deallocating memory resources for data storage. When a program runs, it requires memory to store variables, objects, and other data structures. Memory management ensures that memory is allocated efficiently and released when it is no longer needed to prevent memory leaks and optimize performance.

Common Memory Management Techniques:

  1. Stack Memory: In stack memory allocation, memory is allocated in a last-in, first-out (LIFO) fashion. Variables declared within a function are allocated on the stack and automatically deallocated when the function returns. Example:
void foo() {
    int x = 10;
    // x is allocated on the stack
}
  1. Heap Memory: Heap memory allocation allows for dynamic memory allocation at runtime. Memory is allocated on the heap using functions like malloc() and calloc() and must be explicitly deallocated using free() to prevent memory leaks. Example:
int* ptr = malloc(sizeof(int));
// allocate memory on the heap
*ptr = 10;
free(ptr);
// deallocate memory
  1. Garbage Collection: Garbage collection is an automatic memory management technique used in languages like Java and C#. It automatically deallocates memory that is no longer in use, reducing the risk of memory leaks. Example:

Pattern Matching in C#: The Starters Guide

2025-12-23 23:41:29

Hey there! 👋🏻

If you've been coding in C# for a while, you've probably used the traditional if-else statements and the classic switch statement to handle different conditions in your code. But did you know that C# has evolved significantly in this area? Pattern matching is one of those powerful features that makes your code cleaner, more readable, and honestly, more fun to write!

In this post, we're going to explore pattern matching in C#, and I'll show you how it can transform your conditional logic from verbose and repetitive to concise and elegant.

What is Pattern Matching? 🤔

Pattern matching is a feature in C# that allows you to test if a value has a certain "shape" and extract information from it at the same time. Instead of writing multiple if statements to check types, values, or properties, you can express these checks more naturally and in fewer lines of code.

Think of it as a smarter, more expressive way to ask questions about your data.

The Classic Switch Statement (The Old Way) 🕰️

Before we dive into pattern matching, let's look at how we used to handle different cases with the traditional switch statement:

public string GetAnimalSound(string animal)
{
    switch (animal)
    {
        case "Dog":
            return "Woof!";
        case "Cat":
            return "Meow!";
        case "Cow":
            return "Moo!";
        default:
            return "Unknown sound";
    }
}

This works, but it's quite verbose, especially when you need to handle more complex scenarios. Now let's see how pattern matching makes this better!

Switch Expressions (The New Way) ✨

C# introduced switch expressions, which are a more concise way to write switch statements. Here's the same code rewritten using a switch expression:

public string GetAnimalSound(string animal) => animal switch
{
    "Dog" => "Woof!",
    "Cat" => "Meow!",
    "Cow" => "Moo!",
    _ => "Unknown sound"
};

Much cleaner, right? Notice how we got rid of the case, return, and break keywords. The _ at the end is the discard pattern, which acts like the default case.

Type Patterns 🎯

One of the most useful aspects of pattern matching is checking the type of an object and extracting it in one go. Before pattern matching, you'd have to do something like this:

// The old way
public void ProcessPayment(object payment)
{
    if (payment is CreditCard)
    {
        var creditCard = (CreditCard)payment;
        Console.WriteLine($"Processing credit card ending in {creditCard.LastFourDigits}");
    }
    else if (payment is PayPal)
    {
        var paypal = (PayPal)payment;
        Console.WriteLine($"Processing PayPal payment for {paypal.Email}");
    }
}

With pattern matching, you can check the type and declare a variable in one line:

// The new way
public void ProcessPayment(object payment)
{
    if (payment is CreditCard card)
    {
        Console.WriteLine($"Processing credit card ending in {card.LastFourDigits}");
    }
    else if (payment is PayPal paypal)
    {
        Console.WriteLine($"Processing PayPal payment for {paypal.Email}");
    }
}

Even better, you can use a switch expression for this:

public string ProcessPayment(object payment) => payment switch
{
    CreditCard card => $"Processing credit card ending in {card.LastFourDigits}",
    PayPal paypal => $"Processing PayPal payment for {paypal.Email}",
    BankTransfer bank => $"Processing bank transfer from {bank.AccountNumber}",
    _ => "Unknown payment method"
};

Property Patterns 🔍

Property patterns let you match based on the properties of an object. This is incredibly useful when you want to make decisions based on the state of an object.

Let's say we have a Person class and we want to determine if someone is eligible for a senior discount:

public record Person(string Name, int Age, string Country);

public bool IsEligibleForSeniorDiscount(Person person) => person switch
{
    { Age: >= 65, Country: "USA" } => true,
    { Age: >= 60, Country: "UK" } => true,
    { Age: >= 67, Country: "Germany" } => true,
    _ => false
};

You can even combine multiple conditions:

public string GetTicketPrice(Person person) => person switch
{
    { Age: < 12 } => "Child ticket: $5",
    { Age: >= 12 and < 18 } => "Teen ticket: $8",
    { Age: >= 18 and < 65 } => "Adult ticket: $12",
    { Age: >= 65 } => "Senior ticket: $6",
    _ => "Unknown"
};

Relational Patterns 📊

Relational patterns allow you to use comparison operators like <, >, <=, and >= directly in your patterns. This makes range checking much cleaner:

public string GetGrade(int score) => score switch
{
    >= 90 => "A",
    >= 80 => "B",
    >= 70 => "C",
    >= 60 => "D",
    _ => "F"
};

Compare this to the traditional approach:

// The old way
public string GetGrade(int score)
{
    if (score >= 90)
        return "A";
    else if (score >= 80)
        return "B";
    else if (score >= 70)
        return "C";
    else if (score >= 60)
        return "D";
    else
        return "F";
}

The pattern matching version is not only shorter but also more readable!

Logical Patterns (and, or, not) 🧮

You can combine patterns using logical operators to create more complex conditions:

public string CheckWeather(int temperature) => temperature switch
{
    < 0 => "Freezing!",
    >= 0 and < 15 => "Cold",
    >= 15 and < 25 => "Mild",
    >= 25 and < 35 => "Warm",
    >= 35 => "Hot!",
    _ => "Unknown"
};

public bool IsWeekend(DayOfWeek day) => day switch
{
    DayOfWeek.Saturday or DayOfWeek.Sunday => true,
    _ => false
};

public bool IsValidAge(int age) => age switch
{
    >= 0 and <= 120 => true,
    _ => false
};

Real-World Example 🌍

Let's put it all together with a practical example. Imagine you're building an e-commerce system and need to calculate shipping costs based on multiple factors:

public record Order(decimal TotalAmount, string Country, bool IsPrime, int Weight);

public decimal CalculateShipping(Order order) => order switch
{
    { IsPrime: true } => 0m,
    { Country: "USA", Weight: <= 1 } => 5m,
    { Country: "USA", Weight: > 1 and <= 5 } => 10m,
    { Country: "USA", Weight: > 5 } => 15m,
    { Country: "Canada", Weight: <= 1 } => 8m,
    { Country: "Canada", Weight: > 1 and <= 5 } => 15m,
    { Country: "Canada", Weight: > 5 } => 25m,
    { TotalAmount: >= 100 } => 0m,
    _ => 20m
};

This code is clean, easy to read, and handles multiple conditions elegantly. Try writing the same logic with traditional if-else statements, and you'll see how much more verbose it would be!

When to Use Pattern Matching ⚙️

Pattern matching shines when you need to:

  • Check types and extract values at the same time
  • Make decisions based on object properties
  • Handle multiple conditions with different ranges or values
  • Replace long chains of if-else statements
  • Make your code more expressive and readable

Conclusion ✅

Pattern matching in C# is a powerful feature that makes your code more concise and expressive. We've covered switch expressions, type patterns, property patterns, relational patterns, and logical patterns. Each of these gives you a new tool to write cleaner, more maintainable code.

The best way to get comfortable with pattern matching is to start using it in your projects. Next time you're writing a switch statement or a long chain of if-else conditions, try refactoring it with pattern matching and see the difference!

I hope you learned something new from this post!

Thanks for reading! 👋🏻

🚀 Terraform Day 15: Modules — Writing Reusable, Scalable Infrastructure Code

2025-12-23 23:35:37

🔹 What Is a Terraform Module?
A Terraform module is a self-contained set of Terraform files that define a reusable infrastructure component.

In simple terms:
A module is Terraform code that can be called multiple times with different inputs.

Terraform already uses modules implicitly:
The root directory is a module
Child modules are reusable blocks

1️⃣ Creating a Simple EC2 Module
modules/ec2/main.tf
resource "aws_instance" "this" {
ami = var.ami
instance_type = var.instance_type
subnet_id = var.subnet_id

tags = var.tags
}
modules/ec2/variables.tf
variable "ami" {
type = string
}
variable "instance_type" {
type = string
}
variable "subnet_id" {
type = string
}
variable "tags" {
type = map(string)
}

modules/ec2/outputs.tf
output "instance_id" {
value = aws_instance.this.id
}

2️⃣ Calling a Module from Root Configuration
In your root Terraform directory:
module "web_ec2" {
source = "./modules/ec2"

ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
subnet_id = data.aws_subnet.public.id

tags = {
Name = "web-server"
Env = "dev"
}
}

Terraform treats this module like a function call:
Inputs → variables
Outputs → return values

3️⃣ Using Module Outputs
You can reference module outputs easily:
output "web_instance_id" {
value = module.web_ec2.instance_id
}

This enables:
Cross-module communication
Cleaner root configurations
Better composition of infrastructure

4️⃣ Modules Across Environments
One of the biggest benefits of modules is environment reuse.
The same module can be used for:
Dev
QA
Prod
Only inputs change.

module "ec2_dev" {
source = "./modules/ec2"
instance_type = "t2.micro"
}

module "ec2_prod" {
source = "./modules/ec2"
instance_type = "t3.large"
}
✔ Same code
✔ Different behavior

5️⃣ Why Modules Are Mandatory in Real Projects
In professional Terraform setups:
❌ Copy–paste is forbidden
✅ Modules enforce DRY (Don’t Repeat Yourself)
✅ Changes happen in one place
✅ Code reviews are easier
✅ Bugs reduce drastically

Modules also enable:
Versioning
Team collaboration
CI/CD pipelines
Terraform Registry usage

process-polyfill.ts in Refly codebase.

2025-12-23 23:30:00

In this article, we review process-polyfill file in Refly codebase. We will look at:

  1. process-polyfill.ts

  2. dom-patch.ts

process-polyfill.ts

You will find the following code in process-polyfill.ts

/**
 * Process polyfill for browser environments
 * This is used to provide a 'process' global that some 
 * libraries expect to exist
 */

// Simply providing minimal process shim
// @ts-ignore - Ignoring type errors to create a simple shim
if (typeof window !== 'undefined') {
  // @ts-ignore - Using any to bypass strict type checking
  window.process = window.process || {
    env: {},
    version: '0.0.0',
  };
}

export {};

The comment is self explanatory, but I am not sure which package in Refly expects window.process to exist.

I also found the similar code in refly/apps/web/public/index.html.

<!-- Process polyfill -->
<script>
  window.process = window.process || {
    env: {},
    browser: true,
    version: '0.0.0'
  };
</script>

This process-polyfill file is imported in refly/web/src/index.tsx as shown below:

// Some injects
import './process-polyfill';
import './utils/dom-patch';
import './index.css';
import './tokens.css';
import './antd-overrides.css';
import './audio-controls.css';

import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '@refly-packages/ai-workspace-common/utils/request';
import { App } from './App';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <QueryClientProvider client={queryClient}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </QueryClientProvider>,
);

This is where I came across another inject, dom-patch.ts. In the section, let’s find out what dom-patch is about.

dom-patch.ts

You will find the following code in refly/web/dom-patch.ts

// @ts-nocheck - Disable all type checking for this file

// Workaround for removeChild and insertBefore errors when 
// google translate is enabled
// See https://github.com/facebook/react/issues/11538#issuecomment-417504600.
if (typeof Node === 'function' && Node.prototype) {
  const originalRemoveChild = Node.prototype.removeChild;
  Node.prototype.removeChild = function (child) {
    if (child.parentNode !== this) {
      if (console) {
        console.error('Cannot remove a child from a different parent', child, this);
      }
      return child;
    }
    // biome-ignore lint/style/noArguments: using arguments is simpler
    return originalRemoveChild.apply(this, arguments);
  };

  const originalInsertBefore = Node.prototype.insertBefore;
  Node.prototype.insertBefore = function (newNode, referenceNode) {
    if (referenceNode && referenceNode.parentNode !== this) {
      if (console) {
        console.error(
          'Cannot insert before a reference node from a different parent',
          referenceNode,
          this,
        );
      }
      return newNode;
    }
    // biome-ignore lint/style/noArguments: using arguments is simpler
    return originalInsertBefore.apply(this, arguments);
  };
}

This function has added the check below in removeChild and insertBefore methods:

if (referenceNode && referenceNode.parentNode !== this) {
  if (console) {
    console.error(
      'Cannot insert before a reference node from a different parent',
      referenceNode,
      this,
    );
  }
  return newNode;
}

Why? you might ask. Well, I don’t know. I am thinking this has to do with the comment:

// Workaround for removeChild and insertBefore errors when 
// google translate is enabled
// See https://github.com/facebook/react/issues/11538#issuecomment-417504600.

In the OSS, it is a common practice to leave links in the comments to justify the work arounds/hacks.

There is also a biome/ignore comment:

// biome-ignore lint/style/noArguments: using arguments is simpler
return originalRemoveChild.apply(this, arguments);

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: [email protected]

I spent 200+ hours analyzing Supabase, shadcn/ui, LobeChat. Found the patterns that separate AI slop from production code. Stop refactoring AI slop. Start with proven patterns. Check out production-grade projects at thinkthroo.com

References:

  1. refly/apps/web/src/process-polyfill.ts#L2

  2. refly-ai/refly/blob//apps/web/public/index.html#L50

  3. search?q=repo%3Arefly-ai%2Frefly+polyfill&type=code

  4. search?q=repo%3Arefly-ai%2Frefly+process-polyfill&type=code

  5. refly/web/src/index.tsx

Rsbuild in Refly codebase.

2025-12-23 23:30:00

In this article, we review Rsbuild usage in Refly codebase. We will look at:

  1. What is Rsbuild?

  2. What is Refly?

  3. Configure Rsuild.

What is Rsbuild?

Rsbuild is the Rspack powered build tool. This helps you build your web application instantly.

Check out Rsbuild Quick Start guide.

Features

  1. Rspack-based

  2. Batteries included

  3. Framework agnostic

  4. Deep optimization

  5. Highly pluggable

  6. Easy to configure

Rsbuild is lightning fast. Below are the stats I copied from the rsbuild.rs site

What is Refly?

Refly.AI helps non-technical creators automate tasks, produce production-ready content, and earn from what they build — all with natural language and a visual canvas.

Features

  1. Workflow automation

  2. AI-powered builder

  3. App integrations

  4. File library

  5. Community templates

  6. Creator rewards

Configure Rsbuild

I read their quick start and here’s what I learnt. You can create a new Rsbuild application using the following command:

npm create rsbuild@latest

Follow the prompts to choose options, such as whether to add optional tools like TypeScript and ESLint.

After creating the application, do the following:

  • Run git init to initialize a Git repository.

  • Run npm install (or your package manager's install command) to install dependencies.

  • Run npm run dev to start the dev server, which runs on http://localhost:3000 by default.

There are some templates available as well, much like Vite.

There are also framework specific guides:

  1. React

  2. Vue

  3. Preact

  4. Svelte

  5. Solid

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: [email protected]

I spent 200+ hours analyzing Supabase, shadcn/ui, LobeChat. Found the patterns that separate AI slop from production code. Stop refactoring AI slop. Start with proven patterns. Check out production-grade projects at thinkthroo.com

References:

  1. refly-ai/refly/blob/main/apps/web/package.json#L8

  2. https://rsbuild.rs/guide/start/quick-start

  3. https://refly.ai/

  4. https://rsbuild.rs/guide/framework/react