Skip to content

Take your App to the Next Level with Vue 3

Take your App to the Next Level with Vue 3

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

Vue 3 has now officially launched and you are probably wondering how you are going to start migrating your existing Vue 2 apps to Vue 3.

I will be honest with you: a framework migration is always the most tedious and painstaking task you will ever encounter. The good news is that migrating from Vue 2 to Vue 3 is not that difficult and complicated.

As you may know, Vue 3 source code has been written from scratch. However, the maintainers of the framework made sure not to change the API too much. In other words, we will benefit from all the goodies Vue 3 brings, with minimal change. How awesome is that?!

Vue 3 Official Migration Guide

The Vue documentation website has been refreshed to reflect the latest changes. The Vue community has maintained the best documentation to help us learn and use Vue.

The Vue documentation dedicates a section on Vue 3 Migration making mention of the new features, the breaking changes for Vue 2 apps, the supporting libraries like Vue CLI, Vuex, Vue Router and others. The website explicitly states that the team is still working on a dedicated migration guide from Vue 2 to Vue 3.

Vue 3 Migration Guide Announcement

Meanwhile, until an official migration guide is released, let’s get a little insight on what could possibly be involved if you were to tackle this for yourself.

What to consider before upgrading to Vue 3?

As Vue 3 is still new, there will be some things to keep in mind. There are thousands of applications and third-party libraries created for Vue 2 and even Vue 1.5. It’s going to be a lengthy and time consuming effort to migrate all those libraries to support Vue 3.

Before you attempt any migration process, make sure all the libraries you use are supported by Vue 3. For instance, Vuetify isn't. You can read more about this here.

In addition, if you use any of the third-party libraries, they need to be checked or you might find they have upgraded already.

Moreover, the Vue 3 reactivity system has been rewritten to utilize the new language features in ES2015. Vue 3 uses proxies for its reactivity system instead of the Object.defineProperty() function.

JavaScript proxies are supported by most modern browsers. Unfortunately, Proxies cannot be polyfilled for older browsers; therefore, Vue 3 offers two implementations of it’s reactivity system. One implementation will use proxies for the most recent and modern browsers. The other one will fall back to the Vue 2 way of implementing reactivity to support the older browsers.

Step by Step Migration - Demo

In this section, we'll go through migrating the This Dot - Vue Meetup website. The existing website is built with Vue 2.

It’s essential to follow the steps below as is. Of course, depending on the features you’ve used, you will adjust this workflow to fit your needs and migrate more features in your apps.

Let's start!

Step 1: Create a new Git branch

It’s important to start off with a brand new branch to play around with the migration. This way your main branches, like master or dev, will remain intact without disrupting any live code.

Let’s assume we are branching from the master branch. Run the following command to create a new branch:

git checkout master && git pull
git checkout -b upgrade-to-vue3

Step 2: Install the latest Vue CLI version

Currently, as of the time of writing this article, the latest version of the Vue CLI is 4.5.6.

To install the latest version, run the following command:

npm install -g @vue/cli

Verify the installation by running the following command and making sure it reads as @vue/cli 4.5.6:

vue --version

Upgrading the Vue CLI not only helps in upgrading the existing application, but it also gives you the chance to scaffold a new Vue 3 app in the future.

Step 3: Upgrade the Vue libraries

The next step is to upgrade the Vue NPM packages and all other packages used inside the package.json file.

To start with, open the package.json file and make sure to amend the Vue libraries with the following versions:

"vue": "^3.0.0",
"vue-router": "^4.0.0-beta.11"
"vuex": "^v4.0.0-beta.4"

Now, let’s upgrade the rest of the libraries using the Vue CLI. Run the following command to start upgrading the libraries:

vue upgrade

The command goes through all the libraries you are using inside the package.json file and tries to upgrade them to the latest compatible version.

Vue Upgrade Prompt

For example, when I run this command, the Vue CLI detects the Vue libraries that need to be upgraded and prompts for confirmation:

Type Y to continue with the upgrade.

In summary, the upgrade reported the following packages changes, additions, and removal.

EsLint Upgrade

While the CLI is upgrading the @vue/cli-plugin-eslint it will also upgrade the current ESLint version installed on your computer. The latest Vue CLI supports ESLint v6. Once again, the Vue CLI prompts for confirmation before upgrading ESLint.

Type Y to continue with the upgrade.

added 131 packages from 157 contributors, removed 34 packages, updated 90 packages, moved 3 packages and audited 1908 packages in 19.798s

The numbers will definitely be different for you and depending on the app.

It’s now time to run the app and make sure you don’t have missing libraries or other problems. In my case, I ran the app and got a few ESLint issues. Luckily, the Vue CLI comes packaged with a command to auto fix ESLint issues. In this case, you run the npm run lint and the Vue CLI handles the rest for you!

Step 4: Add the @vue/compiler-sfc NPM package

