Building apps for the fancy face goggles

Issue #261.February 8, 2024.2 Minute read.
Bytes

Today’s issue: Big news for jQuery and Miley Cyrus fans, why hot module replacement is (not) easy, and my forthcoming screenplay about a developer who dared to dream.

Welcome to #261.


Eyeballs logo

The Main Thing

Adam Sandler dressed up as Scuba Steve from Big Daddy

Welcome to the metaverse, pal

Building apps for the fancy face goggles

Since the Apple Vision Pro launched last Friday, there’s been one thought on most people’s minds: Will my favorite niche tech influencer pretend to notice me if I spend 2 months rent to buy these?

Sadly, the answer is probably yes. But the economically savvy developers among us are asking a different question: How can we build apps for this thing and start making that sweet spatial cash ASAP?

You could learn Swift, but that sounds time-consuming and gross.

You could use React Native in Compatibility Mode, which lets you compile your app like you’re targeting an iPad and use it on VisionOS. This is pretty straightforward, but it limits you to showing rectangular screens in a room with only iPad functionality — no spatial computing features and no fancy transparent backgrounds.

But thanks to the mad lads at Callstack, we can now use React Native visionOS to build apps with full support for the VisionOS platform SDK.

This allows you to utilize the full capabilities of the VisionOS platform, like ImmersiveSpace, multi-window apps, and all the native-feeling UI elements that’ll make your RN app feel right at home next to the other VisionOS apps. This side-by-side comparison to Compatibility Mode lets you feel the difference.

How did they do it? When AVP was first announced last summer, the Callstack team quickly started creating an out-of-tree fork of the React Native core so it could extend to a new platform. This mostly consisted of adding compiler conditionals around code that aren’t supported on the VisionOS platform (check out the blog post for examples).

But it was still tricky for two reasons: 1) Many of the necessary build tools weren’t yet available for VisionOS, and 2) the Callstack team didn’t actually have the device itself to test on. They were able to work around those issues in the short term to release this experimental version of React Native visionOS, but the pace of development should increase now that AVP is out in the wild.

Bottom Line: The last time Apple gave us a new major computing platform, we saw some developers making $20,000 a day from apps like iBeer in the early years. Who knows if AVP will be as transformative as mobile computing — but if it is, you better believe I’m going to use RN visionOS to build some fully immersive iBeerGoggles.

        

Postman logo

Our Friends
(With Benefits)

A guy popping a wheelie on his seated lawnmower

Me omw to POST/CON

Get a 50% discount to POST/CON 24 (5 days left)

If you only go to one conference this year, make it POST/CON 24 in San Francisco on April 30-May 1.

Meet hundreds of industry leaders from the biggest software companies and master valuable skills during hands-on workshops, open labs, and expert talks on a variety of topics, including:

  • How to build and use dedicated AI APIs to create better software
  • How to streamline collaboration between frontend and backend devs, PMs, and testers
  • How to improve developer onboarding and write less documentation
  • How to build more robust end-to-end API testing systems

Get 50% off your ticket if you register before Feb. 13 — and kiss the FOMO goodbye.


Spot the Bug logo

Spot the Bug

Sponsored by CodeRabbit

Their AI-first code reviewer gives you context-aware review feedback on your PR’s, so you can reduce the time spent on manual code reviews and catch errors that you might otherwise miss.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>User Profile Template</title>
    <style>
      .profile {
        border: 1px solid #ddd;
        padding: 10px;
        margin-bottom: 10px;
      }
    </style>
  </head>
  <body>
    <template id="user-profile-template">
      <div class="profile">
        <img width="300" src="" alt="User Photo" />
        <p class="username"></p>
        <p class="email"></p>
      </div>
    </template>

    <script>
      const template = document.getElementById("user-profile-template").content;
      const userData = {
        username: "John Smith",
        email: "john.smith@thecompany.com",
        photoUrl:
          "https://images.unsplash.com/flagged/photo-1570612861542-284f4c12e75f",
      };

      const clone = template.cloneNode(true);

      clone.querySelector(".username").textContent = userData.username;
      clone.querySelector(".email").textContent = userData.email;
      clone.querySelector("img").src = userData.photoUrl;

      clone.addEventListener("click", () => {
        alert("Profile clicked");
      });

      document.body.appendChild(clone);
    </script>
  </body>
</html>

Cool Bits logo

Cool Bits

  1. The jQuery 4.0 beta just launched, and Miley Cyrus just won a Grammy for Record of the Year. The dream of 2012 is still alive.

  2. OneSchema built an embeddable CSV importer that’s easy to set up in your app and even easier for your customers to use. It’s incredibly performant at scale, comes with advanced data editing features, and saves teams 6 months (!!) of engineering time on average. [sponsored]

  3. Vite 5.1 is hot off the press today with a new runtime API, improved support for .css?url, improved HMR for circular import, and lots more.

  4. Bjorn Lu (a member of the Vite and Svelte core teams) wrote an in-depth post called Hot Module Replacement is Easy. Thankfully, he tells you upfront that it’s actually not easy at all — which helps you feel much better about yourself as you try to wrap your mind around the 4,100-word deep dive that follows.

  5. Remix just launched v2.6 and also open-sourced their website.

  6. Clerk created a full suite of embeddable UIs, flexible APIs, and admin dashboards, so you can build enterprise-ready authentication and user management in a few hours. Plus, their free tier gives you 10,000 monthly active users for free (no credit card required). [sponsored]

  7. Kadi Kraman wrote, What every dev should know about using Environment Variables on the new and improved Expo blog. It looks great and more importantly, it’s no longer hosted on Medium 🙏.

  8. Sadly, the same cannot be said of Flutter’s blog 💀 — but Craig Labenz did write an interesting deep dive on How and why Google Earth rewrote their mobile and web clients in Flutter.

  9. GSAP (GreenSock Animation Platform) just released a new React hook that solves a few React-specific pain points when building animations. They also made this 12-minute demo video on how it works.

  10. Stephanie Stimac wrote a quick post on Using CSS Media Query for scripting support. I’ve been looking for my own “scripting support”, since all those Hollywood snobs are apparently too cool for my screenplay about an indie developer who ignores the haters and makes it big with his hit Apple Vision Pro app, iBeerGoggles.


Spot the Bug logo

Spot the Bug: Solution

Sponsored by CodeRabbit

An HTML template returns a DocumentFragment. Since only its children are appended to the document, the event listener is not attached to the template. To fix this, the event listener should be attached to the DocumentFragment’s children.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>User Profile Template</title>
    <style>
      .profile {
        border: 1px solid #ddd;
        padding: 10px;
        margin-bottom: 10px;
      }
    </style>
  </head>
  <body>
    <template id="user-profile-template">
      <div class="profile">
        <img width="300" src="" alt="User Photo" />
        <p class="username"></p>
        <p class="email"></p>
      </div>
    </template>

    <script>
      const template = document.getElementById("user-profile-template").content;
      const userData = {
        username: "John Smith",
        email: "john.smith@thecompany.com",
        photoUrl:
          "https://images.unsplash.com/flagged/photo-1570612861542-284f4c12e75f",
      };

      const clone = template.cloneNode(true);

      clone.querySelector(".username").textContent = userData.username;
      clone.querySelector(".email").textContent = userData.email;
      clone.querySelector("img").src = userData.photoUrl;

      // Add the event listener to the profile div instead of the DocumentFragment
      clone.querySelector(".profile").addEventListener("click", () => {
        alert("Profile clicked");
      });

      document.body.appendChild(clone);
    </script>
  </body>
</html>