Exclusive tips every week

If you like Anthony's newsletter on Vue.js Developers, you'll enjoy this one, too.

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

    🔥 (226) Nuxt 4 is here! And NuxtLabs sold to Vercel!

    Lots of news recently in the Nuxt ecosystem!

    First, Nuxt 4 was released!

    You can read the official announcement here.

    Second, last week Vercel acquired NuxtLabs (not the Nuxt framework itself) and hired Daniel Roe (lead of Nuxt team), Sébastien Chopin (creator of Nuxt) and a few others from the Nuxt team.

    This is also huge news, and we covered it in our latest episode of DejaVue (scroll down a bit to find it).

    I'm working through my own thoughts on this and will have an article soon. But if you want more context, here are a bunch of links to check out:

    Also, check out this amazing video showing how Nuxt 4 was released.

    I've also got the regular tips and such here.

    Enjoy your week!

    — Michael

    🔥 Make Testing Easy

    Testing is important to do, but it can be hard to do.

    In my experience, good architecture lends itself to easy-to-write tests (or at least, easier-to-write). The inverse is also true, that difficult-to-write tests are typically a symptom of poor architecture.

    Of course, sometimes tests are just hard to write, and there’s no way around it.

    The best thing we can do is borrow a tool from mathematics and science, and transform a difficult problem into an easier but equivalent one:

    • Humble Components — UI is notoriously hard to test, and always has been. So keep as much in Humble Components, components that only receive props and emit events and nothing else. By making our UI as simple as possible we also make it much easier to test.
    • Extract logic to composables — And I mean all of your logic. Components (that aren’t Humble) should only contain the bare minimum to connect all the different composables together. Think of them as Controller Components, the “C” in MVC.
    • Composables are thin layers of reactivity — The easiest thing in the world to test are pure functions that have no dependencies. If you can make the majority of your codebase simple JS or TS code, you’ve already won. Composables then become simple wrappers that add a layer of reactivity to this business logic.

    🔥 Lightweight State Management

    We can add computed and methods directly on to a reactive object:

    const counter = reactive({
    count: 0,
    increment() {
    this.count += 1;
    },
    decrement() {
    this.count -= 1;
    },
    });

    This works because this is set to the object that the method is accessed through, which happens to be the reactive object.

    Vue’s reactivity system uses Proxies to watch for when a property is accessed and updated. In this case, we have a small overhead from accessing the method as a property on the object, but it doesn’t trigger any updates.

    If we had a whole series of counters we can reuse this over and over:

    const listOfCounters = [];
    for (const i = 0; i < 10; i++) {
    const counter = reactive({
    id: i,
    count: 0,
    increment() {
    this.count += 1;
    },
    decrement() {
    this.count -= 1;
    },
    })
    listOfCounters.push(counter);
    }

    In our template we can use the counters individually:

    <div v-for="counter in listOfCounters" :key="counter.id">
    <button @click="counter.decrement()">-</button>
    {{ counter.count }}
    <button @click="counter.increment()">+</button>
    </div>

    Instead of making the entire object reactive, we can use ref to make only our state reactive:

    const counter = {
    count: ref(0),
    increment() {
    this.count.value += 1;
    },
    decrement() {
    this.count.value -= 1;
    },
    };

    This saves us a small and likely unnoticeable overhead. But it also feels somewhat better since we’re being more thoughtful with our use of reactivity instead of spraying it everywhere.

    Here’s our example from before, but this time I’m going to add in a factory function to make it more readable:

    const createCounter = (i) => ({
    id: i,
    count: ref(0),
    increment() {
    this.count.value += 1;
    },
    decrement() {
    this.count.value -= 1;
    },
    });
    const listOfCounters = [];
    for (const i = 0; i < 10; i++) {
    listOfCounters.push(createCounter(i));
    }

    Of course, we can use a factory method with the previous reactive method as well.

    🔥 Using two script blocks

    The <script setup> sugar in Vue 3 is a really nice feature, but did you know you can use it and a regular <script> block?

    <script setup>
    // Composition API
    import { ref } from 'vue';
    console.log('Setting up new component instance');
    const count = ref(0);
    </script>
    <script>
    // ...and the options API too!
    export default {
    name: 'DoubleScript',
    };
    </script>

    This works because the <script setup> block is compiled into the component's setup() function.

    There are a few reasons why you might want to do this:

    • Use the options API — not everything has an equivalent in the composition API, like inheritAttrs. For these you can also use defineOptions.
    • Run setup code one time — because setup() is run for every component, if you have code that should only be executed once, you can't include it in <script setup>. You can put it inside the regular <script> block, though.
    • Named exports — sometimes, it's nice to export multiple things from one file, but you can only do that with the regular <script> block.

    Check out the docs for more info

    🎙️ #060 — Was Nuxt just sold?! (with Daniel Roe and Sébastien Chopin)

    In this special episode of DejaVue, Alexander and Michael are joined by Daniel Roe and Sébastien Chopin to discuss the recent acquisition of NuxtLabs by Vercel. Questions like "Was Nuxt just sold", "How much influence has Vercel", and "What is Vercel excepting from the deal" are answered.

    If you wonder what impact the deal has on Nuxt, you as a user and developer, as well as the open-source community, you should tune in! 

    Enjoy the Episode!

    Watch on YouTube or listen on your favorite podcast platform.

    In case you missed them:

    📜 Mastering Prose Components in Nuxt Content

    Prose components are perhaps one of the best features of Nuxt Content!

    In this article, we'll go through a few examples of how you can easily create your own.

    Check it out here: Mastering Prose Components in Nuxt Content

    📜 Dynamically Updating my Landing Page with Nuxt Content

    I recently spent some time updating the landing page for Clean Components Toolkit so that it will automatically update the outline as I update the course content itself.

    In this article, I'll show you how it's done.

    Check it out here: Dynamically Updating my Landing Page with Nuxt Content

    💬 First Do It

    "First do it, then do it right, then do it better." — Addy Osmani

    🧠 Spaced-repetition: Directly accessing parent components (and why)

    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.

    Props down, events up. That's how your components should communicate — most of the time.

    But in rare cases, that just doesn't work.

    If you need direct access to the parent component, you should just use provide/inject to pass down the relevant value or method:

    import { provide } from 'vue';
    const someMethodInTheParent = () => {};
    provide('method', someMethodInTheParent)

    Then, inject it into the child component:

    import { inject } from 'vue';
    const method = inject('method');
    method();

    In Vue 2, you can also use the instance property $parent:

    // Tight coupling like this is usually a bad idea
    this.$parent.methodOnParentComponent();

    This is simpler, but leads to higher coupling and will more easily break your application if you ever refactor.

    You can also get direct access to the application root, the very top-most component in the tree, by using $root. Vue 2 also has $children, but these were taken out for Vue 3 (please don't use this one).

    When would these be useful?

    There are a few different scenarios I can think of. Usually, when you want to abstract some behaviour and have it work "magically" behind the scenes.

    You don't want to use props and events to connect up a component in those cases. Instead, you use provide/inject, $parent, or $root, to automatically connect the components and make things happen.

    (This is similar to the Compound Component pattern)

    But it's hard to come up with an example where this is the best solution. Using provide/inject is almost always the better choice.

    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.