The @vue/compiler-sfc package contains lower level utilities that you can use if you are writing a plugin / transform for a bundler or module system that compiles Vue single file components into JavaScript. It is used in the vue-loader.

This is an essential component if you are using Single File Components which is the case in most of the Vue apps.

Let’s install this package by running the following command:

npm i @vue/compiler-sfc

Let’s move on and start upgrading the source code to use the latest APIs offered by Vue 3.

Step 5: Upgrade the main.js file

Vue 3 changes the way an application is created by introducing the createApp() function. Back in Vue 2 and earlier versions, we used to create a global Vue instance. This approach had several disadvantages. The main one had third-party libraries to making changes to our Vue single App instance.

By introducing createApp(), you can instantiate multiple Vue apps side by side. It creates a context or boundary for your app instance where you do all the registration as you will see shortly.

Typically, a Vue app is started inside the main.js file. Let’s visit this file and make the necessary changes to upgrade to Vue 3.

import Vue from "vue";

import App from "./App.vue";
import GlobalVarMixin from "./mixins/global-variables-mixin";
import router from "./router";

import VueAnalytics from "vue-analytics";

//layouts
import Default from "./1.layouts/l-default.vue";
import Form from "./1.layouts/l-form.vue";
import Content from "./1.layouts/l-content.vue";

Vue.component("l-default", Default);
Vue.component("l-form", Form);
Vue.component("l-content", Content);

Vue.mixin(GlobalVarMixin);

if (process.env.VUE_APP_GOOGLE_ANALYTICS_ID) {
  Vue.use(VueAnalytics, {
    id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID,
    router
  });
} else {
  console.log("Google Analytics not loaded");
}

Vue.config.productionTip = false;

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

This is a slimmed down version of the original main.js file in the app. Let’s dissect the file one line at a time and upgrade accordingly.

import Vue from "vue";

Replace the line above with:

import { createApp } from "vue";

Let’s replace the code that’s creating the app using the Vue 3 createApp() function.

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");

Replace with:

const app = createApp(App);

The app variable now holds a new Vue app instance for us. The router instance will be registered separately.

Let’s update the Vue component registration.

Vue.component("l-default", Default);
Vue.component("l-form", Form);
Vue.component("l-content", Content);

Replace with:

app.component("l-default", Default);
app.component("l-form", Form);
app.component("l-content", Content);

With Vue 3, you register components at the app instance level and not globally.

Let’s update the Vue mixin registration.

Vue.mixin(GlobalVarMixin);

Replace with:

app.mixin(GlobalVarMixin);

Now register the router on the app instance as follows:

app.use(router);

Now let’s register the vue-analytics plugin on the app instance.

if (process.env.VUE_APP_GOOGLE_ANALYTICS_ID) {
  Vue.use(VueAnalytics, {
    id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID,
    router
  });
} else {
  console.log("Google Analytics not loaded");
}

Replace with:

if (process.env.VUE_APP_GOOGLE_ANALYTICS_ID) {
  app.use(VueAnalytics, {
    id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID,
    router
  });
} else {
  console.log("Google Analytics not loaded");
}

The plugin is now installed on the app instance rather than the global Vue instance. This is also valid for any other plugin out there.

Make sure to remove the line below as it’s not needed anymore in Vue 3 apps:

Vue.config.productionTip = false;

Finally, let’s mount the app instance by using the following:

app.mount("#app");

The final version of the upgrade main.js file looks like this:

import { createApp } from "vue";

import App from "./App.vue";
import router from "./router";
import GlobalVarMixin from "./mixins/global-variables-mixin";
import VueAnalytics from "vue-analytics";

//layouts
import Default from "./1.layouts/l-default.vue";
import Form from "./1.layouts/l-form.vue";
import Content from "./1.layouts/l-content.vue";

const app = createApp(App);

app.component("l-default", Default);
app.component("l-form", Form);
app.component("l-content", Content);
app.mixin(GlobalVarMixin);

app.use(router);

if (process.env.VUE_APP_GOOGLE_ANALYTICS_ID) {
  app.use(VueAnalytics, {
    id: process.env.VUE_APP_GOOGLE_ANALYTICS_ID,
    router
  });
} else {
  console.log("Google Analytics not loaded");
}

app.mount("#app");

That’s it!

Step 6: Upgrade the router.js file

The Vue Router has undergone changes and it’s now under v4.0.

Let’s review what the current router.js file looks like:

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

export default new Router({
  routes: [
    ...
  ],
  scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      return { selector: to.hash };
    } else if (savedPosition) {
      return savedPosition;
    } else {
      return { x: 0, y: 0 };
    }
  }
});

Replace the import statements with the following line:

import { createRouter, createWebHashHistory } from "vue-router";

Instead of creating a new instance of the Router object, we will be using the new function provided by Vue Router which is createRouter().

export default createRouter({
  history: createWebHashHistory(),
  routes: [...]
})

The router.js file now exports an instance of the Router object using the createRoute() function. This function expects an input parameter of type object. The routes and history properties are the minimum accepted to pass into this object.

