Read this on my blog Hey all! Not a whole lot to share this week. I've been enjoying the early spring here with my family as it warms up. A new podcast, some tips, and more as usual. — Michael 🔥 Easy Unit Testing in Nuxt For your unit tests, @nuxt/test-utils lets you opt-in to a Nuxt environment by adding .nuxt. to the filename of your test: ./tests/MyComponent.nuxt.test.ts
You can also add a special comment at the top of the file: @vitest-environment nuxt
Or enable the environment for all Vitest tests in your config: // vitest.config.ts import { defineVitestConfig } from '@nuxt/test-utils/config'; export default defineVitestConfig({ test: { environment: 'nuxt' }, };
🔥 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.
🔥 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: 🎙️ #054 — Open Source Sustainability (with Daniel Roe, Chad Whitacre & Rijk van Zanten) Join hosts Michael Thiessen and Alexander Lichter for a special episode of DejaVue - a fascinating panel discussion on open source sustainability with three open source enthusiasts: - Daniel Roe (Nuxt Team Lead)
- Chad Whitacre (Head of Open Source at Sentry)
- Rijk van Zanten (CTO and co-founder of Directus)
The panelists dive deep into what sustainability truly means in open source and get deep into the weeds of different licensing models, debating whether open source functions as a gift economy, and discuss the challenges of project governance. The panel also discusses important questions about leadership structures in open source projects, the role of companies in funding development, and practical ways everyone can contribute to making the ecosystem more sustainable - whether financially or through other meaningful contributions. Watch on YouTube or listen on your favorite podcast platform. Chapters: In case you missed them: 📜 What is Universal Rendering in Nuxt? Modern web development has brought forth two main types of applications: Single Page Apps (SPA) and Server Side Rendered apps (SSR). While each has its advantages, Nuxt offers a unique approach that combines the benefits of both types. This article delves deeper into the workings of SPAs, SSRs, and the innovative Universal Rendering of Nuxt. Check it out here: What is Universal Rendering in Nuxt? 📜 Make Your Components Easier to Think About I hate thinking. Well, actually, I love thinking, but only when I'm able to solve problems or make progress with it. But often our code gets in the way of this. And as one workshop attendee said about reading code, "if you're confused, it's not your fault." This article goes over some ways you can make your code easier to think about, so you're less confused and can actually get stuff done. Check it out here: Make Your Components Easier to Think About 📅 Upcoming Events Here are some upcoming events you might be interested in. Let me know if I've missed any! VueConf US 2025 — (May 13, 2025 to May 15, 2025) Giving a talk here on component patterns! A great Vue conference, this year held in Tampa. Two days of conference talks, plus a day for workshops. Check it out here MadVue 2025 — (May 29, 2025) It's time to get together in Madrid. Join for a full day of talks, activities, and networking with the Vue.js community and ecosystem. Check it out here 💬 The absence of bugs "Testing can only prove the presence of bugs, not their absence." — Edsger W. Dijkstra 🧠 Spaced-repetition: Nuxt Content Queries 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. Nuxt Content 2 gives us an effortless way to query our content using the queryContent method: // composables/useArticles.js export default () => queryContent('articles') .where({ // Optional fields that may be true or non-existent ghost: { $ne: true }, newsletter: { $ne: true }, // Don't render articles scheduled for the future date: { $lte: new Date() }, }) .only(['title', 'path', 'description', 'date', 'tags']) .sort({ date: -1 }) .find();
Here, I've created a composable called useArticles for my blog, which grabs all of the content inside of the content/articles/ directory. The queryContent composable is a query builder, which gives us a lot of expressiveness in what data we fetch. Let's see how we're using this here. First, we're using a where clause to filter out all the articles we don't want. Sometimes I will add an article before I want it to be "published" to the site. I do this by setting the date in the future and then only taking articles before "today" using this clause: date: { $lte: new Date() }
Second, some articles are the newsletters I write each week. Others are pieces of content that I want to keep in the articles folder but don't want to be published. I use frontmatter fields to specify this: --- newsletter: true # This is a newsletter ---
--- ghost: true # This content won't appear on the site ---
Third, we use the only clause to grab just the fields we need. By default, the queryContent method returns a lot of data, including the entire piece of content itself, so this can make a big difference in payload size. Lastly, as you have probably guessed, we have a sort clause to sort the articles so the most recent ones appear last. The queryContent composable has more options than this, which you can read about on the docs. 🔗 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: |
评论
发表评论