🔥 (#195) Vue Toronto Panel, Inline Composables, and Reactive SVGs

Read this on my blog

Hey!

I hope you're enjoying the last few weeks of 2024!

Yesterday, I opened up early access for my new course, Composable Design Patterns.

It's on a 35% off sale until Friday — after that, you'll have to wait until it's finished to get it (in early 2025).

Go here to learn more about it: Composable Design Patterns

In November, Alex and I did a panel at VueConf Toronto, and it was fantastic! We had four speakers, including Evan You, Daniel Roe, Sigrid Huemer and John Leider.

And of course, we've got some tips and more.

Enjoy!

— Michael

🔥 Inline Composables

You can define composables inline, keeping them in your SFC file:

<script setup>  const useCount = (i) => {    const count = ref(0);      const increment = () => count.value += 1;    const decrement = () => count.value -= 1;      return {      id: i,      count,      increment,      decrement,    };  };    const listOfCounters = [];  for (const i = 0; i < 10; i++) {    listOfCounters.push(useCount(i));  }  </script>  <template>    <div v-for="counter in listOfCounters" :key="counter.id">      <button @click="counter.decrement()">-</button>            <button @click="counter.increment()">+</button>    </div>  </template>

But is there any point to doing this?

If you're keeping your components focused on a specific task (and you should be), then it stands to reason that the logic is also focused on a single task.

This means that if you wrap up all relevant logic into an inline composable, you've wrapped up all — or nearly all — the logic that this component has:

<script setup>  // Create an inline composable  const useStuff = () => {    <all_our_logic>  };    // ...only to destructure most of it to use in our template  const {    value,    anotherValue,    eventHandler,    anotherEventHandler  } = useStuff();  </script>

At which point, we might as well write our logic without that unnecessary wrapper:

<script setup>  const value = ...  const anotherValue = ...  const eventHandler = ...  const anotherEventHandler = ...  </script>

However, if you have do have logic that can be encapsulated nicely within this inline composable, it could make your code cleaner and easier to use.

Using lexical scoping to create more boundaries within your files helps you to understand and think through your code, which is always helpful.

🔥 Reactive SVG components

SVGs can be reactive components, too.

After all, they're HTML elements just like div, span, and button.

Here's an SVG component that has a prop to change it's fill colour:

<template>    <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">      <circle cx="50" cy="50" r="50" :fill="color" />    </svg>  </template>  <script setup lang="ts">  defineProps<{    color: string  }>();  </script>

I'm sure you can build some pretty wild things if you dig into different SVG elements and attributes.

Scoped slots and SVGs? Why not...

Here's a demo if you want to see this example in action.

🔥 Components are Functions

Underneath it all, components are just functions that return some HTML.

It's a huge simplification, and if you've ever looked at the complexity of the Vue codebase you know this isn't actually true. But, fundamentally, this is what Vue is doing for us — plus a million other amazing things.

Take a look at this component:

<template>    <div>      <h1></h1>      <p>Some words that describe this thing</p>      <button>Clickity click!</button>    </div>  </template>

Now, here is some Javascript that does essentially the same thing:

function component(title) {    let html = '';      html += '<div>';    html += `<h1>${title}</h1>`;    html += '<p>Some words that describe this thing</p>';    html += '<button>Clickity click!</button>';    html += '</div>';      return html;  }

This code constructs the HTML in much the same way that the Vue component would.

Granted, we don't get reactivity, event handling, or a bunch of other features with this, but the HTML that gets output is the same thing.

This means that we can apply all of the patterns and experience from Javascript (and other languages) to our components. Things like breaking components down into smaller pieces, naming them well, and avoiding over-abstraction are all examples.

Of course, there are many more!

🎙️ #037 — VueConf Toronto Panel (with Evan You, Daniel Roe, Sigrid Huemer and John Leider)

For the first time, the DejaVue Podcast goes "live"! Alex and Michael met up at VueConf Toronto and could do a whole DejaVue episode on stage. Of course, this is even more fun with guests, so they are joined by four speakers of the Conference:

  • Evan You, Creator of Vue, Vite, Rolldown and Founder of VoidZero,
  • Daniel Roe, Lead of the Nuxt Team,
  • Sigrid Huemer, Software Engineer at Sentry, and
  • John Leider, Creator of Vuetify.

But that's not the end!

The audience could ask questions to the whole panel, while the DejaVue hosts curated and selected the most interesting ones.

Learn more about how all of the panelists started with Open Source, which were their biggest achievements, how Impostor Syndrome influenced them, what talks they'd be interested in as speakers and much more.

Watch on YouTube or listen on your favorite podcast platform.

Chapters:

In case you missed them:

📜 Nuxt: Pages vs. Layouts vs. Components

Nuxt comes with 3 different ways to organize your components: pages, layouts, and components.

It can be difficult to know which to use when, so I wrote this article to help explain the differences.

Check it out here: Nuxt: Pages vs. Layouts vs. Components

📜 Suspense: Everything You Need to Know

I wrote this article for VueSchool.io to clear up some misconceptions I've seen around Suspense.

If you load data in your application, I think you'll find it useful.

There are even some code demos so you can code along with the article!

Check it out here: Suspense: Everything You Need to Know

📅 Upcoming Events

Here are some upcoming events you might be interested in. Let me know if I've missed any!

Vuejs Amsterdam 2025 — (March 12, 2025 to March 13, 2025)

The biggest Vue conference in the world! A two-day event with workshops, speakers from around the world, and socializing.

Check it out here

VueConf US 2025 — (May 13, 2025 to May 15, 2025)

A great Vue conference, this year held in Tampa. Two days of conference talks, plus a day for workshops.

Check it out here

💬 Don't Change Anything

"A Fallacy of Software: If it works, and we don't change anything, it will keep working." — Jessica Kerr

🧠 Spaced-repetition: Nuxt's Powerful Built-In Storage

The best way to commit something to long-term memory is to periodically review it, gradually increasing the time between reviews 👨‍🔬

Actually remembering these tips is much more useful than just a quick distraction, so here's a tip from a couple weeks ago to jog your memory.

Nitro, the server that Nuxt 3 uses, comes with a very powerful key-value storage system:

const storage = useStorage();    // Save a value  await storage.setItem('some:key', value);    // Retrieve a value  const item = await storage.getItem('some:key');

It's not a replacement for a robust database, but it's perfect for temporary data or a caching layer.

One great application of this "session storage" is using it during an OAuth flow.

In the first step of the flow, we receive a state and a codeVerifier. In the second step, we receive a code along with the state again, which let's us use the codeVerifier to verify that the code is authentic.

We need to store the codeVerifier in between these steps, but only for a few minutes — perfect for Nitro's storage!

The first step in the /oauth endpoint we store the codeVerifier:

// ~/server/api/oauth    // ...  const storage = useStorage();  const key = `verifier:${state}`;  await storage.setItem(key, codeVerifier);  // ...

Then we retrieve it during the second step in the /callback endpoint:

// ~/server/api/callback    // ...  const storage = useStorage();  const key = `verifier:${state}`;  const codeVerifier = await storage.getItem(key);  // ...

A simple and easy solution, with no need to add a new table to our database and deal with an extra migration.

This just scratches the surface. Learn more about the unstorage package that powers this: https://github.com/unjs/unstorage

🔗 Want more Vue and Nuxt links?

Michael Hoffman curates a fantastic weekly newsletter with the best Vue and Nuxt links.

Sign up for it here.

p.s. I also have a bunch of products/courses:

Unsubscribe

评论

此博客中的热门博文

🔥 (#155) A Vue podcast?

Scripting News: Tuesday, February 13, 2024