The routes array is still the same as in Vue 2. It’s an array of routes, nothing has changed here.

The createWebHashHistory() function is now used to specify a Hash History mode in the Vue Router. As a side note, depending on what you are using in your app, there is also the createWebHistory() function that sets the mode to HTML 5.

You can read more about History Modes.

Next, we will update the scrollBehavior() function as it has undergone some major changes.

Replace the existing function with the following:

scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      return {
        el: to.hash,
        behavior: "smooth"
      };
    } else if (savedPosition) {
      return savedPosition;
    } else {
      return { top: 0 };
    }
  }

You can read more about Scroll Behavior in the Vue Router 4.0.

Now, let’s run the app and see if everything works as expected.

When I run the app, I get the following warning in the Dev Tools:

<router-view> can no longer be used directly inside <transition> or <keep-alive>.
Use slot props instead:

<router-view v-slot="{ Component }">
  <transition>
    <component :is="Component" />
  </transition>
</router-view>

This warning has to do with Vue Router and the Transition component. You can read more about the Transitions in Vue Router.

Let’s navigate to the App.vue component and check what the current source code is:

 <div>
    <transition :name="transitionName">
      <router-view :key="$route.params.slug || 'default'" />
    </transition>
  </div>

In Vue Router v4.0, you can no longer nest a <router-view> component inside a <transition> component. The fix is simple and provided to you in the documentation.

Replace the above with the following:

<div>
    <router-view :key="$route.params.slug || 'default'" v-slot="{ Component }">
      <transition :name="transitionName">
          <component :is="Component" />
      </transition>
    </router-view>
  </div>

These were all the steps needed to upgrade the Vue Meetup app.

Others

I’d like to draw your attention to a few more things when upgrading your apps to Vue 3.

One of the components in the app had a single slot; that is, the default slot. The way it was used in the Vue 2 app was:

...
<template></template>
...

When I ran the app, the component was showing nothing, an empty screen! It seems Vue 2 was more tolerant by not forcing me to specify the name of the slot, even though this is the default slot.

The quick fix in Vue 3 is as follows:

...
<template #default>
 ...
</template>

Something else I didn’t mention is the Vuex v4.0. The same steps that we followed to upgrade the Vue Router can be followed here. The approach is similar.

You can read more about the Vuex v4.0 Breaking Changes.

Conclusion

I am pretty sure we will all face more issues and encounter different hiccups while upgrading our apps. It will all depend on the features of your Vue 2. Remember, everything has a solution! While we wait for the Vue team to share an official migration guide, start trying to upgrade and see how you go.

If you get stuck, feel free to drop me a message on twitter using my Twitter handle @bhaidar.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Nuxt DevTools v1.0: Redefining the Developer Experience Beyond Conventional Tools cover image

Nuxt DevTools v1.0: Redefining the Developer Experience Beyond Conventional Tools

