<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alois Sečkár</title>
    <description>The latest articles on DEV Community by Alois Sečkár (@aloisseckar).</description>
    <link>https://dev.to/aloisseckar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1190890%2F4085b787-6249-4c48-b457-f9e915782b00.png</url>
      <title>DEV Community: Alois Sečkár</title>
      <link>https://dev.to/aloisseckar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aloisseckar"/>
    <language>en</language>
    <item>
      <title>New in Vue - March 2026</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 28 Mar 2026 11:49:43 +0000</pubDate>
      <link>https://dev.to/aloisseckar/new-in-vue-march-2025-2g74</link>
      <guid>https://dev.to/aloisseckar/new-in-vue-march-2025-2g74</guid>
      <description>&lt;p&gt;I &lt;a href="https://dev.to/aloisseckar/new-in-vue-february-2025-2kac"&gt;promissed&lt;/a&gt; new summary once &lt;a href="https://vuejs.amsterdam/" rel="noopener noreferrer"&gt;VueJS Amsterdam&lt;/a&gt; is over. It took me two weeks longer, but there we are. Hear, hear! I bring the latest Vue news.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" alt="New Vue newsletter launched" width="66" height="100"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Unfortunately, I must start with a sad announcement - the &lt;strong&gt;Weekly Vue News&lt;/strong&gt;, the invaluable source of inspiration for Vue devs are no more. Their long-time curator Michael Hoffmann &lt;a href="https://weekly-vue.news/issues/v2/205" rel="noopener noreferrer"&gt;called it quits&lt;/a&gt;. Let his hard work be remembered.&lt;/p&gt;

&lt;p&gt;But life goes on. And the life in the Vue ecosystem is everything but steady. So lets recap the new releases:&lt;/p&gt;

&lt;p&gt;The most significant one would be the &lt;a href="https://vite.dev/blog/announcing-vite8" rel="noopener noreferrer"&gt;&lt;strong&gt;Vite 8.0&lt;/strong&gt;&lt;/a&gt;. Why? Because Vite is nowadays fundament for modern JS development. And v8 brings important updates like using brand new and super-fast &lt;a href="https://rolldown.rs/" rel="noopener noreferrer"&gt;Rolldown&lt;/a&gt; bundler. There was a beta testing phase running since December, and now the stable version was made available.&lt;/p&gt;

&lt;p&gt;On top of that, there is &lt;a href="https://voidzero.dev/posts/announcing-vite-plus-alpha" rel="noopener noreferrer"&gt;&lt;strong&gt;Vite+&lt;/strong&gt;&lt;/a&gt; - a unified modern toolchain built with the latest available features as &lt;em&gt;"This is the way"&lt;/em&gt; of developing webapps in 2026. The current state of the project is Alpha with stable release expected soon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vitest&lt;/strong&gt;, the testing framework, couldn't stay behind and &lt;a href="https://vitest.dev/blog/vitest-4-1.html" rel="noopener noreferrer"&gt;released v4.1&lt;/a&gt;. Unlike the significant v4 update, this is rather a service update to natively support Vite v8. But there are also some new features to give a try. If you don't use Vitest in your project, you should think about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nuxt&lt;/strong&gt;, the #1 framework to go with Vue projects, continues its steady evolution, with &lt;a href="https://nuxt.com/blog/v4-4" rel="noopener noreferrer"&gt;v4.4&lt;/a&gt; being the latest release. With each minor version something new appears, although the changes are not really revolutionary. The same applies for &lt;strong&gt;Nuxt UI&lt;/strong&gt;, the official UI library - the &lt;a href="https://github.com/nuxt/ui/releases/tag/v4.5.0" rel="noopener noreferrer"&gt;v4.5&lt;/a&gt; and &lt;a href="https://github.com/nuxt/ui/releases/tag/v4.6.0" rel="noopener noreferrer"&gt;v4.6&lt;/a&gt; were released since my last newsletter. For smaller projects, you really don't need anything else to handle the appearance and basic UX.&lt;/p&gt;

&lt;p&gt;Nuxt already foresees its version 5. You can even opt in into future forward compatibility &lt;a href="https://nuxt.com/docs/4.x/guide/going-further/features#compatibilityversion" rel="noopener noreferrer"&gt;through a setting&lt;/a&gt;. One of the prerequisites is the finalization of &lt;strong&gt;Nitro v3&lt;/strong&gt; JS server engine. This milestone is now one step closer as its &lt;a href="https://nitro.build/blog/v3-beta" rel="noopener noreferrer"&gt;beta phase has started&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Among new tools, I want to point out first stable release of &lt;a href="https://pinia-colada.esm.dev/" rel="noopener noreferrer"&gt;&lt;strong&gt;Pinia Colada&lt;/strong&gt;&lt;/a&gt;, the advanced Vue solution for data fetching and state management. You probably have heard of Pinia, this brings the concept further created by the same author.&lt;/p&gt;

&lt;p&gt;I must not forget about &lt;a href="https://www.evlog.dev/" rel="noopener noreferrer"&gt;evlog&lt;/a&gt;, the new logging tool by Hugo Richard, one of the Nuxt team members. I haven't touched it yet, but I really want to do it soon. I really like the idea of having my logs better organized. Logging is generally hard - it doesn't matter until it's too late. Right?&lt;/p&gt;

&lt;p&gt;If you are trying to keep up with the times and use AI to boost your developer performance (which you absolutely should), this might be useful for you - Daniel Kelly from VueSchool wrote an article about &lt;a href="https://vueschool.io/articles/vuejs-tutorials/vue-agent-skills-for-reliable-ai-development/" rel="noopener noreferrer"&gt;Vue Agent skills&lt;/a&gt; that should gradually improve the quality of GenAI tools output.&lt;/p&gt;

&lt;p&gt;Last but not least, we have a &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/" rel="noopener noreferrer"&gt;new TypeScript version&lt;/a&gt;. Microsoft released its stable version 5 days ago. However, this version is considered rather a less important bridge on the way to v7, which is expected to be the real change after its core being rewritten to &lt;code&gt;Go&lt;/code&gt; language for better performance. So you don't necessarily need to drop everything and start migrating your codebases to v6.&lt;/p&gt;

&lt;p&gt;That's it for today. When I approach you the next time, I hope I would be able to share details about the &lt;a href="https://pragvue.com/" rel="noopener noreferrer"&gt;PragVue 2026&lt;/a&gt; conference we are about to organize for the third time already. Until then.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; fixed title from March 2025 to 2026. Thanks &lt;strong&gt;Arvind PJ&lt;/strong&gt; for spotting out.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Upcoming events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vueconf.us/" rel="noopener noreferrer"&gt;Vueconf.US 2026&lt;/a&gt; - &lt;strong&gt;19-21 May 2026&lt;/strong&gt;, Atlanta [USA]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://madvue.es/" rel="noopener noreferrer"&gt;MadVue 2026&lt;/a&gt; - &lt;strong&gt;22 May 2026&lt;/strong&gt;, Madrid [ESP]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Past issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-february-2025-2kac"&gt;February 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-december-2025-1hk0"&gt;December 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-november-2025-1l1b"&gt;November 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-october-2025-6i7"&gt;October 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-september-2025-4mef"&gt;September 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-august-2025-lip"&gt;August 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-july-2025-24id"&gt;July 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/aloisseckar"&gt;Follow me&lt;/a&gt; for more updates on Vue, Nuxt, Vite - and maybe even more!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>nuxt</category>
      <category>vite</category>
    </item>
    <item>
      <title>Speed of Vibes: We can turn bathroom ideas into features within minutes now</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 14 Feb 2026 21:15:44 +0000</pubDate>
      <link>https://dev.to/aloisseckar/speed-of-vibes-we-can-turn-bathroom-ideas-into-features-within-minutes-now-3dko</link>
      <guid>https://dev.to/aloisseckar/speed-of-vibes-we-can-turn-bathroom-ideas-into-features-within-minutes-now-3dko</guid>
      <description>&lt;p&gt;A month ago, I &lt;a href="https://dev.to/aloisseckar/ai-the-way-out-of-doubt-2fbg"&gt;wrote&lt;/a&gt; I am a &lt;em&gt;&lt;strong&gt;rational pessimist&lt;/strong&gt;&lt;/em&gt; about AI. Yesterday's dispute with my co-worker about unnecessary complexity of AI-infused &lt;em&gt;Korn shell&lt;/em&gt; script delivered by our other colleague reminded me there are also &lt;em&gt;&lt;strong&gt;radical pessimists&lt;/strong&gt;&lt;/em&gt; among us. However, every day when I dare to go further into the uncertain wilderness of imperfect prompts followed by indeterministic and &lt;em&gt;not-always-right&lt;/em&gt; responses, I see progress, new opportunities and new ways of doing better.&lt;/p&gt;

&lt;p&gt;Today, I have another success story to share.&lt;/p&gt;

&lt;p&gt;It started one evening after a workday recently. I came back from my daily dev job and went running to compensate for hours sitting in front of a screen. After the jogging session I was in a shower and suddenly got a cool idea for my side project.&lt;/p&gt;

&lt;p&gt;I thought it would be nice to provide to my future users a convenient way of reporting bugs. But also to make it convenient for me. I would be happiest to have reports appearing as GitHub issues. But teaching BFUs to login to GitHub and creating new issues in a consistent way? Good luck with that. So what if I just provide a simple form on my website and wire it to a backend service that will collect the input and create the issue automatically?&lt;/p&gt;

&lt;p&gt;Sounded like a plan. But imagine all the work you need to do. Putting together the form, writing the backend service, figuring out how the GitHub API works exactly to be able to call it... Let's just put the idea into the inner memory deep in the back of my brain and we will surely look at it. &lt;em&gt;One day. Not today...&lt;/em&gt; My inner demon of procrastination nearly won again.&lt;/p&gt;

&lt;p&gt;But times have changed lately. Now I am armed and dangerous with tireless AI companions. Despite all those legit complaints about coding agents not doing their job as good as you would hope and not nearly as great as AI-driven companies keep promising you, in early 2026 your favorite excuses &lt;em&gt;"I don't know how to start"&lt;/em&gt; or &lt;em&gt;"This task is too big to start it today"&lt;/em&gt; are no longer valid. You can always just kick off with a simple natural language prompt and see how it goes. Even the last season's truth that the prompt needs to be well designed (and thus you "cannot" start as &lt;em&gt;"I don't know how to write a correct prompt"&lt;/em&gt;) is fading out.&lt;/p&gt;

&lt;p&gt;Before going further, I'd like to make a statement. This &lt;strong&gt;doesn't&lt;/strong&gt; mean I am encouraging you to just fire ambiguous prompt and YOLO-deploy the first iteration right into the production.  &lt;a href="https://ai-manifesto.dev/" rel="noopener noreferrer"&gt;The AI Manifesto&lt;/a&gt; is still valid and &lt;strong&gt;you should always verify the results&lt;/strong&gt;, reason about code and understand everything before moving on. It is easier for me as a senior dev, but if you are a beginner, the more important it is before you get lost and become a hostage of a machine mind. On the other hand, you shouldn't hold yourself back too much. AI is there for you. Use it. Benefit from it. 💪🦾&lt;/p&gt;

&lt;p&gt;Before I finished bathing, ate dinner and socialized with my family, it was already getting quite late. But I was feeling lucky and wanted to try.&lt;/p&gt;

&lt;p&gt;Here is the prompt for my (paid) Copilot I quickly put together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I want a new feature in this Nuxt 4 project. I need a new client page 
"/report" with a Nuxt UI form entitled "Report problem" that will include 
text field for "gameLink", radio switching between "report false positive" 
and "report false negative", text field for "issue" and text area 
"description" for describing the issue to be reported. All fields will be 
mandatory. The filled form will be send to backend API route where it is 
validated and then a GitHub issue in &amp;lt;&amp;lt;REPO&amp;gt;&amp;gt; repository is created from 
given contents. Issue will be named by "issue" field and contain both 
"gameLink" and "description". Selected radio value will result into 
corresponding label (that will be prepared in the repositry). The report 
form is annonymous, there will be dedicated service account with access 
token to create the issues configurable via Nuxt runtime config (server-
side, so NOT public).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just this. No context engineering, no MCP servers, no skills or whatever. Just my codebase, internet connection and the rough task description in natural language with a few instructions and restrictions. Typos and grammar mistakes included.&lt;/p&gt;

&lt;p&gt;Maybe one thing. If you are AI-geek, you may have noticed new model &lt;a href="https://www.anthropic.com/news/claude-opus-4-6" rel="noopener noreferrer"&gt;Claude Opus 4.6&lt;/a&gt; was released recently. I did notice and I also decided this was a perfect opportunity to test it in action. And I wasn't disappointed.&lt;/p&gt;

&lt;p&gt;I spent two, maybe three minutes writing the prompt (while already have it more or less ready in my mind). Copilot with Claude took about 4 minutes to deliver the result. The surprising part was - the code was nearly perfect!&lt;/p&gt;

&lt;p&gt;I was trying, but I was unable to find any significant flaws. It created decent frontend form, it added Zod schema validation, it created backend endpoint, handled and validated the incoming data, put together the GitHub API call and wired the response back into the client. It even noticed there was no &lt;code&gt;&amp;lt;NuxtPage /&amp;gt;&lt;/code&gt; yet and made adjustments accordingly to support new &lt;code&gt;/report&lt;/code&gt; page along the existing (implicit) &lt;code&gt;/index&lt;/code&gt;. Yea, I might do some refactoring and polishing later, because looking back, the code might be more compact and less verbose. But overall it was not &lt;em&gt;glued together somehow until it accidentally worked&lt;/em&gt;. It was a decent job. I don't think I would do much better for the first iteration.&lt;/p&gt;

&lt;p&gt;My victory wasn't so flawless, because then I spent at least 30 more minutes configuring my new GitHub service account and getting the proper access token (AI-backed again). But overall it was less than an hour from the first keystroke to test issue successfully created in my repository. Wow! 👀&lt;/p&gt;

&lt;p&gt;There were a few success points that helped:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I knew what and how I want to do and I know &lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;Nuxt&lt;/a&gt; good enough to request general architecture with at least basic level of security (i.e. token must be kept on server-side and not exposed as public config).&lt;/li&gt;
&lt;li&gt;Copilot wasn't building from scratch but inside already established repository with configured Nuxt UI and existing server routes to copy from.&lt;/li&gt;
&lt;li&gt;People from Nuxt ecosystem are working hard to create AI-friendly solutions so it is much easier for agents to get relevant up-to-date information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I was hoping for good outcome, but this really amazed me. It reminded me that it already me who is being the bottleneck. My hesitation, my reluctance and my incompetence to delegate tasks that should be delegated without losing control. Despite I am still not scared about my very existence as some fellow devs seem to be, I was re-assured I should know much better. And I will keep trying to do so.&lt;/p&gt;

