The secret lovechild of Angular and Vue

Issue #251.January 4, 2024.2 Minute read.
Bytes

Today’s issue: Assuming Leeerob’s identity, SPA mode for Remix, and what the safety instructions of a particular Disneyland ride can teach us about JavaScript in 2024.

Welcome to #251.


Eyeballs logo

The Main Thing

Maury Povich from the Maury Show

DNA test results show that you are the father

The secret lovechild of Angular and Vue

Editorial Note: We’ve been busy breaking our New Year’s resolutions already, so we asked our good friend David East for some help with this story. He’s the Lead DevRel for idx.dev at Google and a Firebase lifer

Things are getting a lot more interesting for Analog.js since we first wrote about them back in October. That’s because the up-and-coming Angular metaframework is working on a new Single File Component format for Angular named .ng.

As you probably know, SFC is a special file format that has always been a defining feature of Vue, allowing you to encapsulate the template, logic, and styling of a component in a single file.

So why bring this to Angular? Because Brandon Roberts and Chau Tran of the Analog.js team think that an SFC format will fit nicely with the many new features that Angular has added over the last year — including Signals for simplified state management, new control flow syntax, life cycle hooks for safe DOM manipulation, a revamped SSR system, and more.

Let’s dive in by looking at some basic syntax:

<script lang="ts">
  import { inject, signal } from '@angular/core';

  defineMetadata({
    selector: 'app-root'
  });

  const counter = signal(1);
  const increment = () => counter.update((value) => value + 1);
</script>
<template>
  <div>Count: {{ counter() }}</div>
  <button (click)="increment()">increment</button>
</template>
<style>
  div { color: #f00; }
</style>

Each file can contain three sections: <script>, <template>, and <style>.

The defineMetadata({ }) function works a lot like the traditional @Component() decorator added on top of Angular component classes. It can define the selector name, directive, and pipe imports, as well as other useful metadata the component needs.

Things get even more interesting with how components are imported with .ng. Traditionally with Angular, you have to specify components within an imports array.

import { BytesArticle } from './bytes-article.component';

@Component({
  standalone: true,
  selector: 'bytes-issue-list',
  // Tell the component what is available to use in the template
  imports: [BytesArticle],
  template: `
    <bytes-article></bytes-article>
  `,
})
export class BytesIssueList {

}

This ends up being a three step process: the import, the array entry, and then the tag. However, with .ng it’s a lot more like what you would expect from Vue or (gasp) React. You import the component and it’s ready for use within the template.

<script lang="ts">
  import BytesArticle from './bytes-article.component.ng'

  defineMetadata({
    selector: 'bytes-issue-list'
  });
</script>
<template>
  <BytesArticle />
</template>

How it works: Analog registers a vite plugin to locate the template sections (<script>, <template>, and <style>) and creates a class-based Angular component behind the scenes. Angular-the-framework is none the wiser about this .ng format and keeps chugging along like normal.

Importantly, the .ng format allows all the new features Angular added in 2023 to shine. The inject() function (added before 2023) provides dependency injection outside of a constructor, signals provide observability outside of RxJS or class methods like ngOnChanges(), and new control flow syntax is a bit more legible compared to the directive-based structural flow syntax.

Bottom line: Single File Components is an (experimental) Analog.js feature, not an official Angular feature. But it does look like another promising development for the Angular ecosystem’s ongoing glow-up.

You can check out the sample repo if you want to try out the Vue-Angular lovechild for yourself.

        

Pieces logo

Our Friends
(With Benefits)

Kermit the frog walking with a toolbox into the sunlight

Me and my AI copilot about to put in an honest day’s work

Pieces gives you a free AI copilot for your entire workflow

Just download the free desktop app, and you’ll instantly supercharge your productivity. Here’s how:

  • The on-device AI connects to your IDE, browser extensions, and other devtools to integrate your entire workflow and reduce context switching.

  • You can ask the Pieces Copilot to generate contextual code for you, answer questions about entire repos, debug and review code, summarize what you worked on yesterday, talk to teammates, and lots more.

  • The AI understands code, text, screenshots, and videos to help you establish context and troubleshoot complex coding problems.

And because it’s an on-device AI with local, cloud, and custom LLM options, Pieces is able to work offline and is always learning from your workflow to get more helpful over time.

Download the app for free on macOS, Windows or Linux – and see why thousands of developers at companies like GitHub, Google, and Microsoft use it every day.


Spot the Bug logo

Spot the Bug

function* userGenerator(users) {
  for (let user of users) {
    if (!user.isActive) {
      return;
    }
    yield user;
  }
}

const users = [
  { name: "Ben", isActive: true },
  { name: "Alex", isActive: false },
  { name: "Tyler", isActive: true },
];

const gen = userGenerator(users);

for (let user of gen) {
  console.log(user);
}

Cool Bits logo

Cool Bits

  1. Austin Merrick wrote about Tail Call Optimization in Bun. It’s a niche optimization that’s implemented by JavaScriptCore but not V8, resulting in some key differences between Bun and Deno/Node.

  2. Speaking of Bun, they just released v1.0.21 on January 2nd to add console.table() support, fix some memory leak errors from node:fs, and more. Nice to see that Jarred & friends had a very fun and relaxing holiday break.

  3. Halvor William Sanden wrote about The Implied Web.

  4. Dan Moore wrote a visual guide to How Single Sign-on Works And Why You Should Care for the FusionAuth blog. I love it when people tell me why I should care about things. [sponsored]

  5. Remix is working on a SPA mode.

  6. Giridhar Talla wrote this guide to using Next.js 14 in his article, How Lee Robinson created his Guestbook, and you can do it too. One of my New Year’s resolutions is to slowly assume Leeerob’s identity, so this couldn’t have come at a better time.

  7. ESLint just released v9.0.0-alpha.0, which removes seven different formatters, among other breaking changes.

  8. Callstack’s App Performance Optimization provides your team with a holistic approach to improving your app performance for good. They diagnose all of your perf problems, fix them for you, and futureproof your app, so you’ll never deal with performance issues again. [sponsored]

  9. Juan Diego Rodríguez wrote an article called Making Sense Of “Senseless” JavaScript Features, presumably because he was listening to Kissing the Lipless by The Shins on repeat over Christmas. Me too, brother.

  10. Ryan Carniato wrote about JavaScript frameworks heading into 2024, but if you’re looking for a quicker TLDR, I recommend this 9-second excerpt from the safety instructions of a classic Disneyland ride.


Spot the Bug logo

Spot the Bug: Solution

return will stop the generator, so the second user will not be yielded which causes only the user object for Ben to be logged (instead of both Ben and Tyler). To fix this, use continue instead of return.

function* userGenerator(users) {
  for (let user of users) {
    if (!user.isActive) {
      continue;
    }
    yield user;
  }
}

const users = [
  { name: "Ben", isActive: true },
  { name: "Alex", isActive: false },
  { name: "Tyler", isActive: true },
];

const gen = userGenerator(users);

for (let user of gen) {
  console.log(user);
}