In the ever-evolving world of web development, Nuxt.js has taken a monumental leap with the launch of Nuxt DevTools v1.0. More than just a set of tools, it's a game-changer—a faithful companion for developers. This groundbreaking release, available for all Nuxt projects and being defaulted from Nuxt v3.8 onwards, marks the beginning of a new era in developer tools. It's designed to simplify our development journey, offering unparalleled transparency, performance, and ease of use. Join me as we explore how Nuxt DevTools v1.0 is set to revolutionize our workflow, making development faster and more efficient than ever. What makes Nuxt DevTools so unique? Alright, let's start delving into the features that make this tool so amazing and unique. There are a lot, so buckle up! In-App DevTools The first thing that caught my attention is that breaking away from traditional browser extensions, Nuxt DevTools v1.0 is seamlessly integrated within your Nuxt app. This ensures universal compatibility across browsers and devices, offering a more stable and consistent development experience. This setup also means the tools are readily available in the app, making your work more efficient. It's a smart move from the usual browser extensions, making it a notable highlight. To use it you just need to press Shift + Option + D (macOS) or Shift + Alt + D (Windows): With simple keystrokes, the Nuxt DevTools v1.0 springs to life directly within your app, ready for action. This integration eliminates the need to toggle between windows or panels, keeping your workflow streamlined and focused. The tools are not only easily accessible but also intelligently designed to enhance your productivity. Pages, Components, and Componsables View The Pages, Components, and Composables View in Nuxt DevTools v1.0 are a clear roadmap for your app. They help you understand how your app is built by simply showing its structure. It's like having a map that makes sense of your app's layout, making the complex parts of your code easier to understand. This is really helpful for new developers learning about the app and experienced developers working on big projects. Pages View lists all your app's pages, making it easier to move around and see how your site is structured. What's impressive is the live update capability. As you explore the DevTools, you can see the changes happening in real-time, giving you instant feedback on your app's behavior. Components View is like a detailed map of all the parts (components) your app uses, showing you how they connect and depend on each other. This helps you keep everything organized, especially in big projects. You can inspect components, change layouts, see their references, and filter them. By showcasing all the auto-imported composables, Nuxt DevTools provides a clear overview of the composables in use, including their source files. This feature brings much-needed clarity to managing composables within large projects. You can also see short descriptions and documentation links in some of them. Together, these features give you a clear picture of your app's layout and workings, simplifying navigation and management. Modules and Static Assets Management This aspect of the DevTools revolutionizes module management. It displays all registered modules, documentation, and repository links, making it easy to discover and install new modules from the community! This makes managing and expanding your app's capabilities more straightforward than ever. On the other hand, handling static assets like images and videos becomes a breeze. The tool allows you to preview and integrate these assets effortlessly within the DevTools environment. These features significantly enhance the ease and efficiency of managing your app's dynamic and static elements. The Runtime Config and Payload Editor The Runtime Config and Payload Editor in Nuxt DevTools make working with your app's settings and data straightforward. The Runtime Config lets you play with different configuration settings in real time, like adjusting settings on the fly and seeing the effects immediately. This is great for fine-tuning your app without guesswork. The Payload Editor is all about managing the data your app handles, especially data passed from server to client. It's like having a direct view and control over the data your app uses and displays. This tool is handy for seeing how changes in data impact your app, making it easier to understand and debug data-related issues. Open Graph Preview The Open Graph Preview in Nuxt DevTools is a feature I find incredibly handy and a real time-saver. It lets you see how your app will appear when shared on social media platforms. This tool is crucial for SEO and social media presence, as it previews the Open Graph tags (like images and descriptions) used when your app is shared. No more deploying first to check if everything looks right – you can now tweak and get instant feedback within the DevTools. This feature not only streamlines the process of optimizing for social media but also ensures your app makes the best possible first impression online. Timeline The Timeline feature in Nuxt DevTools is another standout tool. It lets you track when and how each part of your app (like composables) is called. This is different from typical performance tools because it focuses on the high-level aspects of your app, like navigation events and composable calls, giving you a more practical view of your app's operation. It's particularly useful for understanding the sequence and impact of events and actions in your app, making it easier to spot issues and optimize performance. This timeline view brings a new level of clarity to monitoring your app's behavior in real-time. Production Build Analyzer The Production Build Analyzer feature in Nuxt DevTools v1.0 is like a health check for your app. It looks at your app's final build and shows you how to make it better and faster. Think of it as a doctor for your app, pointing out areas that need improvement and helping you optimize performance. API Playground The API Playground in Nuxt DevTools v1.0 is like a sandbox where you can play and experiment with your app's APIs. It's a space where you can easily test and try out different things without affecting your main app. This makes it a great tool for trying out new ideas or checking how changes might work. Some other cool features Another amazing aspect of Nuxt DevTools is the embedded full-featured VS Code. It's like having your favorite code editor inside the DevTools, with all its powerful features and extensions. It's incredibly convenient for making quick edits or tweaks to your code. Then there's the Component Inspector. Think of it as your code's detective tool. It lets you easily pinpoint and understand which parts of your code are behind specific elements on your page. This makes identifying and editing components a breeze. And remember customization! Nuxt DevTools lets you tweak its UI to suit your style. This means you can set up the tools just how you like them, making your development environment more comfortable and tailored to your preferences. Conclusion In summary, Nuxt DevTools v1.0 marks a revolutionary step in web development, offering a comprehensive suite of features that elevate the entire development process. Features like live updates, easy navigation, and a user-friendly interface enrich the development experience. Each tool within Nuxt DevTools v1.0 is thoughtfully designed to simplify and enhance how developers build and manage their applications. In essence, Nuxt DevTools v1.0 is more than just a toolkit; it's a transformative companion for developers seeking to build high-quality web applications more efficiently and effectively. It represents the future of web development tools, setting new standards in developer experience and productivity....

Getting started with Vitepress cover image

Getting started with Vitepress

