Exclusive tips every week

Join 13,567+ other Vue devs and get exclusive tips and insights delivered straight to your inbox, every week.

    Picture of Michael Thiessen

    đź‘‹Hey friend! I work hard to send you amazing stuff each week.

    — Michael

    I really love and enjoy reading these emails.

    You are one of the most pro VueJS devs I know, and I am happy that you share this knowledge.

    Fabian Beer

    Here's my latest newsletter

    🔥 (222) Destructuring in a v-for, Watching Nested Values, and Multiple v-models

    Read this on my blog

    Hey there,

    The stable release of Nuxt 4 is coming soon, and I'm busy getting Mastering Nuxt ready for it!

    Alex and I talked with Daniel Roe, the head of the Nuxt team, about the upcoming release of Nuxt 4. You can catch that Deja Vue episode below.

    With Mastering Nuxt we now have nine chapters of videos, with three more on the way. And all of it is updated and ready to work with Nuxt 4.

    Right now you can still get it with the early access discount, but once it's finished it will go up to full price.

    I wrote more about how that will work here: Master Nuxt 4 From Day One: No Waiting, No Outdated Content

    I also wrote an article based on a really fun lesson from the course where we use AI to generate the chat titles with a cool animation:

    Automatically Generate AI Chat Titles with Animation in Nuxt

    And as always, I've got some other tips and articles for you!

    — Michael

    🔥 Destructuring in a v-for

    Did you know that you can destructure in a v-for?

    <li
    v-for="{ name, id } in users"
    :key="id"
    >
    {{ name }}
    </li>

    It's more widely known that you can grab the index out of the v-for by using a tuple like this:

    <li v-for="(movie, index) in [
    'Lion King',
    'Frozen',
    'The Princess Bride'
    ]">
    {{ index + 1 }} - {{ movie }}
    </li>

    When using an object you can also grab the key:

    <li v-for="(value, key) in {
    name: 'Lion King',
    released: 2019,
    director: 'Jon Favreau',
    }">
    {{ key }}: {{ value }}
    </li>

    It's also possible to combine these two methods, grabbing the key as well as the index of the property:

    <li v-for="(value, key, index) in {
    name: 'Lion King',
    released: 2019,
    director: 'Jon Favreau',
    }">
    #{{ index + 1 }}. {{ key }}: {{ value }}
    </li>

    🔥 Watching Nested Values

    You may not have known this, but you can easily watch nested values directly when using the Options API, just by using quotes:

    watch: {
    '$route.query.id'() {
    // ...
    }
    }

    This is really useful for working with deeply nested objects!

    We can also watch nested values using the Composition API:

    watch(
    () => value.that.is.really.nested,
    () => {
    // ...
    }
    );

    🔥 Nuxt Layout Fallback

    If you’re dealing with a complex web app in Nuxt, you may want to change what the default layout is:

    <NuxtLayout fallback="differentDefault">
    <NuxtPage />
    </NuxtLayout>

    Normally, the NuxtLayout component will use the default layout if no other layout is specified — either through definePageMeta, setPageLayout, or directly on the NuxtLayout component itself.

    This is great for large apps where you can provide a different default layout for each part of your app.

    🎙️ #059 — Double Trouble: The Nuxt Surprise (with Daniel Roe)

    Big news in the Nuxt ecosystem. While you out there already know what has been announced - some of us didn't. Luckily, Daniel Roe, Head of the Nuxt team joins this DejaVue episode and discusses the highly anticipated "double trouble": Not one, but two major versions for Nuxt are on the horizon.

    After over a year of delays, Daniel reveals the strategic decision to release Nuxt 4 in less than a month from now, followed by Nuxt 5 which will include the long-awaited Nitro 3 integration and significant Vite improvements.

    The episode covers the smooth migration experience early adopters reported already, the philosophy behind careful breaking changes, and how the team plans to maintain a yearly major release cycle moving forward.

    Enjoy the Episode!

    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

    📜 Optimizing a Vue App

    Michelle does an excellent job of giving a high-level overview of best practices to keep your app speedy.

    Great as a starting off point or checklist for anyone looking to optimize their Vue app.

    Check it out here: Optimizing a Vue App

    đź’¬ Comments

    "Good code is its own best documentation. As you're about to add a comment, ask yourself, 'How can I improve the code so that this comment isn't needed?'" — Steve McConnell

    đź§  Spaced-repetition: Configurable Composables

    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.

    We can make our composables more reusable by passing in an object that contains all of the configuration options for how we want the composable to behave:

    const state = ref({ email: '' });
    const { history, undo, redo } = useRefHistory(state, {
    // Track history recursively
    deep: true,
    // Limit how many changes we save
    capacity: 10,
    });

    We use an object here instead of a long list of parameters:

    const { history, undo, redo } = useRefHistory(state, true, 10));

    Using an options object instead of parameters gives us several benefits.

    First, it’s self-documenting. We have the name of the parameter right beside the value, so we never forget what each value is doing.

    We can also create a type for the entire options object:

    export type RefHistoryOptions {
    deep?: boolean;
    capacity?: number;
    };
    export type RefHistoryReturn {
    history: Ref;
    undo: () => void;
    redo: () => void;
    };
    export function useRefHistory(
    ref: Ref,
    options: RefHistoryOptions
    ): RefHistoryReturn {};

    Second, we don’t need to worry about ordering or unused options. The more potential edge cases we cover with a composable, the more options we’ll have. But we usually only need to worry about a couple of them at one time — they’re all optional.

    Third, it’s much easier to add new options. Because the order doesn’t matter and none of the options are required, adding a new capability to our composable won’t break anything. We simply add it to the list of possible options and carry on.

    The pattern doesn’t require a lot of work to implement, either:

    export function useRefHistory(ref, options) {
    const {
    deep = false,
    capacity = Infinity,
    } = options;
    // ...
    };

    First, we pass in the options object as the last parameter. This makes it possible to have the options object itself as an optional parameter.

    The required params come first. Typically, there will only be one or two. More parameters is a code smell, and likely means that your composable is trying to do too much.

    The required parameter (or parameters) is very often a Ref, or a MaybeRef if we’re also implementing the Flexible Arguments Pattern.

    We then access the options by destructuring.

    Doing this gives us a really clean and readable way of providing defaults. Remember, these are options so they should all have defaults. If the values are required they should likely have

    This helps to clarify what options are being used in this composable. It’s not uncommon for one composable to use another composable, and in that case some of the options are simply passed along to the inner composable:

    export function useRefHistory(ref, options) {
    const {
    deep = false,
    capacity = Infinity,
    ...otherOptions,
    } = options;
    // Pass along some options we're not using directly
    useSomeOtherComposable(otherOptions);
    };

    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:

    Here's what others are saying

    I'm starting to think that your newsletter is one of the best things that happened to me this year. I just love these emails.
    Stanislaw Gregor
    I'm somewhere in the upper-middle level at Vue, and I never miss an email you and always find something cool when reading!
    Eduard Climov
    This is the first time where I'm actually enjoying email newsletters. I like your format a lot.
    Fahmi Alfituri
    You have great content in your emails. I seriously learn something from every one of them.
    Titus Decali
    Just wanted to say I enjoy these emails. They encourage me to constantly improve my craft. Fantastic work.
    Joe Radman
    Thanks for another beautiful tip 🙏
    Victor Martins Onuoha
    Loving these, and the spaced repetition.
    Mark Goldstein
    I really enjoy reading your emails, because I love Vue. Thanks for these emails.
    Arturo Espinoza
    I really love and enjoy reading these emails. You are one of the most pro VueJS devs I know, and I am happy that you share this knowledge.
    Fabian Beer
    THANK YOU! I did not know about the deep property, so I assumed you simply couldn't watch objects.
    Darryl Noakes
    I really must say you are doing a really great job. Now I am aware of a cleaner and more performant way to use Tailwind. Thanks a lot!
    Henry Eze
    Thank you so much, I really enjoy and appreciate your emails.
    Carlos Gonzalez
    Thanks for sharing great Vue tips.
    Fernando Navarro
    I really enjoy these tips.
    Martin H
    Thank you so much for the weekly Vue education. Thanks and live on longer to educate us more.
    Kabolobari Benakole
    I look forward to your emails every week. This week was something I knew, but I like to be reminded of. Thanks for keeping it up!
    Nathan Strutz
    Thank you for your weekly emails. I always look forward to learning a new tip about Vue or at least relearning old tips :)
    Colin Johnson
    I have really been enjoying your weekly emails, and I also got my two team members to join in on the fun as well.
    Keith Dawson
    Thank you for your newsletter, your explanations have very concise examples and I like it.
    Nicolas Decayeux
    Thanks A LOT for your great work!!! One of the few newsletters that I let pass!
    Martin Tillmann

    Want to level up your Vue skills?

    With over two million reads and 11,067 subscribers, you've come to the right place.

    Subscribe now to get exclusive insights and tips every week.