&lt;p&gt;What about you? What are your recent experiences with AI? Feel free to share your stories, questions, objections and concerns in the comments below 👇&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
    <item>
      <title>New in Vue - February 2025</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 07 Feb 2026 08:14:42 +0000</pubDate>
      <link>https://dev.to/aloisseckar/new-in-vue-february-2025-2kac</link>
      <guid>https://dev.to/aloisseckar/new-in-vue-february-2025-2kac</guid>
      <description>&lt;p&gt;As you probably didn't even notice, I skipped January issue of my wannabe monthly newsletter. I was in a hurry towards some deadlines, and I wrote 3 other articles in 2026 already. So I decided not to post some half-baked something last Saturday and to postpone the release. Today I am travelling by train from Prague to Ostrava, which is always a good opportunity for creative work. Here it comes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" alt="New Vue newsletter launched" width="66" height="100"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Nuxt began 2026 with a &lt;a href="https://nuxt.com/blog/v4-3" rel="noopener noreferrer"&gt;new minor release &lt;code&gt;4.3&lt;/code&gt;&lt;/a&gt;. Among numerous updates and improvements, it is now possible to opt-in into forthcoming &lt;strong&gt;v5&lt;/strong&gt; features via a setting. Nuxt v5 shouldn't be a revolutionary update with large API and behavior changes, but it will bring completely re-worked &lt;a href="https://v3.nitro.build/" rel="noopener noreferrer"&gt;Nitro v3&lt;/a&gt; server engine promising faster and more effective execution with a number of new cool features. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Patch version &lt;a href="https://github.com/nuxt/nuxt/releases/tag/v4.3.1" rel="noopener noreferrer"&gt;4.3.1&lt;/a&gt; landed just a few hours after I finished my overview.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Owners of larger projects also got a pleasant announcement about the official support for Nuxt v3 being extended by 6 months - from end of January to &lt;strong&gt;31 July 2026&lt;/strong&gt;. That gives everyone more time for migration efforts. Some are complaining that the support period should be even longer as production teams need more stability but remember Nuxt is an open source-project. Despite handful of the team members are now being paid by Vercel, the solution capacity is still limited. I would rather see new features being developed than legacy code being maintained indefinitely for (often non-paying) users.&lt;/p&gt;

&lt;p&gt;There are two new official Nuxt modules around the corner. &lt;a href="https://nuxt.com/modules/a11y" rel="noopener noreferrer"&gt;Nuxt Accessibility&lt;/a&gt; will focus on dealing with accessibility issues by providing ways of testing and giving hints during development. &lt;a href="https://nuxt.com/modules/hints" rel="noopener noreferrer"&gt;Nuxt Hints&lt;/a&gt; will go even beyond that and should provide &lt;em&gt;insights about your applications' performance, accessibility, and security&lt;/em&gt;. Both modules are now in alpha stage towards their v1 release which is expected soon.&lt;/p&gt;

&lt;p&gt;Formerly paid premium feature &lt;a href="https://content.nuxt.com/blog/studio-oss" rel="noopener noreferrer"&gt;Nuxt Studio&lt;/a&gt; was made free and fully open-sourced. The transition process started after &lt;a href="https://vercel.com/blog/nuxtlabs-joins-vercel" rel="noopener noreferrer"&gt;Vercel acquired NuxtLabs&lt;/a&gt; last summer and was finished at the dawn of 2026. Nuxt Studio used to be a way of making money for Nuxt development. As this is not necessary anymore, you have this advanced CMS solution at your disposal now.&lt;/p&gt;

&lt;p&gt;Adam Berecz announced his &lt;a href="https://vueform.com/news/20260108-announcing-vueform-2-0" rel="noopener noreferrer"&gt;Vueform 2.0&lt;/a&gt;. I learned about Vueform 11 months ago from his conference talk and I immideately liked it. Now it seems there will be a paradigm shift from more opinionated form-handling solution to a headless core that will allow smooth extension by almost any UI library. Looking forward to the result. Forms are a big (and somewhat painful) topic, and I am afraid I haven't picked my dream setup yet. Another player out there might be &lt;a href="https://formisch.dev/" rel="noopener noreferrer"&gt;Formisch&lt;/a&gt; which is being developed from last summer by Fabian Hiller, the author of Valibot validation library. But since &lt;a href="https://ui.nuxt.com/" rel="noopener noreferrer"&gt;Nuxt UI&lt;/a&gt; also opensourced their previously paid components, maybe their &lt;a href="https://ui.nuxt.com/docs/components/form" rel="noopener noreferrer"&gt;Form&lt;/a&gt; is all a Nuxter would need? I am planning to experiment on this theory a bit...&lt;/p&gt;

&lt;p&gt;Let's not forget about broader Vite ecosystem. As you may have heard, one of the fundamental parts of the ongoing improvement efforts is &lt;strong&gt;Rolldown&lt;/strong&gt;. The bundler written in Rust is made to be crazy fast and effective in building modern webapps. Vite version 8, which is already in beta stage &lt;a href="https://voidzero.dev/posts/announcing-vite-8-beta" rel="noopener noreferrer"&gt;since December&lt;/a&gt;, will be powered by Rolldown exclusively. And soon there will be standalone Rolldown release, we already have &lt;a href="https://voidzero.dev/posts/announcing-rolldown-rc" rel="noopener noreferrer"&gt;release candidates&lt;/a&gt;. And there is much more going on as you can see in the &lt;a href="https://voidzero.dev/posts/whats-new-jan-2026" rel="noopener noreferrer"&gt;fresh monthly summary&lt;/a&gt; by Alex Lichter.&lt;/p&gt;

&lt;p&gt;Last thing that caught my attention lately is &lt;a href="https://github.com/npmx-dev/npmx.dev" rel="noopener noreferrer"&gt;npmx&lt;/a&gt; - an alternative frontend to NPM package registry. It is an open-source project, currently under active development, that promises improved experience when browsing NPM packages. Not a competing repository and ecosystem, just an alternative frontend with additional features. I was satisfied with classic &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;https://www.npmjs.com/&lt;/a&gt;, but this seems as one of those updates you don't know you need until you get it. I will keep my eye on it.&lt;/p&gt;

&lt;p&gt;I plan to release the March issue after &lt;a href="https://vuejs.amsterdam/" rel="noopener noreferrer"&gt;VueJS Amsterdam conference&lt;/a&gt;. This year I am not travelling there in person, but I will keep my eye on the updates and I am sure there will be a lot of news to talk about. Take care until then!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Upcoming events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vuejs.amsterdam/" rel="noopener noreferrer"&gt;VueJS Amsterdam 2026&lt;/a&gt; - &lt;strong&gt;12-13 March 2026&lt;/strong&gt;, Amsterdam [NED]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vueconf.us/" rel="noopener noreferrer"&gt;Vueconf.US 2026&lt;/a&gt; - &lt;strong&gt;19-21 May 2026&lt;/strong&gt;, Atlanta [USA]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://madvue.es/" rel="noopener noreferrer"&gt;MadVue 2026&lt;/a&gt; - &lt;strong&gt;22 May 2026&lt;/strong&gt;, Madrid [ESP]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Past issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-december-2025-1hk0"&gt;December 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-november-2025-1l1b"&gt;November 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-october-2025-6i7"&gt;October 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-september-2025-4mef"&gt;September 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-august-2025-lip"&gt;August 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-july-2025-24id"&gt;July 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/aloisseckar"&gt;Follow me&lt;/a&gt; for more updates on Vue, Nuxt, Vite - and maybe even more!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>nuxt</category>
      <category>vite</category>
    </item>
    <item>
      <title>I cheated to maintain GitHub streak and I don't regret it</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 24 Jan 2026 14:13:23 +0000</pubDate>
      <link>https://dev.to/aloisseckar/i-cheated-to-maintain-github-streak-and-i-dont-regret-it-39ka</link>
      <guid>https://dev.to/aloisseckar/i-cheated-to-maintain-github-streak-and-i-dont-regret-it-39ka</guid>
      <description>&lt;p&gt;Since September 2022, I am actively trying to have a GitHub streak - every day at least one new contribution. And yes, I totally agree with you, &lt;a href="https://dev.to/sylwia-lask/your-github-contribution-graph-means-absolutely-nothing-and-heres-why-2kjc"&gt;it is meaningless&lt;/a&gt;. But it has a meaning for me. I want to do it, and I want to keep it. Even if some days the contribution has little to no value - like just adding a new article I have recently read into &lt;a href="https://master-coda.cz/" rel="noopener noreferrer"&gt;one of my news lists&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://github.com/DenverCoder1/github-readme-streak-stats" rel="noopener noreferrer"&gt;this widget&lt;/a&gt; to display the number of days on my GitHub profile. It was great until it stopped working some time ago. Some API changes probably. Maybe it'll come back eventually. But I didn't want to wait. I found &lt;a href="https://github.com/pranesh-2005/github-readme-stats-fast" rel="noopener noreferrer"&gt;an alternative&lt;/a&gt; that works here and now.&lt;/p&gt;

&lt;p&gt;Except it doesn't work the same way as the previous one and as the GitHub commit graph itself. It only counts "real" commits, it doesn't recognize code reviews.&lt;/p&gt;

&lt;p&gt;And this pointed out a flaw in my beloved streak. One day, June 1st, 2024, I somehow forgot to actually commit something. I "only" did two reviews for my Dependabot updates. I didn't notice, because when I opened GitHub page, the day was green. But my streak suddenly dropped by more than half 🥹&lt;/p&gt;

&lt;p&gt;I could have just let it go and accept the bitterness. But I didn't want to. The other day I did four commits! What if I just virtually travel back in time and alter one of them to fill in the gap? 💡&lt;/p&gt;

&lt;p&gt;And so I did. And the timeline was fixed. And I can enjoy my 1236 and counting streak. End of the story.&lt;/p&gt;

&lt;p&gt;But this wasn't meant to be just a confession. And I don't ask for redemption. The title says I don't regret it. Here I wanted to explain why not.&lt;/p&gt;

&lt;p&gt;Because due to this "cheating", I learned to know Git better than before. &lt;/p&gt;

&lt;p&gt;Git is one of those things you can adopt in a few minutes and then spend a lifetime trying to really understand it. Btw it took &lt;a href="https://www.zdnet.com/article/linus-torvalds-built-git-in-10-days-and-never-imagined-it-would-last-20-years/" rel="noopener noreferrer"&gt;just 10 days&lt;/a&gt; to forge this backbone on modern development. Stories like that keep reminding me how mediocre I actually am.&lt;/p&gt;

&lt;p&gt;To be able to change a year and half worth of my project Git history, I needed to understand how to work with &lt;code&gt;git rebase&lt;/code&gt; command. How to find the correct commit and how to alter it via the &lt;em&gt;interactive&lt;/em&gt; mode. The biggest Aha! moment was realizing that once you do this, you effectively &lt;strong&gt;erase the current history&lt;/strong&gt; starting from the altered commit and you'll get a new one. The changes and messages remain the same (except what was changed), but &lt;strong&gt;all commits will become new with new hashes&lt;/strong&gt;. I used &lt;code&gt;git rebase&lt;/code&gt; before, but only to fix very recent issues. So I successfully overlooked this fact. Now I am smarter.&lt;/p&gt;

&lt;p&gt;Another 🤯 thing I have learned is that when using GitHub, there are two commit dates - the original &lt;code&gt;Author Date&lt;/code&gt; (marking the point of time when the commit was created) and &lt;code&gt;Commit Date&lt;/code&gt; (changing when the commit gets edited - or rebased). I learned it the hard way after I &lt;em&gt;force-pushed&lt;/em&gt; my changes to GitHub and suddenly 150 commits were "made" on 17th January 2026 😰 &lt;/p&gt;

&lt;p&gt;That unfortunate event directly leads into my third discovery of existence of &lt;code&gt;git filter-branch&lt;/code&gt; command and (more modern) &lt;code&gt;git filter-repo&lt;/code&gt; tool. Those can be called into action to do bulk updates over commits. And help undone lapses like mine. So no worries, after another &lt;em&gt;trial-and-error&lt;/em&gt; session with Copilot, I managed to repair my flawed Git history, and you could never tell again.&lt;/p&gt;

&lt;p&gt;And that concludes my story. If you already knew all the above, good for you. It took me like 8 years of working with Git to dig that deep. I guess one can go even deeper, but I will take a break for a while. If you have stories to share or questions to ask, feel free to express them in the comments below. And stay tuned for another &lt;em&gt;Alois discovers trivial things&lt;/em&gt; article.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; You should be careful when tampering with your Git timeline and force-pushing something in the repository. If you have changes in other branches or even uncommitted in your local checkouts, you may get into trouble. If the team is bigger than just you, the troubles may be even bigger. I could afford to ignore those concerns as it was my private repo with no WIP. But this is not always the case.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>github</category>
      <category>git</category>
      <category>learning</category>
    </item>
    <item>
      <title>AI the way out of doubt</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 17 Jan 2026 08:17:54 +0000</pubDate>
      <link>https://dev.to/aloisseckar/ai-the-way-out-of-doubt-2fbg</link>
      <guid>https://dev.to/aloisseckar/ai-the-way-out-of-doubt-2fbg</guid>
      <description>&lt;p&gt;When it comes to AI, I believe to be a &lt;em&gt;rational pessimist&lt;/em&gt;. I am using AI-powered tools here and there, but I don't see it as a second coming of Jesus that would take our dev jobs and replace us. It is a useful tool, but only a tool. This is probably why I am always a bit behind the newest features and trends that keep emerging every week.&lt;/p&gt;

&lt;p&gt;On the other hand, I am not reluctant to AI either. I don't think it is crippling my mind not to write everything by hand and rather focus on the bigger picture than wiring all the boilerplate together. But finding the right tasks to be asked about or even delegated to AI-agent seems to be the biggest bottleneck in my workflows. I am being constrained by &lt;em&gt;too much thinking&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;While the other extreme - not thinking and all and just &lt;em&gt;vibe code&lt;/em&gt; the entire app and let it to production without any sanity and security checks   - might be even worse, not shipping anything, because you cannot decide how to put it together, is not the ideal outcome either. Whenever I manage to break from the circle, the positive results surprise me. I decided to write this article to share my latest small win achieved through AI. Maybe it inspires you too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scene
&lt;/h2&gt;

&lt;p&gt;I have a custom page where I collect and keep all my running since 2013 - where I run, how many meters and what time. I am just a casual runner, but  it's becoming decent set - nearly 2000 entries and closing to 12K kilometers. And it all can be tracked down to March 11th 2013, when I started with first 1825 meters in 9 minutes and 15 seconds.&lt;/p&gt;