Getting started with Vitepress to create your blog site Have you heard about Vitepress, but you have not checked it out at it yet? Well, in this article, we are going to cover the basic setup and share what all the fuss about this new fantastic static site generator. If you are looking for something that would allow you to quickly create a static site with Markdown support, search, Light/Dark theme, advertisement, navigation, and much more, then Vitepress is what you are looking for. Suppose you want some proof of Vitepress's power without having to invest any further time, I suggest you head over to the main Vitepress site (vitepress.dev) and experience what Vitepress can do, as the official site is built on Vitepress! What is Vitepress Vitepress is a powerful Static Site Generator powered by Vite mainly used for Documentation and Blogs with the default theme, and open to customization to be used for anything you may need it to with custom themes and theme overrides.. Vitepress power comes from its low learning curve, powerful configuration settings, and the ability to easily customize it. For example, internationalization is built-in, Theme toggling is built-in and even full-site searches require a single line in the config to be set up. What makes Vitepress so powerful is its extensive configuration and the fact that it can be customized by overriding the existing theme, creating your theme, or simply enhancing pages with custom Vue code. Prerequisites To successfully run the following demo, you will need: - Node.js version 18 or higher. - Terminal for accessing VitePress via its command line interface (CLI). - Text Editor with Markdown syntax support. - VSCode is recommended, along with the official Vue extension. Create your project To create the project, we will follow the steps shown in the official Getting Started guide. If you want to set up a Vitepress project quickly, run the following steps: - Create a new folder mkdir vitepress-tutorial - Access the folder cd vitepress-tutorial - Install Vitepress npm add -D vitepress - Run the Wizard npx vitepress init - Answer the questions: - Where should VitePress initialize the config? - Site title - Site Description - Theme - Do you want Typescript support? - run npm run docs:dev - Enjoy your site. After you run the above steps, your Vitepress will be ready and running as shown below What is available out of the box The site comes fully set up with enough to get you started. Let's see what features are available within the software: - Navbar: The site comes with a Navbar that already includes links to our blog pages - Light/Dark theme: Out of the box theming - Home page: Basic Homepage layout - Blogs: Two different blog posts with sidebar navigation All of the above is available with just 4 files! Let's move forward and see how to customize our app. Overriding the homepage It is time to modify our site by accessing its folders. What you will probably notice when opening the site, is that Vitepress follows a very simple file structure, in fact, a new installation just includes 4 extra files on top of the expected package.json and node_modules. Let's update our homepage to make it more unique. Because Vitepress follows a "file-system based router" we can find this file within the root of the project within a file called index.md. This file will be accessible at "/" or "/index.html" of your site. The content of the file is the following: ` As you can see, the file has no code in it, and it is just driven by configuration, or more specifically in this case Markdown frontmatter, that is a set of configurations accepted by markdown files that help you set up your options such as title, description, og:image. We will describe frontmatter in more detail later in the article. Before we jump into modifying the configuration of the file, you should know that Vitepress has a very extensive and well-detailed documentation site where you can find help if you are stuck or would like to learn more. In this case, we are overriding the "home" page, so the documentation can be found here: Home Page Default Theme configuration. If you read the current file within the homepage, you will notice that it defines a "layout" of "home". This layout displays a main header with CTAs and a set of feature blocks. There are three different layouts available in the Default theme: "home", "doc" and "page". The title and description have already been set from the information we provided from the installation wizard. But the rest is just a basic boiler template. Let's see what we can change: 1) Add a hero image. This image can either be externally sourced or saved within the repository. ` 2) Update the action buttons. ` As shown above, Action buttons have two themes "brand" or "alt" and can accept internal or external links. Vitepress is clever enough to set the external links to open in a new tab and set the rel="noreferrer". 3) Change the feature blocks: Features blocks are great for engaging with the user and telling them what makes your site special. This accepts an icon and some text, so let's change ours with the following: ` The homepage is now completed and updated and it should look like this: Please note that what we did on the homepage is just changing the markdown front matter of the "home" layout. What this means is that if you want to, you can easily customise the page further by either adding more blocks to the layout file or actually by writing and styling the rest of the page as normal. Site configuration In this step, we are going learn about the main site configuration and how we can use it to customize our site. The configuration file can be found in the .vitepress folder under the name of "config.mjs". Just like the homepage layout, the configuration used in the preset file is self-explanatory: ` This file is very important and you are probably going to have it open at all times as it is going to be responsible for the layout of the sidebar navigations of your site. In this section, we are going to learn how to use the Vitepress configuration file to achieve the following: - Modify the sidebar navigation - Enable Search - Add Favicon to your site Modify the sidebar navigation The sidebar is the component displayed on the left-hand side of the blog pages. This is not automatically generated, but it is manually set in this file. You can have more than one navigation, so, for example, you could specify sidebar navigation that shows in pages that have "/blog/" within their path and another one for all markdown pages that have "/tutorials/". Let's see how to implement this: ` With the above code, there will be 2 different sidebars. One will just show if the URL includes "/blog" and the other will be displayed if the path includes "tutorials". Clicking on the above items will give a 404 error as we do not have any pages in that specific location. Still, we can easily fix the issue by creating the two folders "blog" and "tutorial" and creating the required files within these folders in our case are "index.md" and "one.md" for the blog and "index.md" and "two.md" for tutorials. The sidebar has further settings like the ability to create a nested tree or create collapsable menus. You can learn more by checking out the the official documentation on default theme sidebar. Enable Search No documentation or blog site is complete until a search is fully implemented on it. Luckily for us, enabling a site-wide search is extremely simple with Vitepress. Vitepress supports two different search types: a full-text search using minisearch and Algolia based search. In this tutorial, we are going to enable the full-text search. This is fully built-in and requires no external accounts. To enable search, we need to add a "Search" parameter within our themeConfig and set the provider to "local". We can add this right below the socialLinks. ` With just a simple config change, our site will now have a full site search working as shown below: The official search documentation has further information about the look and functionality of the search. Add Favicon to your site Even if the site configuration is very extensive, there are times when you will need to add something within the site-wise page that is not available. In this section we are going to learn how to add specific attributes to the of our site, and specifically how to add a favicon. To add custom values to the head, we are going to use the "head" properties available with the Vitepress configuration. The "head" configuration is an array that accepts an array with the element type (eg. link, script, meta), and an object including all the attributes for that specific element. So for example to replicate the following HTML: ` we would define the following head config: ` We can use this technique to set up metadata and even load fonts or Google Analytics. More info in the site-config head Writing your post In the last section of this article, we are going to learn how to actually write a blog post and also learn how to customize the pages with JS and styles. Writing your first page In the previous section, we created a couple of markdown files, but they are currently empty. Let's see how to create beautiful documentation using the built-in feature of Vitepress. In this section, we are going to work on the file stored in /blog/index.md. This file can be accessed in your browser by accessing "http://localhost:5174/blog/index.html". Blog Frontmatter Every file needs to have a frontmatter defined. This is used to define basic information on the page, such as the title, description, and more. For best SEO results, it is best practice to always define a title and description for a new page. We can do this by adding the following code at the top of our file: ` Frontmatter in Markdown files are delimited by the "---". In the above code, we set our title and description. Vitepress frontmatter supports further config like lastUpdates, sidebar, outline, and more. You can find info on the frontmatter-config documentation. Frontmatter has some global configuration, such as title and description, but also "layout specific" settings that are just available on specific layouts. This is clearly explained in the documentation. Blog Markdown Now that our post frontmatter is set, it is time to write the content of it. This is done using a very extensive markdown engine. Let's start with the basics and write a heading with some text and a link as shown below: ` After saving, our development environment will show the following results: Let's add a couple of headings and a table of contents to our document using [[toc]] to the top of our page: ` The above will produce an unordered list with all our links. The last feature that I want to share about the Vitepress markdown engine is the code editors. The markdown engine used in Vitepress offers extensive features when it comes to code rendering. Features available are "code highlight", "code focus", external snippets loading and much more. The full list of features can be found in the markdown docs. Let's implement a simple code snippet with a line of code focused. This can be achieved by adding "// [!code focus]" at the end of our row. Let's give it a try: ` The output of this will be: Customize your blog with Vue In this last section, we will learn how to customize our code by adding js logic, style, and external components. Before we begin, it is important to understand that when you use the default template of Vitepress, your pages are going to be rendered with Vue. This means that we can expand the individual page's functionality by rendering other vue components and/or writing logic and styles directly on the page. To better explain this concept, we are going to create a team page. Create a file called team.md within the root of our repository. This file will be accessible on "http://localhost:5174/team.html" and will be just a simple Markdown file. First, we set up the frontmatter as before. In this case, we have to specify an additional config called "layout". This will ensure the page has no style or components loaded such as sidebar or aside. ` Then we will have to create our team variable, just like a normal Vue component; we can do so by defining a script setup tag and defining the constant there. ` In the above code, we have imported the VPTeamMembers component from the vitepress/theme and defined an array of members. The values used in the members array are hardcoded, but as you may expect, you can load this information directly from an API. We now have to use the "members" variable within our file. We can do so by writing normal JavaScript. The markdown file will evaluate the JavaScript and render it, so in the following example it will render a specific component. ` Before we move forward we need to define some style as the page is unstyled since we have loaded the layout of "page". Just like we did with the tag, we can load a tag and update our styles: ` The completed file will look like this: ` The file above now includes: - A frontmatter that specifies a "page" layout - A script tag that loads an external component and defines a variable - Styles to make the page pretty - Markdown with a custom component The completed team page would render the following: Conclusion Vitepress is an extremely flexible static site generator. Its default theme provides you with everything you need to get started quickly. The ability to load external themes, enhance the current theme, and or write custom code within your page makes this tool extremely powerful. In future articles, we will discover what components are available within the Default Theme and see how you can make the most of your Vitepress site but keep on coding....

