🔥 (#194) 7 Composable Design Patterns, CSS pseudo-selectors, and prose components

Read this on my blog

Hey!

This week I've got a new article for you on composable patterns.

You can read it here: 7 Composable Design Patterns

I'm also hard at work on the composable patterns course!

I'm planning to do an early access launch next week, with the full course available in early 2025. It will be a similar format as Clean Components Toolkit:

  • 5 patterns to start — with more in-depth patterns following for the full release
  • In-depth explanations — that explain when and how to use the pattern, edge cases, and variations
  • Real-world examples — with code examples that show how to actually use the pattern in practice

If you're interested in getting early access (and a special discount), you can sign up for the waitlist here: Composable Patterns Course Early Access

And if you haven't yet filled out the State of Vue.js Survey, please do! It takes less than 5 minutes and helps people in the community understand what you all want from the Vue ecosystem.

We've also got a new episode of the podcast on security with Jakub Andrzejewski.

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

Enjoy!

— Michael

🔥 Prose Components in Nuxt 3

With Nuxt Content 2 we can customize how Markdown gets rendered in our Nuxt 3 apps by creating our own custom Prose components.

We do get code highlighting built-in through Shiki, but I already have a custom theme for Prism.

So I needed to create a custom ProseCode component that used PrismJS to render the code blocks from my Markdown:

<template>    <pre :class="`language-${language}`"    ><code v-html="highlighted"></code></pre>  </template>
import Prism from 'prismjs';    const { code = '', language = null, filename = null, highlights = [] } = defineProps<{    code?: string;    language?: string | null;    filename?: string | null;    highlights?: Array<number>;  }>();    const highlighted = language    ? Prism.highlight(        code,        Prism.languages[language],        language      )    : code;

When we place this component in ~components/content and name it ProseCode, Nuxt Content knows to use it when rendering code blocks from Markdown.

We get a few props, and then use PrismJS to highlight it. This is all done on the server too, so our code is already highlighted before it hits the client.

Note: the formatting inside of the pre tag looks weird because it will preserve any formatting, including newlines. Moving the code element to the next line and indenting would cause the code rendered to the page to also have an extra newline and a few spaces in front of it.

You can create custom Prose components for most elements.

🔥 Special CSS pseudo-selectors in Vue

If you want some styles to apply specifically to slot content, you can do that with the :slotted pseudo-selector:

<style scoped>    /* Add margin to <p> tags within the slot */    :slotted(p) {      margin: 15px 5px;    }  </style>

You can also use :global to have styles apply to global scope, even within the

<style scoped>    :global(body) {      margin: 0;      padding: 0;      font-family: sans-serif;    }  </style>

Of course, if you have lots of global styles you want to add, it's probably easier to just add a second

<style scoped>    /* Add margin to <p> tags within the slot */    :slotted(p) {      margin: 15px 5px;    }  </style>    <style>    body {      margin: 0;      padding: 0;      font-family: sans-serif;    }  </style>

Check out the docs for more info.

🔥 How to watch anything in your component

It took me a very long time to realize this, but anything in your component that is reactive can be watched. This includes computed refs as well:

const first = ref('Michael');  const last = ref('Thiessen');  const fullName = computed(() => `${first.value} ${last.value}`);    watchEffect(() => console.log(fullName.value));

Maybe it's just me, but for some reason this wasn't all that intuitive at first for me.

With the Options API it looks like this:

export default {    computed: {      someComputedProperty() {        // Update the computed prop      },    },    watch: {      someComputedProperty() {        // Do something when the computed prop is updated      }    }  };

You can watch:

🎙️ #036 — Secure your Vue and Nuxt applications (with Jakub Andrzejewski)

Security is a topic that is often overlooked in the frontend world. But at least for you all - no longer! To make sure we cover Security for Vue and Nuxt applications as broad as possible, Michael and Alex are joined by Jakub Andrzejewski, who is not only a Senior Frontend Developer but also author of the Nuxt Security Module. We cover not only the module but also how to avoid common security mistakes as a Vue developer and how to protect your applications from vulnerabilities, and which are the most common ones.

Of course, we can't miss out on the State of Vue.js Survey, which is currently running and was co-created by Jakub as well!

Besides talking about the Security and the State of Vue.js, we also discuss how Jakub got into Vue.js at first and how he perceived the transition to Vue 3 and the Composition API.

Watch on YouTube or listen on your favorite podcast platform.

Chapters:

In case you missed them:

📜 Prisma with Nuxt: Seeding the Database with Dummy Data (3 of 5)

A database is useless without any data.

But with Prisma, adding in seed data (or "dummy" data) is extremely easy.

In this article we'll cover:

  • How to generate our Prisma client
  • How to update our Supabase database with migrations
  • How to add in dummy data

Check it out here: Prisma with Nuxt: Seeding the Database with Dummy Data (3 of 5)

📜 24 Time-Saving Tips for Nuxt

We know that Nuxt is a fantastic tool.

But it has so many amazing features that it's hard to keep track of them all.

That's why I've compiled this giant list of 24 Nuxt tips for you — use them to save time and write better Nuxt apps.

We cover a lot of topics here, including:

  • When to use /assets vs. /public directory
  • Using runtimeConfig vs. app.config
  • Understanding how Universal rendering works (and how it's different from SPA and SSR)
  • A utility to make your own NuxtLink components that no one is talking about
  • Adding a basic cache to your data fetching — since Nuxt doesn't do this by default

Of course, there is so much more!

Check it out here: 24 Time-Saving Tips for Nuxt

📅 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

💬 Bugs

"If debugging is the process of removing software bugs, then programming must be the process of putting them in." — Edsger Dijkstra

🧠 Spaced-repetition: Creating an If...Else Component

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.

Ever thought about making an If...Else component in Vue, despite having v-if, v-else, and v-else-if?

Here's a quirky experiment that explores this idea:

<If :val="mainCondition">    <template #true>Render if true</template>    <Else :if="false">Else if condition</Else>    <template #false>Otherwise render this</template>  </If>

This setup uses Compound Components, default and named slots, and even render functions to achieve a flexible If...Else logic.

The If component checks a condition and decides which slot (true, false, or Else) to render.

The Else component — a Compound Component — allows for an else if condition.

I have a detailed write up about this component on my blog.

Here's a simplified version for a cleaner API:

<If :val="condition">    <True>Truth</True>    <Else :if="elseCondition">Else slot</Else>    <False> What up false branch! </False>  </If>

This experiment is a fun way to dive deep into Vue's features like slots, reactivity, and component communication. While it might not replace the built-in directives, it's a great learning exercise and could inspire other creative component designs.

Check out the demo and maybe even try implementing your version: Vue If...Else Component Demo

Remember — experimenting with "weird" ideas is a fantastic way to deepen your understanding of Vue!

🔗 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