&lt;p&gt;The website offers both displaying and filtering the records and the simple admin form, so I can add new record just after I stop running from my phone. It was evolving over the time from custom PHP glued to HTML page to being part of a Nuxt application with using my own &lt;a href="https://github.com/AloisSeckar/nuxt-neon" rel="noopener noreferrer"&gt;nuxt-neon module&lt;/a&gt; for database connection.&lt;/p&gt;

&lt;p&gt;It had one big flaw - for simplicity, I placed logic to frontend and then never troubled with moving the database operations to server-side. Because noone really cared about my running data, there was no urge to change it. I was always like &lt;em&gt;"yeah, I should do it"&lt;/em&gt;, but then always like &lt;em&gt;"but not today"&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The process
&lt;/h2&gt;

&lt;p&gt;Last Wednesday was another such day. &lt;/p&gt;

&lt;p&gt;Productive me: _I should do it now. I need some task for daily GitHub streak anyway."&lt;/p&gt;

&lt;p&gt;Lazy me: &lt;em&gt;But I am tired from coding all day at work. And surely some issues will arise and I will have to sort them out till midnight. Nah, let's play videogames instead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But then for some reason I got that little lightbulb above my head like in cartoons. &lt;strong&gt;What if I just try asking Copilot to refactor my code and see what happens?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I nearly fell in the &lt;em&gt;How to write the correct prompt?&lt;/em&gt; trap, but this time I didn't get distracted. I decided to apply KISS principle and see.&lt;/p&gt;

&lt;p&gt;Therefore, my first prompt was pretty straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Refactor "getTracks" and "getRuns" methods by moving them to Nuxt server side 
and expose as API routes under /server/routes/tracks.get.ts 
and /server/routes/runs.post.ts. Preserve the "filter" as POST input.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Few months ago, my newsfeed was full of articles about &lt;code&gt;prompt engineering&lt;/code&gt; or even &lt;code&gt;context engineering&lt;/code&gt; as an emerging must-have skill. But fast-forward to present. Your codebase is the context and even a mere Copilot (with Pro subscription) can understand simple prompts good enough to deliver expected results. I am using &lt;code&gt;Claude Sonet 4.5&lt;/code&gt; model recently, but I didn't really try any comparison with others.&lt;/p&gt;

&lt;p&gt;It was thinking and working for a while and then I got my refactor. Being aware of &lt;a href="https://ai-manifesto.dev/" rel="noopener noreferrer"&gt;The AI Manifesto&lt;/a&gt;, I didn't just accept the &lt;em&gt;something&lt;/em&gt; it spit out. I went through all changes carefully.&lt;/p&gt;

&lt;p&gt;This is a big advantage for us, seasoned devs - we can verify the results by understanding the code. Even if I am using AI to discover &lt;em&gt;how to do XY&lt;/em&gt;, I can follow up to some level and get a basic idea about what is going on. And I can challenge parts I truly don't understand, asking &lt;em&gt;What does this do?&lt;/em&gt; or &lt;em&gt;Why you put it there?&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;This time the code review was easier because I know how to write a Nitro route. I just took liberty not to since now I have a pocket junior dev who can do it for me. I wouldn't be bothering you with implementation details, I have a &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-0-introduction-4mli"&gt;series of Nuxt tutorials&lt;/a&gt; if you're interested.&lt;/p&gt;

&lt;p&gt;Anyway, the outcome exceeded the expectations. The delivered code was fine. The only issue that Copilot cannot foresee (unless I would ship an MCP server along with my nuxt-neon module) was that I recently split server- and client-side composable, so it must import &lt;code&gt;useNeonServer&lt;/code&gt; instead of &lt;code&gt;useNeonClient&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I fixed that manually. Towards Copilot, I had one additional remark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do we need "useAsyncData"? Shouldn't we be fine with "useFetch"?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was merely a cosmetic thing, the simpler way of achieving the same result - getting data from backend into frontend. And honestly, it was my fault, because I was using &lt;code&gt;useAsyncData&lt;/code&gt; in my code and gullible Copilot just copied it. But he also delivered a fix in no time.&lt;/p&gt;

&lt;p&gt;Reading data was secured at backend. Now I needed to do the same for adding new runs. My third prompt was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Going further. Lets also move "submitRun" method from client side Form.vue 
to new server side /server/routes/runs-add.post.ts and redirect client 
Vueform component to it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was fast including AI picked up change to &lt;code&gt;useNeonServer&lt;/code&gt; and mimicked it correctly. But a technical issue arose - because the data from input form are being posted as &lt;code&gt;multipart/form-data&lt;/code&gt;, standard Nitro &lt;code&gt;readBody&lt;/code&gt; method cannot be used for parsing the request. The correct method handling this case is &lt;code&gt;readFormData&lt;/code&gt;. Copilot helped me debug based on a simple console log and fixed the error itself.&lt;/p&gt;

&lt;p&gt;The last piece was to migrate function for deleting erroneous entries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Last refactor. Move "deleteRun" from Table.vue to backend to 
/server/run-delete.delete.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would have been a walk in the park, if I didn't misclicked to "undo" instead "keep" button and didn't accidentally erase all the changes 🙈 Fortunately, AI doesn't judge and swiftly re-created the edit.&lt;/p&gt;

&lt;p&gt;I spend some more time testing (and coming up with new refactoring ideas), but the job I was afraid to start was done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The outcome
&lt;/h2&gt;

&lt;p&gt;One evening, less than one hour, and the migration from vulnerable Nuxt frontend to more secured Nitro backend was completed. Most of the time I didn't write code, I was just reading and verifying what Copilot produced. &lt;/p&gt;

&lt;p&gt;The task I didn't want to start was finished before it could bother me. It was fun, it was useful and it moved me forward. Just wonder how many more tasks like this wait ahead. Let's find out.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>refactoring</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Nuxt Tutorial 8 - UI Integrations</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sun, 11 Jan 2026 15:32:27 +0000</pubDate>
      <link>https://dev.to/aloisseckar/nuxt-tutorial-7-ui-integrations-4mjm</link>
      <guid>https://dev.to/aloisseckar/nuxt-tutorial-7-ui-integrations-4mjm</guid>
      <description>&lt;p&gt;In the previous part we dealt with CSS; now we’ll move on to more advanced UI integrations. Just like with styling, you don’t necessarily need to reinvent the wheel. Instead of building every functional element from scratch, it’s usually easier to reach for a dedicated library.&lt;/p&gt;

&lt;p&gt;We’ll go through four practical integration examples. The selection isn’t driven by any deep logic - these are simply technologies I’ve come across and needed them in my Nuxt projects. Still, they demonstrate some general techniques you can reuse if you ever need to integrate something similar. At the end of the article, you’ll also find links to ready-made integrations for other well-known UI libraries from the Vue ecosystem. Let’s dive in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrap
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; used to be - and may still be - the most popular CSS framework for fast, responsive web development. It includes a set of predefined CSS classes, components, and JS plugins that make it easier to build modern design, responsive layouts, forms, navigation, and other interactive elements. It goes further than the previously covered &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a#tailwind-css"&gt;Tailwind CSS&lt;/a&gt;, which focuses solely on styling.&lt;/p&gt;

&lt;p&gt;Personally, I never really like it. If you’re starting today, I’d rather recommend combining Tailwind CSS with some library specialized in form controls (one of the next articles will cover those). But many developers are used to Bootstrap from earlier days, and of course Nuxt doesn’t prevent you from continuing to use it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;You can find some Bootstrap solutions in the Nuxt modules directory, but I had doubts about how up-to-date they are, so I chose a DIY approach via a &lt;a href="https://nuxt.com/docs/guide/directory-structure/plugins" rel="noopener noreferrer"&gt;Nuxt plugin&lt;/a&gt;. We haven’t covered plugins yet, but they’re an effective way to add new functionality to a base Nuxt app.&lt;/p&gt;

&lt;p&gt;A quick explanatory aside: Nuxt plugin in this context is a file in the &lt;code&gt;/app/plugins&lt;/code&gt; folder that can enrich the Nuxt instance - or even the underlying Vue.js app - via a dedicated function. Nuxt loads these files automatically and runs them at startup.&lt;/p&gt;