Async Components in Vue 3 cover image

Async Components in Vue 3

Async Components have had their roots in the Vue JS framework since the second version release. However, in Vue 3, they've had a revamped facelift and their API is a well defined and clear API interface. Async components are best used in medium to large apps. When an app is formed out of several hundred components, it's wise not to load all the components at once in a single chunk. Rather, the recommendation is to split the components' packing into a set of smaller packages that get loaded whenever needed asynchronously. While developing, nothing will change in terms of using and placing components inside the section. However, only importing those components will change slightly. Vue 3 offers an intuitive and clear API to help you define the async components. In this article, we'll explore the new Async Components API, delve into the details and show it in action. Async Components In Action Before we go further, here's a link to the Async Components RFC to keep as a reference for later. The new API offers the defineAsyncComponent() method that you use to define the Async Components. This method accepts a callback function. In return, this callback function should return an instance of a Promise. Async Load Inline Defined Component In the simplest form, defining a local async component can be done as follows: ` > You can play with this example at codesandbox.io. Let's focus on the local variable named LocalComponent. This variable is assigned the result of calling the defineAsyncComponent() function. The result is a component named AsyncComponentWrapper that wraps around the loaded component. The callback passed to defineAsyncComponent() function accepts zero parameters and returns a new Promise. The Promise in this case, resolves an inline Vue Component using the Object Literal method that defines the template of the component returned. Figure 1 shows the app running. Async Load Standalone Defined Component The other way to load components async is to have a component defined in its own file and loaded asynchronously when needed. ` The StandaloneComponent is assigned the result of calling the defineAsyncComponent() function. The result is a component named AsyncComponentWrapper that wraps around the loaded component. The callback passed to defineAsyncComponent() function returns the Promise result returned by calling the import() function. The import() function in this context refers to the Dynamic Import feature in JavaScript. If you are running a Vue 3 app using the Vue CLI then the import() function refers to the Webpack Import function. Instead of defining the component-to-be-async-loaded inline, the code imports an existing standalone component: ` Figure 2 shows the app running. > You can play with this example at codesandbox.io Where to define Async Components? There are two main forms of defining async components in a Vue app. You've already seen one form, where the async component is defined locally inside the component. The other option is to define the async component globally at the app level: ` Figure 3 shows the app running. > You can play with this example at codesandbox.io Async Components API Defining an async component can take two forms: the simple usage and the options usage. Simple Usage So far you've seen how to define an async component the simple way. The defineAsyncComponent() method accepts a callback that returns a Promise. ` Options Usage The Async Component API offers a rich API to better control loading components asynchronously. ` > You can play with this example at codesandbox.io. The defineAsyncComponent() method now accepts an object with several options. Let's dissect this object! * loader: It's the bread and butter behind the API. The loader returns a Promise to load the component. Now you can clearly see that the simple usage of the API specifies only a loader! * loadingComponent: Is one you define to show to the user while the API loads the component asynchronously. * errorComponent: You define to show to the user when there is an error loading the component. * delay: It's the time elapse before showing the loadingComponent to the user. * timeout: It's the time elapsed between requesting the component and having it ready to render to the user. * suspensible: By default this property is set to false. This is useful when a component is wrapping a component that makes use of Async Component API to load components asynchronously. If the value of suspensible is set to true, then the component takes precedence in showing a fallback content. The loadingComponent, delay, and other properties of the API will be ignored in this case. If the value was kept false, then the API will take precedence over the component. > You can read more about Suspense in Vue 3. * onErorr: This function has been newly added to the Async Component API in Vue 3. It accepts a few parameters: error, retry, fail, and attempts. When the component fails to load, this function is called. error parameter gives details about the error that occurred. retry is a function callback that you can call to try loading the component again. fail is a function callback that you can call to stop any further trials of loading the component. Finally, the attempts are the number of attempts that were carried out in order to load the component. In brief, that is an introduction to the Async Components API in Vue 3....

Integrating Playwright Tests into Your GitHub Workflow with Vercel cover image

Integrating Playwright Tests into Your GitHub Workflow with Vercel

Vercel previews offer a great way to test PRs for a project. They have a predefined environment and don’t require any additional setup work from the reviewer to test changes quickly. Many projects also use end-to-end tests with Playwright as part of the review process to ensure that no regressions slip uncaught. Usually, workflows configure Playwright to run against a project running on the GitHub action worker itself, maybe with dependencies in Docker containers as well, however, why bother setting that all up and configuring yet another environment for your app to run in when there’s a working preview right there? Not only that, the Vercel preview will be more similar to production as it’s running on the same infrastructure, allowing you to be more confident about the accuracy of your tests. In this article, I’ll show you how you can run Playwright against the Vercel preview associated with a PR. Setting up the Vercel Project To set up a project in Vercel, we first need to have a codebase. I’m going to use the Next.js starter, but you can use whatever you like. What technology stack you use for this project won’t matter, as integrating Playwright with it will be the same experience. You can create a Next.js project with the following command: ` If you’ve selected all of the defaults, you should be able to run npm run dev and navigate to the app at http://localhost:3000. Setting up Playwright We will set up Playwright the standard way and make a few small changes to the configuration and the example test so that they run against our site and not the Playwright site. Setup Playwright in our existing project by running the following command: ` Install all browsers when prompted, and for the workflow question, say no since the one we’re going to use will work differently than the default one. The default workflow doesn’t set up a development server by default, and if that is enabled, it will run on the GitHub action virtual machine instead of against our Vercel deployment. To make Playwright run tests against the Vercel deployment, we’ll need to define a baseUrl in playwright.config.ts and send an additional header called X-Vercel-Protection-Bypass where we'll pass the bypass secret that we generated earlier so that we don’t get blocked from making requests to the deployment. I’ll cover how to add this environment variable to GitHub later. ` Our GitHub workflow will set the DEPLOYMENT_URL environment variable automatically. Now, in tests/example.spec.ts let’s rewrite the tests to work against the Next.js starter that we generated earlier: ` This is similar to the default test provided by Playwright. The main difference is we’re loading pages relative to baseURL instead of Playwright’s website. With that done and your Next.js dev server running, you should be able to run npx playwright test and see 6 passing tests against your local server. Now that the boilerplate is handled let’s get to the interesting part. The Workflow There is a lot going on in the workflow that we’ll be using, so we’ll go through it step by step, starting from the top. At the top of the file, we name the workflow and specify when it will run. ` This workflow will run against new PRs against the default branch and whenever new commits are merged against it. If you only want the workflow to run against PRs, you can remove the push object. Be careful about running workflows against your main branch if the deployment associated with it in Vercel is the production deployment. Some tests might not be safe to run against production such as destructive tests or those that modify customer data. In our simple example, however, this isn’t something to worry about. Installing Playwright in the Virtual Machine Workflows have jobs associated with them, and each job has multiple steps. Our test job takes a few steps to set up our project and install Playwright. ` The actions/checkout@v4 step clones our code since it isn’t available straight out of the gate. After that, we install Node v22 with actions/setup-node@v4, which, at the time of writing this article, is the latest LTS available. The latest LTS version of Node should always work with Playwright. With the project cloned and Node installed, we can install dependencies now. We run npm ci to install packages using the versions specified in the lock file. After our JS dependencies are installed, we have to install dependencies for Playwright now. sudo npx playwright install-deps installs all system dependencies that Playwright needs to work using apt, which is the package manager used by Ubuntu. This command needs to be run as the administrative user since higher privilege is needed to install system packages. Playwright’s dependencies aren’t all available in npm because the browser engines are native code that has native library dependencies that aren’t in the registry. Vercel Preview URL and GitHub Action Await Vercel The next couple of steps is where the magic happens. We need two things to happen to run our tests against the deployment. First, we need the URL of the deployment we want to test. Second, we want to wait until the deployment is ready to go before we run our tests. We have written about this topic before on our blog if you want more information about this step, but we’ll reiterate some of that here. Thankfully, the community has created GitHub actions that allow us to do this called zentered/vercel-preview-url and UnlyEd/github-action-await-vercel. Here is how you can use these actions: ` There are a few things to take note of here. Firstly, some variables need to be set that will differ from project to project. vercel_app in the zentered/vercel-preview-url step needs to be set to the name of your project in Vercel that was created earlier. The other variable that you need is the VERCEL_TOKEN environment variable. You can get this by going to Vercel > Account Settings > Tokens and creating a token in the form that appears. For the scope, select the account that has your project. To put VERCEL_TOKEN into GitHub, navigate to your repo, go to Settings > Secrets and variables > Actions and add it to Repository secrets. We should also add VERCEL_AUTOMATION_BYPASS_SECRETl. In Vercel, go to your project then navigate to Settings > Deployment Protection > Protection Bypass for Automation. From here you can add the secret, copy it to your clipboard, and put it in your GitHub action environment variables just like we did with VERCEL_TOKEN. With the variables taken care of, let’s take a look at how these two steps work together. You will notice that the zentered/vercel-preview-url step has an ID set to vercel_preview_url. We need this so we can pass the URL we receive to the UnlyEd/github-action-await-vercel action, as it needs a URL to know which deployment to wait on. Running Playwright After the last steps we just added, our deployment should be ready to go, and we can run our tests! The following steps will run the Playwright tests against the deployment and save the results to GitHub: ` In the first step, where we run the tests, we pass in the environment variables needed by our Playwright configuration that’s stored in playwright.config.ts. DEPLOYMENT_URL uses the Vercel deployment URL we got in an earlier step, and VERCEL_AUTOMATION_BYPASS_SECRET gets passed the secret with the same name directly from the GitHub secret store. The second step uploads a report of how the tests did to GitHub, regardless of whether they’ve passed or failed. If you need to access these reports, you can find them in the GitHub action log. There will be a link in the last step that will allow you to download a zip file. Once this workflow is in the default branch, it should start working for all new PRs! It’s important to note that this won’t work for forked PRs unless they are explicitly approved, as that’s a potential security hazard that can lead to secrets being leaked. You can read more about this in the GitHub documentation. One Caveat There’s one caveat that is worth mentioning with this approach, which is latency. Since your application is being served by Vercel and not locally on the GitHub action instance itself, there will be longer round-trips to it. This could result in your tests taking longer to execute. How much latency there is can vary based on what region your runner ends up being hosted in and whether the pages you’re loading are served from the edge or not. Conclusion Running your Playwright tests against Vercel preview deployments provides a robust way of running your tests against new code in an environment that more closely aligns with production. Doing this also eliminates the need to create and maintain a 2nd test environment under which your project needs to work....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co