&lt;p&gt;In your project you need dependencies on the NPM package &lt;code&gt;bootstrap&lt;/code&gt; and on &lt;code&gt;sass&lt;/code&gt; (similar to &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a#open-props"&gt;Open Props&lt;/a&gt;, you’ll need some extra CSS processing for your input stylesheet and this is the recommended way). Import Bootstrap styles in the main &lt;code&gt;.scss&lt;/code&gt; file in &lt;code&gt;/app/assets/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* /app/assets/main.scss */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;'bootstrap/scss/bootstrap'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;nuxt.config.ts&lt;/code&gt; we must register this file via &lt;code&gt;css&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /nuxt.config.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/assets/main.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we also need a plugin that provides interactivity to the Nuxt app via Bootstrap JS. These three lines will do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /app/plugins/Bootstrap.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtPlugin&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;defineNuxtPlugin&lt;/code&gt; function is the handler mentioned above. Its callback receives the Nuxt app instance and lets you interact with it in various ways via its exposed API. For example, using &lt;code&gt;provide&lt;/code&gt; you can &lt;em&gt;provide&lt;/em&gt; everything that the &lt;code&gt;bootstrap&lt;/code&gt; package offers through its exports.&lt;/p&gt;

&lt;p&gt;You can find the source code of a simple example implementation here:&lt;br&gt;
&lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-bootstrap" rel="noopener noreferrer"&gt;nuxt-bootstrap @ GitHub&lt;/a&gt; and see it in action.&lt;/p&gt;
&lt;h2&gt;
  
  
  DevExtreme
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://js.devexpress.com/" rel="noopener noreferrer"&gt;DevExtreme&lt;/a&gt; UI library was first introduced to me by an &lt;em&gt;“Angular guy”&lt;/em&gt; colleague. It’s framework agnostic though, so you can use it in Vue as well. The main downside is obvious right away: it’s paid — and not cheap. On the other hand, we used it on a larger real-world project at work, and I have to say building complex nested forms (assembled entirely from scratch) was incredibly smooth with DevExtreme. Their layouts also made it reasonably responsive. The documentation is high quality too, although it took me a bit to learn how to navigate through it.&lt;/p&gt;

&lt;p&gt;Another small blemish is that for some reason &lt;code&gt;Dx&lt;/code&gt; components don’t work with &lt;em&gt;Server-Side Rendering&lt;/em&gt; - or at least, even after several years I never figured out what needed to be done. So you need to set &lt;code&gt;ssr: false&lt;/code&gt; and accept that the app will render via JavaScript only in the client’s browser. That makes it more suitable for SPAs (Single Page Applications), where users treat the website more like a desktop application and are willing to wait a bit for the content to load - which was our case. For projects where loading speed and SEO are critical (typically e-shops), it might not be the best fit.&lt;/p&gt;
&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;package.json&lt;/code&gt; you need to reference the base NPM package &lt;code&gt;devextreme&lt;/code&gt; and its Vue port &lt;code&gt;devextreme-vue&lt;/code&gt;. That alone is enough for local development, but the problem is that &lt;em&gt;“tree-shaking”&lt;/em&gt; (removing unused dependencies from the production build) doesn’t recognize you’re using its components, and it happily strips all the definitions out of the final bundle.&lt;/p&gt;

&lt;p&gt;I struggled with this for quite a while and eventually had to &lt;a href="https://github.com/nuxt/nuxt/discussions/16898" rel="noopener noreferrer"&gt;get help&lt;/a&gt;. The key is, again, a Nuxt plugin where you gradually register the DevExtreme components you want to use as Vue components. I strongly recommend registering them under the same names DevExtreme uses — otherwise you lose the ability to easily search their documentation.&lt;/p&gt;

&lt;p&gt;In this example I only use a basic button, but the principle is the same for everything else:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /app/plugins/DevExtreme.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DxButton&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devextreme-vue/button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtPlugin&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vueApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;DxButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DxButton&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;DxButton&lt;/code&gt; component then becomes globally available in all your app’s component templates, and you can use it anywhere exactly as described in the DevExtreme documentation without additional constraints.&lt;/p&gt;

&lt;p&gt;You can find the source code of the example implementation here:&lt;br&gt;
&lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-dx" rel="noopener noreferrer"&gt;nuxt-dx @ GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After starting the app, you’ll notice a very prominent license warning in the header that DevExtreme injects into the unregistered version. That’s a reminder that without a purchased license, this integration won’t help you much. Still, we’ve demonstrated the general principle of using plugins to add &lt;strong&gt;any&lt;/strong&gt; external Vue components into Nuxt.&lt;/p&gt;
&lt;h2&gt;
  
  
  FontAwesome
&lt;/h2&gt;

&lt;p&gt;After general-purpose UI libraries, let’s move to &lt;a href="https://fontawesome.com/" rel="noopener noreferrer"&gt;FontAwesome&lt;/a&gt;, a popular solution for displaying icons on websites and in apps. It provides a wide selection of vector icons in SVG form (and also as font files) that you can easily use via CSS. FontAwesome allows simple manipulation of icons: changing size, color, and more.&lt;/p&gt;

&lt;p&gt;“FA” used to be an evergreen in web design a few years ago, similar to Bootstrap. I think it’s past its peak too, but let’s still take a look. Since the time I solved the integration manually, a &lt;a href="https://nuxt.com/modules/nuxt-fontawesome" rel="noopener noreferrer"&gt;module&lt;/a&gt; has been created, so it may be easier today than what I describe below. My solution requires at least three new dependencies in &lt;code&gt;package.json&lt;/code&gt; (more if you want to use icons from additional (paid!) sets), and overall it feels a bit clunky to me. But if you’re used to it and can list FontAwesome icon names off the top of your head, you can bring it into Nuxt with you.&lt;/p&gt;

&lt;p&gt;The downside is that, like DevExtreme, FontAwesome doesn’t play nicely with Nuxt SSR, so you need to set &lt;code&gt;ssr: false&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;I integrated FA into a Nuxt project using a plugin again. This time it’s a bit less intuitive: you first extend the &lt;code&gt;library&lt;/code&gt; object with the icon definitions you want to use, then take the &lt;code&gt;FontAwesomeIcon&lt;/code&gt; object (from another FA package) and register it as a Vue component inside your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// /app/plugins/FontAwesome.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;faEnvelope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;faFaceSmile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;faHouse&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fortawesome/free-solid-svg-icons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;library&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fortawesome/fontawesome-svg-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FontAwesomeIcon&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@fortawesome/vue-fontawesome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// these icons will be available as values for the "icon" attribute&lt;/span&gt;
&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;faEnvelope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;faFaceSmile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;faHouse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// register the "fa" component&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtPlugin&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;nuxtApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vueApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FontAwesomeIcon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In component templates you can then use the &lt;code&gt;&amp;lt;fa&amp;gt;&lt;/code&gt; component like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;fa&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"envelope"&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"FA 'envelope' icon"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the source code of the example implementation here:&lt;br&gt;
&lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-fa" rel="noopener noreferrer"&gt;nuxt-fa @ GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Icônes
&lt;/h2&gt;

&lt;p&gt;Because I don’t consider the solution above particularly good, I’d like to immediately present an alternative. &lt;a href="https://icones.js.org/" rel="noopener noreferrer"&gt;Icônes&lt;/a&gt; is a project focused on providing a large collection of icons for websites and apps. It offers a wide selection of SVG vector icons that are easy to use and customize. Icônes makes icon integration simpler and helps improve the visual quality of user interfaces.&lt;/p&gt;

&lt;p&gt;If you ask me what to use for icons, I’ll recommend &lt;strong&gt;Icônes&lt;/strong&gt; without hesitation. It gives you an easy way to get SVG-based definitions that are portable across environments, requires no new dependencies, and offers a huge library of icon definitions &lt;strong&gt;for free&lt;/strong&gt;. In Nuxt - or rather, directly in Vue - you can introduce each icon as its own component. If you’re not using a UI library that handles icons in its own way (see e.g. the upcoming article about Nuxt UI), this is an excellent lightweight option that lets you use only what you actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;Unlike previous, this truly works without &lt;strong&gt;any&lt;/strong&gt; external dependency. You simply find the icon you want on the &lt;a href="https://icones.js.org/" rel="noopener noreferrer"&gt;Icônes&lt;/a&gt; website and export the source code directly as a Vue component. In my demo, three selected icons are copied this way into the &lt;code&gt;/components&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;You can find the source code of the example implementation here:&lt;br&gt;
&lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-icones" rel="noopener noreferrer"&gt;nuxt-icones @ GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Universal icon component
&lt;/h3&gt;

&lt;p&gt;You may have noticed (as I did) that these generated components look almost identical and differ only in their &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; definitions.&lt;/p&gt;

&lt;p&gt;In another project, I therefore have a &lt;a href="https://github.com/AloisSeckar/ELRHistory/blob/main/app/components/BaseIcon.vue" rel="noopener noreferrer"&gt;component&lt;/a&gt; that renders one of predefined Icônes icons based on a definition from a &lt;a href="https://github.com/AloisSeckar/ELRHistory/blob/main/app/assets/icones.json" rel="noopener noreferrer"&gt;data file&lt;/a&gt;. When the app needs a new icon, a new definition is added into the JSON file and linked from icon component. Feel free to use this idea as inspiration in your own projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;In this article, we saw four examples of integrating external UI libraries into a Nuxt app. It’s definitely not an exhaustive list of your options, but I think it’s a solid starting point for inspiration.&lt;/p&gt;

&lt;p&gt;In many cases, there’s already a ready-made Nuxt module for popular technologies that handles the integration for you. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nuxt.com/modules/vuetify-nuxt-module" rel="noopener noreferrer"&gt;Vuetify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuxt.com/modules/primevue" rel="noopener noreferrer"&gt;PrimeVue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nuxt.com/modules/quasar" rel="noopener noreferrer"&gt;Quasar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don’t have personal experience with any of these, but you’ll surely find support in the active and friendly Nuxt community. And if you have a favorite CSS framework or UI library and you’re missing a Nuxt setup guide, reach me through a comment below and we can try to figure out the integration.&lt;/p&gt;

&lt;p&gt;Next time, we’ll take a closer look at one more option that I intentionally left out so far - and also quickly adopted as my own: the &lt;strong&gt;Nuxt UI module&lt;/strong&gt; directly from the Nuxt team.&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>New in Vue - December 2025</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Mon, 29 Dec 2025 15:14:09 +0000</pubDate>
      <link>https://dev.to/aloisseckar/new-in-vue-december-2025-1hk0</link>
      <guid>https://dev.to/aloisseckar/new-in-vue-december-2025-1hk0</guid>
      <description>&lt;p&gt;Hi, everyone. This will be my 24th and last article in 2025. I wish you all a great start into the upcoming New year 2026 and before it happens, let's do this quick recap of latest development in the &lt;strong&gt;Vue&lt;/strong&gt; / &lt;strong&gt;Nuxt&lt;/strong&gt; / &lt;strong&gt;Vite&lt;/strong&gt; world once again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" alt="New Vue newsletter launched" width="66" height="100"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Vue&lt;/strong&gt; will probably end 2025 in maintenance version &lt;strong&gt;3.5.26&lt;/strong&gt;. Vue &lt;strong&gt;v3.5&lt;/strong&gt; was &lt;a href="https://blog.vuejs.org/posts/vue-3-5" rel="noopener noreferrer"&gt;released&lt;/a&gt; more than a year ago, so we can say the fundament of our ecosystem is pretty solid and stable right now. Bugs are being fixed, dependencies patched, and minor tweaks appear from time to time, but overall the code base has been settled and we can develop without worrying we will have to rebuild everything every few months.&lt;/p&gt;

&lt;p&gt;I am not even aware of any ground-breaking changes under development, besides long anticipated &lt;strong&gt;Vapor mode&lt;/strong&gt;, a new strategy for faster components' rendering. This will land in &lt;strong&gt;Vue 3.6&lt;/strong&gt; whose beta release &lt;a href="https://github.com/vuejs/core/releases/tag/v3.6.0-beta.1" rel="noopener noreferrer"&gt;appeared right before Christmas&lt;/a&gt;. If you want to know more, there is &lt;a href="https://vueschool.io/articles/news/vn-talk-evan-you-preview-of-vue-3-6-vapor-mode/" rel="noopener noreferrer"&gt;an article&lt;/a&gt; by Evan You himself. It was released in March though, so you can see the whole process takes its time.&lt;/p&gt;

&lt;p&gt;I would say a solid portion of development effort was re-directed to &lt;strong&gt;Vite&lt;/strong&gt;, the build tool originally designed for &lt;strong&gt;Vue&lt;/strong&gt; which but overgrew into viable cornerstone of JavaScript development. And it is growing further as you can follow at the &lt;a href="https://voidzero.dev/blog" rel="noopener noreferrer"&gt;Void(0) blog page&lt;/a&gt;. &lt;strong&gt;Vite&lt;/strong&gt; itself is now available in version &lt;strong&gt;7.3&lt;/strong&gt; with upcoming &lt;strong&gt;v8&lt;/strong&gt; &lt;a href="https://github.com/vitejs/vite/blob/v8.0.0-beta.5/packages/vite/CHANGELOG.md" rel="noopener noreferrer"&gt;iterating&lt;/a&gt; towards the final release. Everything you need to know about Vite v8, is &lt;a href="https://vite.dev/blog/announcing-vite8-beta" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, &lt;strong&gt;Nuxt&lt;/strong&gt; release cycle slowed down a bit in the last couple of weeks. Recent &lt;strong&gt;v4.2&lt;/strong&gt; is here with us for &lt;a href="https://nuxt.com/blog/v4-2" rel="noopener noreferrer"&gt;2 months already&lt;/a&gt; with second patch release &lt;strong&gt;4.2.2&lt;/strong&gt; being the last available version. Former v3 is still being maintained with backported version released together with v4 (&lt;strong&gt;3.20.2&lt;/strong&gt; is the most recent), but the scheduled EOL date (2026-01-31) is &lt;a href="https://github.com/nuxt/nuxt/discussions/33918" rel="noopener noreferrer"&gt;getting close&lt;/a&gt;. The relative stability is the good news, as it means other parts of the ecosystem as various modules may catch up and stabilize themselves around the latest releases too. Meanwhile, new major Nuxt version 5 is somewhere out there in the distance, probably closer than you fear, but farther then you hope. Or maybe vice versa, if you don't want to migrate again (though it is promised it should be easy and straightforward). Anyway, we'll see what happens in 2026.&lt;/p&gt;

&lt;p&gt;Aside vanilla framework, Nuxt offers a number of wonderful modules to extend the core functionality. One of the most prominent official ones is &lt;strong&gt;Nuxt UI&lt;/strong&gt;, the UI toolkit. The library keeps evolving, with latest version &lt;a href="https://github.com/nuxt/ui/releases/tag/v4.3.0" rel="noopener noreferrer"&gt;4.3&lt;/a&gt;, that was released on 17th December. If you pick it for your next project, you may benefit from &lt;a href="https://vueschool.io/articles/vuejs-tutorials/setting-up-your-ide-for-nuxt-ui-a-complete-guide/" rel="noopener noreferrer"&gt;this practical guide&lt;/a&gt; about how to set up your IDE. Actually, you should check the article anyway, because many tips apply to Vue/Nuxt development in general. And I can confirm I was already using most of the extensions mentioned - they're valid and battle-tested.&lt;/p&gt;

&lt;p&gt;If you want to receive ecosystem updates more often than once in a month, there are &lt;a href="https://weekly-vue.news/" rel="noopener noreferrer"&gt;Weekly Vue News&lt;/a&gt;, an email newsletter being delivered each Monday. I certainly recommend you to subscribe, as I am getting a lot of inspirations from there.&lt;/p&gt;

&lt;p&gt;Last but not least I want to spotlight a &lt;a href="https://snyk.io/articles/npm-security-best-practices-shai-hulud-attack/" rel="noopener noreferrer"&gt;comprehensive NPM security guide&lt;/a&gt; composed by cybersecurity expert Liran Tal. In the woke of recent supply-chain attacks outbreak it is always good to remind and revise strategies to keep your projects safer. &lt;/p&gt;

&lt;p&gt;Stay safe, have a great rest of 2025 and a successful start into 2026. See you again in the New year! 🫡&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Upcoming events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vuejs.amsterdam/" rel="noopener noreferrer"&gt;VueJS Amsterdam 2026&lt;/a&gt; - &lt;strong&gt;12-13 March 2026&lt;/strong&gt;, Amsterdam [NED]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vueconf.us/" rel="noopener noreferrer"&gt;Vueconf.US 2026&lt;/a&gt; - &lt;strong&gt;19-21 May 2026&lt;/strong&gt;, Atlanta [USA]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://madvue.es/" rel="noopener noreferrer"&gt;MadVue 2026&lt;/a&gt; - &lt;strong&gt;22 May 2026&lt;/strong&gt;, Madrid [ESP]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Past issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-november-2025-1l1b"&gt;November 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-october-2025-6i7"&gt;October 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-september-2025-4mef"&gt;September 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-august-2025-lip"&gt;August 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-july-2025-24id"&gt;July 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/aloisseckar"&gt;Follow me&lt;/a&gt; for more updates on Vue, Nuxt, Vite - and maybe even more!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>nuxt</category>
      <category>vite</category>
    </item>
    <item>
      <title>Nuxt Tutorial 7 - Adopting CSS</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sun, 21 Dec 2025 17:46:39 +0000</pubDate>
      <link>https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a</link>
      <guid>https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a</guid>
      <description>&lt;p&gt;We already know how to get a Nuxt application up and running and how to use the various building blocks to assemble it. Now it's time to give our pages a reasonably decent look. In theory, we could handle that ourselves - using CSS styles defined inside the &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; sections of individual components. If you're confident with CSS, you can have a nice-looking website pretty quickly.&lt;/p&gt;

&lt;p&gt;Most of the time, though, we don't want to rebuild everything from scratch. In this article you'll first see how easy it is to import ready-made CSS files, and then we'll go through two example integrations with projects that make styling much easier: &lt;code&gt;Tailwind CSS&lt;/code&gt; and &lt;code&gt;Open Props&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Import CSS
&lt;/h2&gt;

&lt;p&gt;If you're migrating an older project, you might already have your &lt;code&gt;.css&lt;/code&gt; style files ready. Or you may be using a service that ships its styles as a standalone &lt;code&gt;.css&lt;/code&gt; file (i.e. when &lt;a href="https://getbootstrap.com/docs/5.3/getting-started/download/#cdn-via-jsdelivr" rel="noopener noreferrer"&gt;using Bootstrap from a CDN&lt;/a&gt;). Nuxt offers a very simple integration for these cases.&lt;/p&gt;

&lt;p&gt;Upload your style files into the &lt;code&gt;/app/assets&lt;/code&gt; folder (usually into &lt;code&gt;/css&lt;/code&gt; sub-directory for better clarity). Then reference them via the &lt;code&gt;css&lt;/code&gt; option in your &lt;code&gt;nuxt.config.ts&lt;/code&gt; config file, i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/assets/css/main.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The imported styles are then automatically available across the whole application.&lt;/p&gt;

&lt;p&gt;If needed, you can also load them individually per component - either in the &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/assets/css/main.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or inside &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="sx"&gt;url("~/assets/css/main.css")&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Little sidenote: In example above I added &lt;code&gt;scoped&lt;/code&gt; attribute to denote the style sheet should only be relevant for the component file itself. Otherwise the styles would leak globally. While this may be a bad thing, you can also do it on purpose (preferably in &lt;code&gt;app.vue&lt;/code&gt;) and make your styles available throughout the whole application. More common is to use the &lt;code&gt;css&lt;/code&gt; option in Nuxt config though.&lt;/p&gt;

&lt;p&gt;Even with just this, you can achieve quite a lot. For examples of integrations with more advanced CSS libraries, keep reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tailwind CSS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; is a CSS framework for styling websites and applications. Unlike the traditional CSS approach, you don't write your own classes; instead, you compose the final look from a large set of predefined utility classes, which enables fast and flexible styling and layouts. Tailwind itself is also highly adaptable and configurable - for example when it comes to defining color schemes.&lt;/p&gt;

&lt;p&gt;It deserves an article of its own (which I originally planned, and maybe I'll get to it eventually). For me it's currently the number one choice for building a website's look. It requires a slightly different philosophy, but I adjusted in a day, and I don't want to do it any other way now. I migrated couple of my personal projects to Tailwind CSS already, where the original design was done “by hand”. Converting them into the corresponding Tailwind structure usually took just one evening.&lt;/p&gt;

&lt;p&gt;It's fair to note it's not a CSS framework “for purists” because it does impose some constraints. Others criticize it for creating too much abstraction and giving users the illusion that they understand what they're doing - until they hit a trap they can't resolve because they don't really know the underlying CSS. My experience, however, is that it will be enough in vast majority of situations, and its efficiency gives you more time to handle the remaining edge cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;Getting started with Tailwind CSS is now very straightforward. The creators ship a plugin for Vite (the build tool Nuxt uses), which you just install together with the main library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;tailwindcss @tailwindcss/vite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the plugin to &lt;code&gt;nuxt.config.ts&lt;/code&gt; along with a reference to the CSS file that imports Tailwind:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tailwindcss/vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineNuxtConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// Vite integration plugin&lt;/span&gt;
  &lt;span class="na"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;tailwindcss&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// CSS file importing Tailwind classes&lt;/span&gt;
  &lt;span class="na"&gt;css&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;~/assets/css/tailwind.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;// other config...&lt;/span&gt;

&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is creating a simple CSS file that you load via the &lt;code&gt;css&lt;/code&gt; option. Its content can be as minimal as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Demo app
&lt;/h3&gt;

&lt;p&gt;You can try the approach above in practice. The source code for the demo implementation is here: &lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-tailwind" rel="noopener noreferrer"&gt;nuxt-tailwind @ GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The demo focuses on both integration and usage. All the visual behavior is in &lt;code&gt;/app/app.vue&lt;/code&gt;. It contains several examples of how Tailwind CSS can be applied. It also shows that utility classes can be freely combined with classic “plain” CSS. In &lt;code&gt;/app/assets/css/tailwind.css&lt;/code&gt; you can see how easily you can extend Tailwind CSS' default &lt;code&gt;@theme&lt;/code&gt; with your own colors or fonts if the &lt;a href="https://tailwindcss.com/docs/colors" rel="noopener noreferrer"&gt;base palette&lt;/a&gt; isn't enough.&lt;/p&gt;

&lt;p&gt;Based on a personal bad experience, I also decided to add one cautionary example to the demo alongside the positive ones. I'm risking that it might inspire someone to use it and fall into the same trap I once did, but hopefully it will save many of you from unnecessary problems. What is it about? The Tailwind CSS authors encourage you to use utility classes directly in HTML templates as attributes on individual elements whenever possible. Not everyone (hi, former me) likes that, because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Class lists can get really long&lt;/li&gt;
&lt;li&gt;The same definitions repeat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At the same time, a beginner - armed with general programming truths and ready to “fix” things - will sooner or later discover the &lt;a href="https://tailwindcss.com/docs/functions-and-directives#apply-directive" rel="noopener noreferrer"&gt;&lt;code&gt;@apply&lt;/code&gt; directive&lt;/a&gt;, which &lt;em&gt;seems&lt;/em&gt; to allow defining reusable classes in CSS files. And to be fair: it does allow it, and it works perfectly. The problem is that it severely obfuscates the implementation. After a few months, you forget you styled a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; globally and wonder why your inline definitions don't apply. The demo app includes a clear example with the color of an HTML link at the bottom of the page. I wrote more about this in &lt;a href="https://dev.to/aloisseckar/i-was-using-tailwind-wrong-so-you-dont-have-to-4h7j"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;End of the diversion. Definitely take a look at Tailwind CSS - you might end up liking it like I do, along with thousands of other developers who prioritize speed and efficiency over perfect control via native CSS.&lt;/p&gt;

&lt;p&gt;P.S.: Previously I handled the integration via a dedicated &lt;a href="https://tailwindcss.nuxtjs.org/" rel="noopener noreferrer"&gt;Nuxt module&lt;/a&gt;, which was a bit easier to set up (install + add the module). I'm not sure about its current status, though. After &lt;strong&gt;Tailwind v4&lt;/strong&gt; was released, it stopped working for me. Its new version has been stuck in beta for months, and it almost looks like its historical role is over. If the situation changes, I'll come back and update this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Props
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://open-props.style/" rel="noopener noreferrer"&gt;Open Props&lt;/a&gt; is based on a similar idea to Tailwind CSS - it provides a set of prebuilt styles that may constrain you a bit, but in return you don't have to reinvent the wheel everywhere. Instead of shipping complete prebuilt CSS classes, Open Props encodes the styling information as &lt;a href="https://www.w3schools.com/css/css3_variables.asp" rel="noopener noreferrer"&gt;CSS variables&lt;/a&gt;, which you can use and compose inside your own classes. To be honest: Tailwind v4 also uses CSS variables, and you may have already tasted them (even unknowingly) - see how the demo app extends the default &lt;code&gt;@theme&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open Props sits one level lower. It doesn't abstract away writing CSS entirely; it “only” provides ready-made, proven values. That gives you more freedom, but it's a bit more work. The main advantage is how lightweight and scalable it is - the library lets you &lt;a href="https://open-props.style/#overview" rel="noopener noreferrer"&gt;use only the small subset&lt;/a&gt; you actually need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt integration
&lt;/h3&gt;

&lt;p&gt;Because Nuxt (Vue) can't replace CSS variables with actual values at build time by itself, you need to add a CSS processor (&lt;code&gt;postcss&lt;/code&gt; in my demo) along with a plugin that performs the substitution after being fed the definitions from &lt;code&gt;OpenProps&lt;/code&gt;. That's about the only catch; otherwise you just import the &lt;code&gt;open-props&lt;/code&gt; NPM package and start building CSS definitions. There is a showcase of a few styles in the demo.&lt;/p&gt;

&lt;p&gt;What I like most about Open Props are the ready-made &lt;a href="https://open-props.style/#gradients" rel="noopener noreferrer"&gt;gradients&lt;/a&gt; - smooth transitions between colors. Sure, it's not &lt;em&gt;that&lt;/em&gt; hard to write them yourself in plain CSS (I even watched a demo of building a “gradient editor” recently), but if you're not a web designer at heart, who wants to grind through that?&lt;/p&gt;

&lt;p&gt;The source code for the demo implementation is here:&lt;br&gt;
&lt;a href="https://github.com/AloisSeckar/demos-nuxt/tree/main/nuxt-openprops" rel="noopener noreferrer"&gt;nuxt-openprops @ GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We've shown how to load internal and external CSS files into a Nuxt app, plus two examples of CSS libraries and how to integrate them. There are, of course, many other options. If you have a favorite UI/styling library, check whether it already has a Nuxt integration (most commonly in the form of a &lt;a href="https://nuxt.com/modules" rel="noopener noreferrer"&gt;module&lt;/a&gt;). If not, it may be enough just to load the resulting CSS files the way we described at the start and use them directly. And if you get stuck, reach out and we can try to figure something out together.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-7-ui-integrations-4mjm"&gt;upcoming tutorial article&lt;/a&gt;, we'll move from general styling to more advanced &lt;strong&gt;UI libraries&lt;/strong&gt;, which provide not only styles but also prebuilt UI components. We'll look at a few of them along with examples of integrating them into Nuxt.&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I made my Vitest suite in Nuxt run ten times faster</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 20 Dec 2025 11:21:08 +0000</pubDate>
      <link>https://dev.to/aloisseckar/i-made-my-vitest-suite-in-nuxt-run-ten-times-faster-6j7</link>
      <guid>https://dev.to/aloisseckar/i-made-my-vitest-suite-in-nuxt-run-ten-times-faster-6j7</guid>
      <description>&lt;p&gt;Previously I had to wait &lt;strong&gt;about 3 minutes&lt;/strong&gt; till my tests finish, now the same suite clocks &lt;strong&gt;under 20 seconds&lt;/strong&gt;. Let's see what the bottleneck was and how I &lt;em&gt;vibe coded&lt;/em&gt; the re-design. &lt;strong&gt;Spoiler:&lt;/strong&gt; It was painful running in circles and despite AI gave me some valuable insights, I had to be the Deus ex Machina (pun intended).&lt;/p&gt;

&lt;p&gt;I guess I don't have to explain the importance of writing automated tests to protect applications from introducing unnecessary errors. It is never 100%, but as the time flows, test suites grow larger, cover more situations and especially prevent bugs from &lt;strong&gt;re-appearing&lt;/strong&gt;. I would say it is rather hard to develop a habit of writing tests regularly, especially in personal projects, but current tooling focus on making it easy. Setting up &lt;a href="https://vitest.dev/" rel="noopener noreferrer"&gt;Vitest&lt;/a&gt; to &lt;a href="https://nuxt.com/docs/4.x/getting-started/testing" rel="noopener noreferrer"&gt;test Nuxt applications&lt;/a&gt; is quick and you're good to go. &lt;/p&gt;

&lt;p&gt;You can develop a new feature, write new tests for it, and run the suite to check if:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;New tests are passing - so the new feature works as intended&lt;/li&gt;
&lt;li&gt;Old tests are &lt;strong&gt;still passing&lt;/strong&gt; - so you didn't accidentally break any seemingly unrelated things&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then you can commit with greater confidence.&lt;/p&gt;

&lt;p&gt;But there is a catch - more tests run longer and former seconds may prolong to minutes. So you wait minutes and then you come back and see the test suite failed. You fix the error, run the tests again...and wait minutes again. Do this couple of times and you suddenly don't like the whole idea that much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Framing the problem
&lt;/h2&gt;

&lt;p&gt;Test suite for my Nuxt module for &lt;a href="https://neon.com/" rel="noopener noreferrer"&gt;Neon database&lt;/a&gt; connection reached 180+ seconds of runtime. This didn't feel right anymore. The tests were testing, but the inefficiency hit my DevEx hard. It was the turning point when &lt;em&gt;premature optimization&lt;/em&gt; turned into a required one.&lt;/p&gt;

&lt;p&gt;Because it is 2025, I invited AI to check the situation and brainstorm for possible solutions. &lt;/p&gt;

&lt;p&gt;Copilot quickly pointed out, that I am using separate Nuxt app instance for each test file. At first it looked like a good decision to separate concerns - testing SELECT operations in an app for selects, INSERT in another one. It should help keeping things small and organized. But booting them up takes time and all tests had to wait until their app is rendered.&lt;/p&gt;

&lt;p&gt;To make the problem worse, I decided to run my tests sequentially. Because if something messes up and the module cannot even connect to the database, why tests the functions? Or if SELECTs are failing due to an error in constructing the SQL query, why to try INSERTs that would also inevitably fail? This stacks the waiting times up. And despite everything eventually works, I ended up waiting those 3 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  First iteration - double speed
&lt;/h2&gt;

&lt;p&gt;The fix was apparent - merge the separate test apps into one. This was quite easy to do, because I designed my tests so that each has its dedicated Nuxt page (this means separate URL) where it connects, perform SQL action bound to a button and check the resulting HTML for expected values. So I really just have to squash multiple &lt;code&gt;/app/pages&lt;/code&gt; directories into one and make some small adjustments in &lt;code&gt;app.vue&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;But it wasn't enough. Because my E2E test files would still&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;fileURLToPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./neon-test-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;via a function from &lt;code&gt;@nuxt/test-utils/e2e&lt;/code&gt; package. This would still create and bind new instance of Nuxt app for &lt;strong&gt;each&lt;/strong&gt; test file. So it would still take a lot of time.&lt;/p&gt;

&lt;p&gt;To be honest, there was already an observable speed-up. I guess it was because it can re-use some cached pieces and mounting the same app 5 times was about twice as fast as mounting 5 different apps, but it was still very sub-optimal.&lt;/p&gt;

&lt;p&gt;What I really needed was that whenever any test case does&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it should connect to the &lt;strong&gt;same&lt;/strong&gt; instance of underlying demo application. This would only start once and then all tests should call it with a snap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Second iteration - 10x speed, but...
&lt;/h2&gt;

&lt;p&gt;So how to do that? I didn't know. So I asked my smarter/dumber electronic assistant. It came up with very unorthodox solution. If you want to follow along, the result was committed &lt;a href="https://github.com/AloisSeckar/nuxt-neon/commit/32bc4150adefaab175d56ffb2b4227bb505776d6" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;. I will now sum up the most important pieces.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;vitest.config.ts&lt;/code&gt;, new setting was added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;globalSetup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./node_modules/@nuxt/test-utils/dist/runtime/global-setup.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It took me a while to understand what it is even intended to do. I challenged my Copilot's reasoning and cross-checked with my standalone ChatGPT 5.2 Plus. It confirmed the idea. Despite it testified it didn't find any article or discussion about it, it says it &lt;em&gt;assumed&lt;/em&gt; from the code, it would work. The justification made sense. I had nothing to lose. So I believed.&lt;/p&gt;

&lt;p&gt;In short, running this file in &lt;code&gt;globalSetup&lt;/code&gt; before other Vitest actions start should "magically" grant me existence of a mounted app in emulated browser. To tell it, which app I want to mount, I should feed &lt;code&gt;NUXT_TEST_OPTIONS&lt;/code&gt; environment variables which are swallowed during the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;fileURLToPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test/neon-test-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Used by @nuxt/test-utils/runtime/global-setup&lt;/span&gt;
&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NUXT_TEST_OPTIONS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="c1"&gt;// path to neon-test-app&lt;/span&gt;
  &lt;span class="nx"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// don't create a Playwright browser in globalSetup&lt;/span&gt;
  &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second integral part was &lt;code&gt;e2e.setup.ts&lt;/code&gt; - a file to add actions to be run by Vitest before every test file. In &lt;code&gt;beforeAll&lt;/code&gt; method it should construct a virtual browser instance - but only for the first time when it is non-existent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTestContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, this would grant all test files access to the shared context with prepared virtual browser with mounted Nuxt test app. And all tests should just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and start navigating to desired routes and testing the stuff.&lt;/p&gt;

&lt;p&gt;I tried to follow my usual sceptical approach to AI and understand the intents behind the code spitted out - at least briefly. I couldn't grasp all details, but overall it appeared to make sense. And when I tried it - &lt;strong&gt;it worked&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Well, not for the first time. We had to tweak couple of things, but in the end the suite was running. And boy, it was fast! Less than 20 seconds and all tests already passed. If I deliberately made a test fail to check, whether it actually runs and tests something, it started failing just as expected. My job here was done. Commit, close the issue, go to sleep with good feeling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqz64nklevn9ltyh5w6o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqz64nklevn9ltyh5w6o.png" alt=" " width="444" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Except there was a "tiny" detail I missed at the time. The Vitest suite was running fine, but once the process is finished, the output just disappeared from the terminal! So there was no chance to recover the result. Unless you looked at it, you had no chance to tell whether it passed or not. And if it failed, there was no way to see what exactly went wrong.&lt;/p&gt;

&lt;p&gt;My tests essentially become useless 😨&lt;/p&gt;

&lt;h2&gt;
  
  
  Third iteration - to hell and back
&lt;/h2&gt;

&lt;p&gt;The reason why I missed it when I worked on it is interesting per se. &lt;/p&gt;

&lt;p&gt;Because we tried a number of things with my Copilot during the process, at some time we introduced &lt;code&gt;$env:DEBUG='@nuxt/test-utils*'&lt;/code&gt; setting into my current terminal. Thanks to this extra environment setting, the program started to log differently - extensively and without interruption. All the log messages were prefixed with &lt;code&gt;[source]&lt;/code&gt; tags, but I barely noticed that. I saw the Vitest output and I was happy.&lt;/p&gt;

&lt;p&gt;But the default way of things with the &lt;code&gt;globalSetup&lt;/code&gt; is, that the terminal is first occupied with the test Nuxt app build and then it is automatically switched into a new &lt;em&gt;alternate screen&lt;/em&gt; that is visible in the terminal, but only as long as the associated process is running. Then it is just thrown away and replaced by former (empty) terminal.&lt;/p&gt;

&lt;p&gt;I didn't know that, until I spend &lt;strong&gt;HOURS&lt;/strong&gt; of useless attempts of adding config here and there. AI was spitting out fabricated theories, and I was struggling with implementing them and keep failing again and again.&lt;/p&gt;

&lt;p&gt;After some time we at least isolate the &lt;code&gt;DEBUG&lt;/code&gt; option as a possible workaround. But it also came with a very noisy and verbose output. Filtering out was possible, but platform-dependant. Or I could have wait for 20 seconds of silence and then got the filtered result processed by Node. Also not good. &lt;/p&gt;

&lt;p&gt;I tried to bargain with AI until I finally - for the first time I thing - managed to force ChatGPT into saying: &lt;em&gt;"No, this is not possible."&lt;/em&gt; More precisely, it wrote: &lt;em&gt;"This is the moment where I need to be very explicit and honest, because you’ve now hit a hard boundary, not a missing trick."&lt;/em&gt; which I find hilarious now, but I didn't laugh back then.&lt;/p&gt;

&lt;p&gt;The harsh truth hitting me that evening. I wasted hours chasing my own shadow. With AI happily assisting me and encouraging me to continue.&lt;/p&gt;

&lt;p&gt;I have fast, but badly observable tests. Either no output at all, or an output littered by tons of non-related debug messages, or platform-dependant script commands to polish it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fourth iteration - deus ex homine
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/aloisseckar/the-mysterious-case-of-the-query-that-never-ran-1gd9"&gt;my last article&lt;/a&gt; I went to sleep on the problem, and it didn't help. But this time it does. When I woke up this morning, prepared to finalize the ugly but so-so working solution, I suddenly got an out-of-the-box idea.&lt;/p&gt;

&lt;p&gt;What if I stop trying to abuse Vitest into doing something it is not designed for?&lt;/p&gt;

&lt;p&gt;What if I just aggregate my test files into one big suite?&lt;/p&gt;

&lt;p&gt;Like that it would only need to build and mount the test app once and then it will run fast. Yes, there would be a little trade-off - one big test file with a lot of test cases. But to be honest, this doesn't really matter from the runtime perspective. And I can still keep the source code isolated by having separate definition files that will be dynamically imported in the actual single &lt;code&gt;e2e.test.ts&lt;/code&gt; file, the only one that will be executed by Vitest.&lt;/p&gt;

&lt;p&gt;And so just like that, I throw away most of the "clever hacks" from the solution #3 and came up with something else. Despite my AI assistants failed yesterday, I indeed used them again to help me fabricated the vivid solution. Now when I was back with a clear intention in mind, I got helpful output and tips again. The final solution is &lt;a href="https://github.com/AloisSeckar/nuxt-neon/tree/9a7d9745f28178708c2fa7222b76ad6573842d22" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Calls for &lt;code&gt;globalSetup&lt;/code&gt; and even the &lt;code&gt;setupFiles&lt;/code&gt; were removed from &lt;code&gt;vitest.config.ts&lt;/code&gt;. The all I need now is a nice, small and clean &lt;code&gt;e2e.test.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fileURLToPath&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:url&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@nuxt/test-utils/e2e&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// only setup nuxt-test-app ONCE&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;rootDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;fileURLToPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="c1"&gt;// Playwright browser is not required for now&lt;/span&gt;
  &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// import and run E2E test suites AFTER the test app is ready&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-suites/01-basic&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-suites/02-select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-suites/03-insert&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-suites/04-update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../neon-test-suites/05-delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prepares the Nuxt test app via dedicated &lt;code&gt;setup&lt;/code&gt; function and then just awaits and executes one file with test definitions after another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that's it.&lt;/strong&gt; No hacks, no mess in console. It works like charm and it is still fast. 20 seconds and you're done. The output remains in the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwkns02zqx4jw5su39xh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwkns02zqx4jw5su39xh.png" alt=" " width="259" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  To infinity and beyond
&lt;/h2&gt;

&lt;p&gt;So now you know how I wrestle with Vitest with Nuxt and won. If you'd like to know more details about the final implementation or you have objections and ideas for improvement, let me know in the comments.&lt;/p&gt;

&lt;p&gt;You also seen how AI tools still lead you astray easily. To their defence, in this case both Copilot and ChatGPT pretty much resembled a common developer, who is desperately throwing solutions that "should work" without realizing the whole picture. Where they failed and I eventually succeeded was ability to step back and re-think the whole situation. I believe this is still the gap between human developers and the artificial pseudo-intelligence.&lt;/p&gt;

&lt;p&gt;Lastly, this wasn't meant to be an anti-AI rant. It is helping me on daily basis, and I really enjoy getting further and further with its assistance. I just think there are still limits we need to be aware of. It was another nice lesson for me, and I hope you found it somewhat interesting too. &lt;/p&gt;

&lt;p&gt;Looking forward to your feedback and questions.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nuxt</category>
      <category>vitest</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Mysterious Case of the Query that Never Ran</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sat, 13 Dec 2025 09:54:47 +0000</pubDate>
      <link>https://dev.to/aloisseckar/the-mysterious-case-of-the-query-that-never-ran-1gd9</link>
      <guid>https://dev.to/aloisseckar/the-mysterious-case-of-the-query-that-never-ran-1gd9</guid>
      <description>&lt;p&gt;Over the past weekend I encountered a weird bug.&lt;/p&gt;

&lt;p&gt;I was refactoring code for my personal website. I am a casual runner and I have a &lt;a href="https://alois-seckar.cz/run" rel="noopener noreferrer"&gt;page with all my run records&lt;/a&gt;. The data for it are stored in &lt;a href="https://neon.com/" rel="noopener noreferrer"&gt;Neon database&lt;/a&gt; and I am reading them through my own custom &lt;a href="https://www.npmjs.com/package/nuxt-neon" rel="noopener noreferrer"&gt;nuxt-neon&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;I was updating the code to reflect the latest changes in my module. Namely I tried to change the filtering by date (year and/or month). Originally, I use literal string &lt;code&gt;WHERE&lt;/code&gt; condition &lt;code&gt;r.date BETWEEN '${fromDate}' AND '${toDate}'&lt;/code&gt;. Now I planned to battle-test my new object syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;r.date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fromDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;r.date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;toDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AND&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you may argue this is much more complicated and you'd probably be right. But I wanted to test how it works beyond sterile tests defined inside my module. And...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It was a complete failure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No data. Just an ugly HTTP error when trying to get data from the Nuxt server endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NuxtNeonClientError in fetchFromNeonBackend: 
[POST] "/api/_neon/select": 400 Bad Request (status: 500). 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make a quick explanation - my module is providing a client-side &lt;a href="https://vuejs.org/guide/reusability/composables.html#what-is-a-composable" rel="noopener noreferrer"&gt;composable&lt;/a&gt; &lt;code&gt;useNeon&lt;/code&gt; that exposes couple of wrappers for SQL functions (namely &lt;code&gt;select&lt;/code&gt; in this case). Those wrappers are essentially just forwarding input query to Nuxt server endpoints for each SQL function. Like this, I can keep the DB credentials safely stored on the server side and not leak them via runtime config into the browser. AFAIK Neon does not provide safe public API keys as services like Supabase do.&lt;/p&gt;

&lt;p&gt;So I started to investigate what might be wrong.&lt;/p&gt;

&lt;p&gt;At first, I thought I messed up the implementation, and I am constructing a bad SQL query. But there were two "buts" to this theory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The very same query worked just fine when I reproduced it as a test case in my module codebase. And in fact, I was already testing whether &lt;em&gt;"greater than / less than"&lt;/em&gt; operators pick the right data.&lt;/li&gt;
&lt;li&gt;Despite I set enhanced debug logs for my module (you can debug both the execution flow and the actual SQL produced inside the module), I saw no data for my request. Actually, it looked like the API endpoint wasn't even called.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I found myself desperately tampering with the files inside my &lt;code&gt;node_modules&lt;/code&gt; folder trying to track down where I am and why I am not seeing any usable output to understand the issue.&lt;/p&gt;

&lt;p&gt;I had a faint suspicion that the literal characters &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; should be the root issue. But no viable theory of why it would matter.&lt;/p&gt;

&lt;p&gt;I gave it a one-day break and unsurprisingly I didn't get any brilliant idea overnight. As a last resort, I just tried to ask my Copilot. I was postponing this move, because &lt;em&gt;&lt;strong&gt;what would my question be&lt;/strong&gt;&lt;/em&gt;? I don't understand what is going on, how should I instruct mindless LLM to come up with a solution? Without good prompt, I can't get good result, can I?&lt;/p&gt;

&lt;p&gt;Well no, but actually yes. Copilot didn't magically save the day. But it gave me one important clue to follow: &lt;em&gt;"Reproduce with curl (bypasses browser and frontend)"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This means, just call the API endpoint directly with a bare HTTP request. Strip it down from all frontend framework noise. Then you might understand better what is breaking up before backend can process your request. So I did as machine mind said and &lt;em&gt;voilà!&lt;/em&gt;, everything clicked together.&lt;/p&gt;

&lt;p&gt;Turned out my request was being rejected by &lt;a href="https://nuxt.com/modules/security" rel="noopener noreferrer"&gt;Nuxt Security module&lt;/a&gt; and its XSS attack protection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...\node_modules\.pnpm\nuxt-security@2.4.0_magicast@0.3.5_rollup@4.52.5\
node_modules\nuxt-security\dist\runtime\server\middleware\
xssValidator.js:38:18
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like that, it is pretty obvious. The problem was this particular line was swallowed inside Nuxt leaving me only with a cryptic error with no apparent reason.&lt;/p&gt;

&lt;p&gt;Naturally, it was because of the &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; brackets. Nuxt Security treats them as potentially malicious attempt to smuggle a script into the payload. Between me and you - this module is pretty good in protecting your Nuxt applications with little to no effort of setting it up, but then it keeps biting you back like that.&lt;/p&gt;

&lt;p&gt;So this was the missing piece. It worked in my tests because the naive demo app is not concerned about security that much. But I chose to shield my homepage with more advanced protection, and it backfired.&lt;/p&gt;

&lt;p&gt;To mitigate the problem, I am adding an internal mapping that translates angle brackets to text abbreviations on client and back when constructing the actual SQL query on the server. For user convenience I decided to keep them available instead of forcing everyone to learn they should use &lt;code&gt;GT&lt;/code&gt; and &lt;code&gt;LT&lt;/code&gt; abstraction.&lt;/p&gt;

&lt;p&gt;Despite the root cause and the solution itself isn't groundbreaking, I still thought the unique combination of circumstances is worth an article. I wanted to share following lessons learned from this debugging struggle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't be shy to ask AI for help&lt;/strong&gt; - Even if you don't know the right question yet, just ask: &lt;em&gt;"Why do I have this error?"&lt;/em&gt; Start explaining the situation and you may &lt;em&gt;vibedebug&lt;/em&gt; the solution eventually. It keeps surprising me how effective this becomes lately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolate the problem&lt;/strong&gt; - If backend seems not to respond properly, call it directly to abstract from possible interference. I should have known this after all those years in software development, yet I got lost in the frontend land and needed virtual assistant to pull me out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take 3rd party SW in account&lt;/strong&gt; - Maybe it is not just your code that causes the trouble. Maybe some other library is acting up (because of something in your code).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I have been developing software for at least two decades now. I feel like a senior and being treated as such. But as you can see, I keep getting stuck in trivial situations and feeling rather stupid afterwards. I believe this is part of the process. You keep running into the walls, keep falling down and keep raising up, being ready for more.&lt;/p&gt;

&lt;p&gt;Thank you for reading this and may it help someone in the future. Until the next awkward issue to solve.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nuxt</category>
      <category>debugging</category>
      <category>learning</category>
    </item>
    <item>
      <title>New in Vue - November 2025</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Thu, 27 Nov 2025 13:21:49 +0000</pubDate>
      <link>https://dev.to/aloisseckar/new-in-vue-november-2025-1l1b</link>
      <guid>https://dev.to/aloisseckar/new-in-vue-november-2025-1l1b</guid>
      <description>&lt;p&gt;Attention! More news and events from the ever-evolving world of &lt;strong&gt;Vue&lt;/strong&gt;, &lt;strong&gt;Nuxt&lt;/strong&gt;, &lt;strong&gt;Vite&lt;/strong&gt;, and their awesome open-source ecosystems are there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcsywjp8b1lrbu95xywgi.png" alt="New Vue newsletter launched"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;I would like to start 5th issue of my Vue newsletter with something I haven't done yet - sharing a video:&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/ofQV3xiBgT8"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;As you can see, it is a flashback from the &lt;a href="https://viteconf.amsterdam/" rel="noopener noreferrer"&gt;ViteConf&lt;/a&gt; I was talking about last month. The reason why am I featuring this is interesting topic of &lt;em&gt;not-so-distant&lt;/em&gt; future of our ecosystem together with the awesome stage presence of the speaker. I remember my very first impression was &lt;em&gt;"Oh wow, the guy sounds quite nervous"&lt;/em&gt;. But then Jim Dummet delivered one of the most memorable IT talk I can think about. The fact it was his only second live talk ever makes it even more awesome. Give it a try if you have a spare 30 minutes.&lt;/p&gt;

&lt;p&gt;Speaking about ViteConf, two more interesting news I forgot to point out in October were released there. The &lt;a href="https://github.com/vitejs/devtools" rel="noopener noreferrer"&gt;Vite DevTools&lt;/a&gt; project was announced by Anthony Fu, which will bring the developer experience one more step (or even a leap) forward. Despite it seems nowhere near close to stable release yet, it is something worth paying attention to. And I am looking forward to the result. Second update came from &lt;a href="https://nitro.build/" rel="noopener noreferrer"&gt;Nitro&lt;/a&gt; - an alpha version of its v3 major upgrade was released during the conference by its maintainer Pooya Parsa. Also not finished yet, but another gamechanger in the ecosystem that is knocking at the door.&lt;/p&gt;

&lt;p&gt;To get a comprehensive overview of what happened in Amsterdam (and &lt;strong&gt;should NOT&lt;/strong&gt; stay in Amsterdam) was &lt;a href="https://voidzero.dev/posts/whats-new-viteconf-2025" rel="noopener noreferrer"&gt;written by Alex Lichter&lt;/a&gt;, so if you want more detail plus direct links to respective talks, give it a go.&lt;/p&gt;

&lt;p&gt;Overall November was quieter in terms of hot ecosystem news. Or they went past me if there were any. The one that hit me and I find it worth mentioning was the alpha release of &lt;a href="https://github.com/nuxt/hints" rel="noopener noreferrer"&gt;Nuxt Hints&lt;/a&gt; module. It is promised to provide &lt;em&gt;"real-time feedback on your application's performance, accessibility, and security right in your browser"&lt;/em&gt;. I believe it will become very helpful to make our Nuxt apps better. It is out for two weeks now, and I am looking forward to set it up and give it a try. Sadly, there wasn't time for that yet.&lt;/p&gt;

&lt;p&gt;Tiny promo (getting no commission for this, I just like it) - if you need an easy way of integrating &lt;code&gt;Share with &amp;lt;&amp;lt;insert_socal_network&amp;gt;&amp;gt;&lt;/code&gt; buttons to your website, &lt;a href="https://nuxt-social-share.stefanobartoletti.it/" rel="noopener noreferrer"&gt;Nuxt Social Share&lt;/a&gt; is there for help. It is incredibly easy with zero knowledge of the APIs required - you just add a component, pick the target via a string prop and get the sharing functionality. I set it up within minutes for my blog. The "hardest" part is to adjust the default styling, but it uses Tailwind CSS, so it is actually not that hard at all. I really recommend this 👍&lt;/p&gt;

&lt;p&gt;Did you ever feel overwhelmed by different approaches to managing stateful data in Vue applications? Michael Hoffmann wrote a useful guide for &lt;a href="https://mokkapps.de/blog/vue-state-management-composables-provide-inject-pinia" rel="noopener noreferrer"&gt;how to pick between Composables, Provide/Inject, and Pinia&lt;/a&gt; which might help you navigate through it. He also runs &lt;a href="https://weekly-vue.news/" rel="noopener noreferrer"&gt;Weekly Vue News&lt;/a&gt; email newsletter, so consider subscribing for even more "New In Vue" stuff from him.&lt;/p&gt;

&lt;p&gt;I'll be back in late December. Thank you for reading this and if you have any questions or feedback, feel free to use the comments bellow.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Upcoming events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://vuejs.amsterdam/" rel="noopener noreferrer"&gt;VueJS Amsterdam 2026&lt;/a&gt; - &lt;strong&gt;12-13 March 2026&lt;/strong&gt;, Amsterdam [NED]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vueconf.us/" rel="noopener noreferrer"&gt;Vueconf.US 2026&lt;/a&gt; - &lt;strong&gt;19-21 May 2026&lt;/strong&gt;, Atlanta [USA]&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://madvue.es/" rel="noopener noreferrer"&gt;MadVue 2026&lt;/a&gt; - &lt;strong&gt;22 May 2026&lt;/strong&gt;, Madrid [ESP]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Past issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-october-2025-6i7"&gt;October 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-september-2025-4mef"&gt;September 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-august-2025-lip"&gt;August 2025&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/aloisseckar/new-in-vue-july-2025-24id"&gt;July 2025&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dev.to/aloisseckar"&gt;Follow me&lt;/a&gt; for more updates on Vue, Nuxt, Vite - and maybe even more!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>nuxt</category>
      <category>vite</category>
    </item>
    <item>
      <title>Nuxt Tutorial 6 - Vue.js Intermezzo</title>
      <dc:creator>Alois Sečkár</dc:creator>
      <pubDate>Sun, 23 Nov 2025 22:01:10 +0000</pubDate>
      <link>https://dev.to/aloisseckar/nuxt-tutorial-6-vuejs-intermezzo-45aa</link>
      <guid>https://dev.to/aloisseckar/nuxt-tutorial-6-vuejs-intermezzo-45aa</guid>
      <description>&lt;p&gt;In this inserted article, we take a closer look at selected fundamental concepts of the Vue.js framework that Nuxt builds upon. I believe it is not a good idea to use any tool without at least a rough understanding of how it works under the hood. Before we continue exploring more of Nuxt’s great features, we’ll go back to the roots without building anything specific here. But you will end up better prepared when you try it yourself later.&lt;/p&gt;

&lt;p&gt;To begin, note the best available source of Vue information - the &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;. You will learn much more about everything mentioned in this article there, and you can always return to consult questions and issues.&lt;/p&gt;

&lt;p&gt;Now for the promised overview of the basics. First, we return to components, which we &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-2-components-pages-432g"&gt;briefly described&lt;/a&gt; earlier, and go a bit deeper now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;The basic building block of a Vue application is a &lt;strong&gt;component&lt;/strong&gt;. By composing and nesting them you create the required functionality. By far the most common (though not the only possible) way to define a component is the &lt;strong&gt;SFC – single file component&lt;/strong&gt;. As the name suggests, it combines all UI parts and logic into a single file identifiable by the &lt;code&gt;.vue&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;Vue’s built-in compiler can interpret these files and, during the application build, translate them into fully functional HTML + JavaScript. This means that if we want to use them, we must include a &lt;em&gt;build phase&lt;/em&gt; during which the transformation happens. I mention this because Vue can also be used statically via a simple &lt;a href="https://vuejs.org/guide/extras/ways-of-using-vue.html#standalone-script" rel="noopener noreferrer"&gt;standalone script inclusion&lt;/a&gt; in an HTML page. But this effectively limits you to use only bits of Vue here and there. However, I already tricked you into adopting the build step from the very beginning with the first &lt;code&gt;pnpm dev&lt;/code&gt; command. That’s why we could use SFCs without worrying about anything.&lt;/p&gt;

&lt;p&gt;An SFC consists of three main parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Template&lt;/strong&gt; - an HTML‑like template that defines the final appearance of the rendered page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Script&lt;/strong&gt; - a section for JS/TS code that drives rendering logic, backend communication, and coordination with other parts of the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Style&lt;/strong&gt; - a place for defining CSS styles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not strictly necessary to include all three. A valid component can contain only &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; (a “renderless” or &lt;em&gt;functional&lt;/em&gt; component) or only &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; if you don’t need more substantial data preparation or manipulation. A standalone &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; is not allowed because it wouldn’t be clear what the styles belong to.&lt;/p&gt;

&lt;p&gt;I prefer having &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; first, &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; second and &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; last (if present). I found out I swim against a current with this habit, because you'll probably see &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; before &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; more often, but  it just feel more natural - first I want to see how the component will look like and only then what values will it display. Data without context seem less useful for me. Anyway, it is a matter of personal preference. The only guideline set is not to mix the order up within a project. Pick just one style and follow it everywhere.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It’s also theoretically possible to define arbitrary &lt;a href="https://vuejs.org/api/sfc-spec.html#custom-blocks" rel="noopener noreferrer"&gt;custom blocks&lt;/a&gt;. Vue lets you declare them, but you must handle them yourself. While I haven’t needed them in practice yet, a good example is an &lt;a href="https://vue-i18n.intlify.dev/guide/advanced/sfc.html" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;i18n&amp;gt;&lt;/code&gt; block&lt;/a&gt; in the eponymous library for facilitating webapp localization.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;SFCs are primarily a way to keep all logically connected parts of a certain functionality in one place. This is somewhat at odds with the more traditional (at least for me) separation of concerns. However, in my recent experience it makes much more sense and is much easier to work with than constantly jumping between multiple files. If that’s hard to accept, Vue has sort of a workaround - using the &lt;code&gt;src&lt;/code&gt; attribute you can &lt;a href="https://vuejs.org/api/sfc-spec.html#src-imports" rel="noopener noreferrer"&gt;import block contents from other files&lt;/a&gt;. I still don’t recommend it. If your &lt;code&gt;.vue&lt;/code&gt; files feel bloated, rather consider splitting them into several smaller components.&lt;/p&gt;

&lt;p&gt;Now let’s look inside each base block:&lt;/p&gt;

&lt;h3&gt;
  
  
  Template
&lt;/h3&gt;

&lt;p&gt;Inside the &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; tag is the definition of the content of the future rendered (part of the) page. You write code very similar to HTML, but you can use certain special Vue syntactic features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Double curly braces (the “mustache” syntax) allow inserting JavaScript - &lt;code&gt;{{ msg }}&lt;/code&gt;. During template compilation, the expression is evaluated and interpolated as &lt;strong&gt;plain text&lt;/strong&gt;, and the evaluated current value appears in the rendered HTML. Typically, you want to evaluate only simple variable references or function calls. Technically you are not limited, but it’s considered a good practice to keep the template clean and push heavy JS work into the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; section or other files - you already know Nuxt allows you to reference them directly thanks to auto‑imports.&lt;/li&gt;
&lt;li&gt;A colon &lt;code&gt;:&lt;/code&gt; before an attribute name (native or your own - see props section later) is shorthand for &lt;code&gt;v-bind:&lt;/code&gt; and binds the attribute to a JavaScript expression. The same advice as above applies - don’t abuse templates for complex inline logic.&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;@&lt;/code&gt; before an event name is shorthand for &lt;code&gt;v-on:&lt;/code&gt; and binds a handler function. When the specified event is captured (native like &lt;code&gt;click&lt;/code&gt; or &lt;code&gt;change&lt;/code&gt;, or custom - see emits later), the given function is called. The function can be written inline, but it’s again better to reference a callback defined in the appropriate place.&lt;/li&gt;
&lt;li&gt;Other &lt;code&gt;v-*&lt;/code&gt; directives are pseudo‑attributes that give the compiler instructions for special handling. For example:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;v-if&lt;/code&gt; - &lt;em&gt;renders&lt;/em&gt; the element if the condition &lt;strong&gt;is&lt;/strong&gt; met&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-else&lt;/code&gt; - &lt;em&gt;renders&lt;/em&gt; the element if the condition &lt;strong&gt;is NOT&lt;/strong&gt; met&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-show&lt;/code&gt; - always &lt;em&gt;render&lt;/em&gt;, but &lt;em&gt;show&lt;/em&gt; the element only if the condition &lt;strong&gt;is&lt;/strong&gt; met&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-for&lt;/code&gt; - render multiple items from a list in a loop&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;v-html&lt;/code&gt; - insert HTML‑styled content into an element (&lt;strong&gt;beware, potentially dangerous&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;complete list is &lt;a href="https://vuejs.org/api/built-in-directives.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;you can also define &lt;a href="https://vuejs.org/guide/reusability/custom-directives.html" rel="noopener noreferrer"&gt;your own&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Vue templates also have the ability to understand references to other components. Use the &lt;code&gt;.vue&lt;/code&gt; filename in PascalCase notation as an identifier. In plain Vue, components must be &lt;a href="https://vuejs.org/guide/components/registration.html" rel="noopener noreferrer"&gt;registered&lt;/a&gt; before use. Nuxt handles this automatically as long as &lt;code&gt;.vue&lt;/code&gt; files are in the &lt;code&gt;/app/components&lt;/code&gt; folder &lt;em&gt;(or you &lt;a href="https://nuxt.com/docs/4.x/directory-structure/app/components" rel="noopener noreferrer"&gt;configure directorsies&lt;/a&gt; where auto‑import should happen)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to this, you can compose larger functional units from individual SFCs. Vue also fuels the simple, yet powerful two-way communication. We’ll show how it works in a moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Script
&lt;/h3&gt;

&lt;p&gt;Because Vue values flexibility, the following is not the only option, but in my opinion there is currently no better approach than wrapping your JavaScript/TypeScript logic using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;setup&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// your JS/TS logic&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tag name is obvious. The &lt;a href="https://vuejs.org/api/sfc-script-setup.html" rel="noopener noreferrer"&gt;&lt;code&gt;setup&lt;/code&gt;&lt;/a&gt; attribute tells the compiler that we will use Vue’s &lt;a href="https://vuejs.org/guide/extras/composition-api-faq.html" rel="noopener noreferrer"&gt;Composition API&lt;/a&gt;. I’ve kept quiet until now that another variant exists, but the Options API is, in my view, an obsolete approach not worth learning first. You may come across guides, libraries and legacy codebases that still use it, but there’s no need to burden yourself until you actually need it. I’m confident you won’t regret using &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;. All the Vue/Nuxt features mentioned later implicitly assume using it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;lang="ts"&lt;/code&gt; attribute denotes a preprocessor that enables TypeScript support. It isn’t mandatory, but without TypeScript and its static analysis I can’t really imagine my development. Properly configured TypeScript in your IDE immediately warns you about accessing undefined variables, passing wrong argument types, or calling functions that don’t exist - and much more. It’s worth investing a bit of effort up front to understand its principles.&lt;/p&gt;

&lt;p&gt;Any JS variables and functions you define inside &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; are automatically available to the component template. They are also safely sealed off from the outside unless you explicitly expose them using &lt;a href="https://vuejs.org/api/sfc-script-setup.html#defineexpose" rel="noopener noreferrer"&gt;&lt;code&gt;defineExpose&lt;/code&gt;&lt;/a&gt; macro. I recommend keeping this block short - declare only elements tightly bound to the current component and refactor longer sequences into separate &lt;code&gt;utils&lt;/code&gt; or &lt;code&gt;composables&lt;/code&gt; (see the &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-3-utils-composables-3o51"&gt;earlier tutorial part&lt;/a&gt;). Once we introduce the last section, we’ll get to more concrete examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Style
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag wraps the CSS definition. If you want more than plain CSS, you can use the &lt;code&gt;lang&lt;/code&gt; attribute to define a preprocessor (e.g., &lt;a href="https://sass-lang.com/" rel="noopener noreferrer"&gt;Sass&lt;/a&gt;), but you must first &lt;a href="https://nuxt.com/docs/4.x/getting-started/styling#using-preprocessors" rel="noopener noreferrer"&gt;configure it&lt;/a&gt; in your project.&lt;/p&gt;

&lt;p&gt;It’s a good practice to keep styles inside an SFC local to that component and avoid letting them &lt;em&gt;leaking&lt;/em&gt; into the rest of the app. That can have unexpected consequences &lt;a href="https://github.com/vuejs-translations/docs-cs/issues/267" rel="noopener noreferrer"&gt;elsewhere&lt;/a&gt; and the source of such bugs is hard to find. Vue makes file‑level encapsulation easy - just add the &lt;code&gt;scoped&lt;/code&gt; attribute: &lt;code&gt;&amp;lt;style scoped&amp;gt;&lt;/code&gt; - and you’re done. Styles meant to apply globally should be defined at the top level in &lt;code&gt;app.vue&lt;/code&gt;, or, if there are more of them, in a separate CSS file &lt;a href="https://nuxt.com/docs/4.x/getting-started/styling#the-css-property" rel="noopener noreferrer"&gt;loaded via Nuxt config&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can define multiple &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; blocks in a single component, but I think it’s not very practical. I also haven’t used &lt;a href="https://vuejs.org/api/sfc-css-features.html#css-modules" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt; much.&lt;/p&gt;

&lt;p&gt;I would say you’ll likely start relying on this block first, but then you shift towards using it more sparingly - only for specific requirements. Appearance is often handled by UI libraries, and there’s no need to reinvent the wheel. Or if you reach for &lt;strong&gt;Tailwind CSS&lt;/strong&gt; (see &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a"&gt;this tutorial part&lt;/a&gt; for more info), classic CSS almost disappears for you…&lt;/p&gt;

&lt;h2&gt;
  
  
  Passing Data Between Components
&lt;/h2&gt;

&lt;p&gt;Encapsulating parts of the app into separate components is great, but they must also communicate. Vue provides support for this indeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Props
&lt;/h3&gt;

&lt;p&gt;With the special &lt;code&gt;defineProps()&lt;/code&gt; function, you can define a set of variables that can be passed into the component from outside. Conceptually this corresponds to public attributes of a class in object‑oriented languages. To be precise, this is not a real function but another &lt;em&gt;compile‑time macro&lt;/em&gt; whose contents are transformed when translating the &lt;code&gt;.vue&lt;/code&gt; file into real code.&lt;/p&gt;

&lt;p&gt;The macro argument is an object of declared properties that Vue refers as &lt;strong&gt;props&lt;/strong&gt;. There are several syntax variants. For a long time I liked so-called &lt;em&gt;object&lt;/em&gt; syntax, because it looks natural:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The downside is that for more complex type you need to re-type it via generic Vue utility &lt;code&gt;PropType&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineProps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;PropType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not very intuitive and it is unnecessarily complex. Because of that I finally adopted newer &lt;em&gt;type based&lt;/em&gt; syntax. It looks weird, but it is more suitable and much shorter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defineProps&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;CustomType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then use the defined values inside &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; as &lt;code&gt;props.foo&lt;/code&gt; and &lt;code&gt;props.bar&lt;/code&gt;. In &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; expressions, you can refer to &lt;code&gt;foo&lt;/code&gt; or &lt;code&gt;bar&lt;/code&gt; directly; the compiler is smart enough to resolve that they are &lt;strong&gt;props&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Passing into the child from one level up looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ChildComponent&lt;/span&gt; &lt;span class="na"&gt;foo=&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt; &lt;span class="na"&gt;:bar=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to TypeScript, type checking works, so &lt;code&gt;foo&lt;/code&gt; only accepts strings and &lt;code&gt;bar&lt;/code&gt; only numbers. Note that text can be passed as a normal HTML attribute value, while all other types must be prefixed with a colon (shorthand for &lt;code&gt;v-bind:&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Also remember that you should treat &lt;strong&gt;props&lt;/strong&gt; as &lt;em&gt;read‑only&lt;/em&gt; inside a component. If you mutate them, you tightly couple parent and child, which undermines encapsulation and reusability. You can use a &lt;strong&gt;prop&lt;/strong&gt; value to initialize your own local variable (beware of &lt;a href="https://medium.com/front-end-weekly/understanding-pass-by-value-and-pass-by-reference-in-javascript-8e2a0806b175" rel="noopener noreferrer"&gt;pass‑by‑reference&lt;/a&gt; with objects). Usually it’s even better to use &lt;code&gt;v-model&lt;/code&gt; or state management (see below).&lt;/p&gt;

&lt;h3&gt;
  
  
  Emits
&lt;/h3&gt;

&lt;p&gt;That covered passing data into a component; now we need the other direction. Use the &lt;code&gt;defineEmits()&lt;/code&gt; macro to declare custom events that a component can &lt;strong&gt;emit&lt;/strong&gt;. In the simplest case, pass an array of event names. In the template, trigger an event by passing its name to &lt;code&gt;$emit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"$emit('event')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, as with props, refer to the &lt;code&gt;defineEmits&lt;/code&gt; result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineEmits&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;buttonClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;event&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the parent component, listen with &lt;code&gt;@&lt;/code&gt; (shorthand for &lt;code&gt;v-on:&lt;/code&gt;) before the declared event name. When the child emits &lt;code&gt;event&lt;/code&gt;, the parent’s &lt;code&gt;foo&lt;/code&gt; method is called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ChildComponent&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;event=&lt;/span&gt;&lt;span class="s"&gt;"foo()"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To pass data upward along with the fact that something happened, events can declare payloads whose values are sent with them. Details here: &lt;a href="https://vuejs.org/guide/typescript/composition-api.html#typing-component-emits" rel="noopener noreferrer"&gt;typing component emits&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Provide/Inject
&lt;/h3&gt;

&lt;p&gt;Passing &lt;strong&gt;props&lt;/strong&gt; works well when the component tree is flat. As components nest deeper, you may find you are passing some props only to forward them further down, until finally a deep child uses them. This can lead to the anti‑pattern known as &lt;em&gt;prop drilling&lt;/em&gt;. The result is a tightly coupled structure that is hard to maintain because a change in internal implementation forces you to adjust prop definitions in many intermediate components.&lt;/p&gt;

&lt;p&gt;Vue sidesteps this with &lt;code&gt;provide&lt;/code&gt; and &lt;code&gt;inject&lt;/code&gt;. Using &lt;code&gt;provide()&lt;/code&gt; you can declare that a component exposes some data to all its descendants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Provided the component is in the ancestor chain, a descendant can request the data with &lt;code&gt;inject()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also provide data globally at the application level using &lt;code&gt;app.provide()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While this distribution mechanism may seem useful at first; in my experience I’ve rarely used it. In practice I find state‑management libraries work better (see below). It’s good to know the option exists, though.&lt;/p&gt;

&lt;p&gt;We don’t have a similar problem with &lt;strong&gt;emits&lt;/strong&gt; because events naturally bubble up the &lt;strong&gt;DOM tree&lt;/strong&gt; and it’s up to you where to catch them. &lt;em&gt;Additionally, Vue lets you play with event behavior via &lt;a href="https://vuejs.org/guide/essentials/event-handling.html#event-modifiers" rel="noopener noreferrer"&gt;modifiers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A brief comment on the &lt;strong&gt;DOM&lt;/strong&gt;: it stands for &lt;em&gt;Document Object Model&lt;/em&gt;, the internal representation of an HTML document - tags, their attributes, and content. By nature it’s a tree-like structure from the &lt;em&gt;root&lt;/em&gt; element down to the deepest descendants. A lightweight JavaScript variant is the &lt;strong&gt;virtual DOM&lt;/strong&gt;, and because manipulating its objects is much faster and more efficient than touching the real DOM, Vue and other frameworks primarily work with it and only then project the result into actual HTML for rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  v-model
&lt;/h3&gt;

&lt;p&gt;A common scenario in interactive apps is a component that accepts an initial value, lets the user work with it, and notifies the parent when it changes. A typical example is a form input.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;v-model&lt;/code&gt; directive in combination with the &lt;code&gt;defineModel&lt;/code&gt; macro provides a more straightforward definition for this. You can create a simple &lt;code&gt;Child.vue&lt;/code&gt; component like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"model"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt; &lt;span class="na"&gt;setup&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And call it just as simply from &lt;code&gt;Parent.vue&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Child&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vue automatically ensures that user input updates &lt;code&gt;foo&lt;/code&gt;; there’s no need to wire extra handlers. Another nice simplification of routine tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  State management
&lt;/h3&gt;

&lt;p&gt;The mechanisms above work fine for simpler apps. As the number of components and interactions grows, constantly thinking about where to wire connections becomes annoying. In such cases, raise the problem a level up and keep the state in one place across the entire application.&lt;/p&gt;

&lt;p&gt;Nuxt provides the &lt;a href="https://nuxt.com/docs/4.x/api/composables/use-state" rel="noopener noreferrer"&gt;&lt;code&gt;useState&lt;/code&gt;&lt;/a&gt; composable, which is sufficient for less complex data on its own. The de facto standard for state management in Vue is currently &lt;strong&gt;Pinia&lt;/strong&gt;, which makes it easy to create, maintain, and safely use global state anywhere in a Vue (Nuxt) app. More on this later in a separate article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reactivity
&lt;/h2&gt;

&lt;p&gt;Vue’s true power appears when you start working with dynamically changing data. For example, after clicking a button, you want the &lt;em&gt;“number of clicks”&lt;/em&gt; value to update. You register a &lt;code&gt;click&lt;/code&gt; listener, increment a variable… and then what? How to force a redraw on the screen? Should you reach into the DOM and edit an element’s text content? None of that - in Vue it just &lt;em&gt;“happens”&lt;/em&gt; thanks to reactivity.&lt;/p&gt;

&lt;p&gt;In the Vue world, reactivity means you can create special wrapper objects around data that automatically track value changes and &lt;strong&gt;react&lt;/strong&gt; by propagating them to &lt;strong&gt;every place&lt;/strong&gt; where the value is used. Different frameworks solve this general notification problem differently. Vue offers the &lt;a href="https://vuejs.org/api/reactivity-core.html" rel="noopener noreferrer"&gt;Reactivity API&lt;/a&gt; that makes it straightforward.&lt;/p&gt;

&lt;p&gt;We won’t dive deep into the technical background here. If you’re interested, continue with &lt;a href="https://vuejs.org/guide/extras/reactivity-in-depth.html" rel="noopener noreferrer"&gt;Reactivity in depth&lt;/a&gt; in the docs. For now, three functions suffice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ref()&lt;/code&gt; - takes a primitive/object/array and wraps it so the return value is reactive. Wherever you use it, it updates in the future whenever it changes. Such objects (&lt;strong&gt;refs&lt;/strong&gt;) can be used in templates, passed as function arguments or even as &lt;strong&gt;props&lt;/strong&gt; to components and carry their reactivity with them. The small cost is writing &lt;code&gt;name.value&lt;/code&gt; when used in scripts to access the inner value. Inside &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; suffices because the compiler fills in &lt;code&gt;.value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;computed()&lt;/code&gt; - takes a callback function that automatically re‑runs if a reactive change is detected inside - i.e., when some value the system tracks changes. This defines dynamic computations. For example, for a simple adder, you can define two &lt;code&gt;ref()&lt;/code&gt; values bound to user input, and their sum is &lt;code&gt;computed(() =&amp;gt; a.value + b.value)&lt;/code&gt;. Whenever the user changes one of the inputs, the result re‑computes immediately.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;watch()&lt;/code&gt; - allows observing a reactive value and performing a &lt;em&gt;side effect&lt;/em&gt; whenever it changes. The first argument determines the value to watch; the second is the callback to run on change. For example, you could track the count of failed login attempts and, after exceeding a limit, set a variable that disables the &lt;em&gt;“Log in”&lt;/em&gt; button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That was a whirlwind tour. The reactivity system is, of course, more complex; more functions exist and offer various options. You can read them as needed. Even with these three basics, you can cover many scenarios.&lt;/p&gt;

&lt;p&gt;It’s more worth pointing out a pitfall now. In my experience, the ease of use tends to tempt overuse in places where it’s not needed. As an application grows, especially with &lt;code&gt;computed()&lt;/code&gt; and &lt;code&gt;watch()&lt;/code&gt;, more and more re‑evaluations happen and a seemingly small change can cause a cascade of calls, not to mention the subsequent manipulations of the DOM. Vue cleverly batches reactive updates and optimizes DOM work, but background load still grows. It also becomes difficult to trace update flows when debugging hidden changes that shouldn’t occur.&lt;/p&gt;

&lt;p&gt;To make the problem worse, at first you might not even realize there is any. All reactivity operations run quietly in the background and, because Vue is well optimized for performance, you won’t notice anything wrong in simple apps. When it starts catching up with you, refactoring and optimizing can be quite hard already. It’s better to approach reactivity skeptically from the start - don’t ask &lt;em&gt;“what can I make reactive”&lt;/em&gt;, but &lt;em&gt;“what doesn’t need to be reactive”&lt;/em&gt;, because it won’t actually change, or it can be solved otherwise than adding &lt;code&gt;computed()/watch()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Still, it’s a very powerful tool and an integral part of a Vue developer’s arsenal. Just beware the &lt;em&gt;Man with a Hammer&lt;/em&gt; syndrome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Component lifecycle
&lt;/h2&gt;

&lt;p&gt;Reactive or not, a Vue component instance is not a static entity. It goes through several phases of its virtual life. Very briefly and simply:&lt;/p&gt;

&lt;p&gt;1) When the compiler determines a new instance should be created, it first runs the code inside &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;. Variables are created and initial reactive state is set.&lt;br&gt;
2) The &lt;strong&gt;mount&lt;/strong&gt; phase begins, when the necessary HTML structure is created inside the virtual DOM that Vue uses to control what ultimately gets rendered. The finished component is then displayed.&lt;br&gt;
3) The mounted component can enter the &lt;strong&gt;update&lt;/strong&gt; phase if a relevant reactive state change is detected - values are recalculated, the virtual DOM is patched, and the HTML is re‑rendered.&lt;br&gt;
4) The component is &lt;strong&gt;unmounted&lt;/strong&gt; because different content is rendered, navigation occurs, or the app exits.&lt;br&gt;
5) The component instance ceases to exist.&lt;/p&gt;

&lt;p&gt;Before and after each &lt;strong&gt;mount&lt;/strong&gt;, &lt;strong&gt;update&lt;/strong&gt;, and &lt;strong&gt;unmount&lt;/strong&gt; phase, you can register a callback that Vue runs every time it reaches that point. Use the special &lt;em&gt;lifecycle hooks&lt;/em&gt; functions &lt;code&gt;onBeforeMount()&lt;/code&gt;, &lt;code&gt;onMounted()&lt;/code&gt;, etc. This can be useful if, for example, you want to show a message that page initialization completed or release resources after the component is done.&lt;/p&gt;

&lt;p&gt;Beware of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async functions are &lt;strong&gt;not awaited&lt;/strong&gt; here. If needed, put &lt;code&gt;await&lt;/code&gt; directly in &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;. An async function inside &lt;code&gt;onBeforeMount()&lt;/code&gt; &lt;strong&gt;does not&lt;/strong&gt; guarantee that DOM mounting starts only after it finishes.&lt;/li&gt;
&lt;li&gt;Don’t place hook registration inside an asynchronous block (e.g., within &lt;code&gt;setTimeout&lt;/code&gt;). As soon as &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt; finishes synchronously, Vue loses the current component instance context, so there is nothing to attach to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information, including a clear diagram, can be found &lt;a href="https://vuejs.org/guide/essentials/lifecycle.html" rel="noopener noreferrer"&gt;HERE&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article is already quite long, even though we only skimmed the surface of most topics and didn’t start many others. I repeat my tip from the beginning - read the &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue documentation&lt;/a&gt;, where you’ll find much more. There is, of course, an extensive &lt;a href="https://nuxt.com/" rel="noopener noreferrer"&gt;documentation for Nuxt&lt;/a&gt; too.&lt;/p&gt;

&lt;p&gt;At this point, you should be armed with enough knowledge about Vue and the Nuxt framework to start building larger, more realistic apps yourself. To make them look good, in the &lt;a href="https://dev.to/aloisseckar/nuxt-tutorial-7-adopting-css-1m2a"&gt;next part of the tutorial&lt;/a&gt;, we’ll show how to integrate CSS with little to no effort.&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>learning</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
