How to Migrate Large Applications Efficiently from Vue.js To Nuxt.js

Step-by-step guide on how to migrate large applications from vuejs to Nuxtjs
Oct 10 2023 · 6 min read

Introduction

The underlying framework of the canopas website is vue.js. To get the benefits of easy-to-implement server-side rendering, improved meta tags, and SEO management, we recently migrated our website to Nuxt.js. 

For large-scale applications, migrating from Vue.js to Nuxt.js can be a complex and challenging attempt. This transition involves adapting your codebase to a new structure, architecture, and project layout, which can be a daunting task. However, with the right strategy and a clear plan in place, you can efficiently make the switch and take the benefits of Nuxt.js.

This blog post will guide you through the process of migrating a large Vue.js application to Nuxt.js. We will cover all the possible topics to help you tackle this migration. Whether you’re considering the move for better SEO, performance, or enhanced development workflows, this guide will provide you with valuable insights to make the transition as painless as possible. 

Healthy habits are the foundation for a successful and fulfilling migration experience. Try out Justly today for building healthy habits.

Create project

Let’s keep the vue project as it is. Create a new Nuxt project using the following command.

npx nuxi init <your-project-name>

It will ask some questions, and answer them based on your requirements. You will have a ready-to-run Nuxt.js project. Go inside the project and follow the below steps.

Directory structure changes

Pages and components

Pages are the UI that will show on each route like home, about, or career. Nuxt.js automatically creates routes based on pages you have created. Consider referring to Nuxt pages and router for more information.

Components are small units, that combine together and build a page. So, ultimately a page is nothing but the combination of multiple components.

You will get more ideas about it at canopas pages where each page is the route of the website and each page contains multiple components.

Changes you need…

  • Arrange your design in pages and components (if you haven’t done so already) and copy them to the Nuxt project.
  • Replace <NuxtWelcome /> with <NuxtPage /> in the app.vue, Which will render pages from the pages directory. And replace router-link with nuxt-link in the whole application.

Error pages

Error pages are the most important pages for the website, to let users know about maintenance or not found pages efficiently.

If you want to show a not found page on other routes than your application routes, add a hook in the nuxt.config like the below,

// Not found page
hooks: {
    "pages:extend"(pages) {
      pages.push({
        name: "Error404", // component name
        path: "/:pathMatch(.*)*",  // other routes then application routes
        file: "~/components/error404/index.vue", // relative path of the component
      });
    },
  },

If your application contains error handling from data, you can follow the Nuxt error handling guide.

Other files

There is no need to update the directory structure of Nuxt as it is mostly the same for Vue and Nuxt. Copy all files and directories like store, configs, assets, and utils from the Vue to the Nuxt project.

Add dependency modules

To use external dependencies like tailwind CSS or pinia, nuxt is providing its module to ensure compatibility. We need to add modules and nuxt will automatically use them with minimal configuration.

For this blog, we will configure tailwind CSS as a dependency module.

The steps are as follows,

  • Install tailwindcss.
yarn add -D tailwindcss @nuxtjs/tailwindcss
  • Copy the tailwind.conf file to the Nuxt project and add the path of CSS files(which were copied to Nuxt in the previous step) in the nuxt.config.
css: ["~/assets/css/global.css", "~/assets/css/app.css"],
  • Add @nuxtjs/tailwindcss to modules in the nuxt.config.
modules: ["@nuxtjs/tailwindcss"]

// For pinia, it is @pinia/nuxt. Install dependency and add it like below,
modules: ["@nuxtjs/tailwindcss", "@pinia/nuxt"]

You can find all modules listed at Nuxt modules.

Replace Icons

The icon module of Nuxt includes a vast variety of ready-to-use icons from Iconify. You can use it easily in place of Font-Awesome or material icons with zero configuration.

Perform the following steps to add Nuxt-icon to the project,

// Install nuxt-icon using,
yarn add -D nuxt-icon

// And add module in nuxt.config,
modules: ["@nuxtjs/tailwindcss", "@pinia/nuxt", "nuxt-icon"]

Now you can replace icons with the below syntax,

<!-- you can keep classes as it is -->
<Icon name="fa6-solid:star" class=""/>

You can find all icons and their ready-to-use names at https://icones.js.org/.

Convert to Composition API

To improve the performance and speed of dynamic pages, composition API offers more benefits than options API as we don’t need to call beforeMount or a created hook for fetching data as of options API.

If you have used options API for dynamic pages, it is sounder to convert them to composition API for more flexibility in fetching data.

Here is a sample example of options API,

<script type="module">
import { useJobListStore } from "@/stores/jobs";
import { mapState, mapActions } from "pinia";

export default {
  data() {
    return {
      currentIndex: 0,
      openList: true,
      previousIndex: 0,
    };
  },
  components: {
    CollapseTransition,
    FontAwesomeIcon,
  },
  mounted() {
    this.loadJobs();
  },
  computed: {
    ...mapState(useJobListStore, {
      careers: "items",
      jobsError: "error",
    }),
  },
  methods: {
    ...mapActions(useJobListStore, ["loadJobs"]),
    expandListItem(id, index) {
      if (this.previousIndex == id && this.openList) {
        this.openList = false;
      } else {
        this.openList = true;
      }
      this.currentIndex = id;
      this.previousIndex = this.currentIndex;
    },
  },
};
</script>

Here are steps to convert it to composition API,

1. Initialize variables

All the data variables from the options API will be initialized like below,

// You can define and use template refs same way as data given below.
// Find more info of template refs at, 
// https://vuejs.org/guide/essentials/template-refs.html

const currentIndex = ref(0);
const previousIndex = ref(0);
const openList = ref(true);

2. Data fetching

You can access the store directly in setup and get the properties of the store in a computed hook like below,

const careers = computed(() => store.items);
const jobsError = computed(() => store.error);

const store = useJobListStore();

// mapActions is no longer needed from pinia
await useAsyncData("jobs", () => store.loadJobs());

3. Methods and other hooks

You can directly write and access methods in the setup.

function expandListItem(id, index) {
  if (previousIndex.value == id && openList.value) {
    openList.value = false;  // use .value instead of this.
  } else {
    openList.value = true;
  }
  currentIndex.value = id;
  previousIndex.value = currentIndex.value;
}

Similarly, you can convert other lifecycle hooks easily using the composition API guide.

The final code is as,

<script setup>
import { useJobListStore } from "@/stores/jobs";

const currentIndex = ref(0);
const previousIndex = ref(0);
const openList = ref(true);

const careers = computed(() => store.items);
const jobsError = computed(() => store.error);

const store = useJobListStore();

await useAsyncData("jobs", () => store.loadJobs());

function expandListItem(id, index) {
  if (previousIndex.value == id && openList.value) {
    openList.value = false;
  } else {
    openList.value = true;
  }

  currentIndex.value = id;
  previousIndex.value = currentIndex.value;
}
</script>

Meta Properties

Nuxt.js provides built-in META tags support. You don’t need to use any external library. It provides many options for setting meta. I have used the useSeoMeta hook for setting meta tags on our website, as it's simple and easy to implement.

In the setup of each page, you can add it like the below,

useSeoMeta({
   title: 'title',
   description: 'description',
   ogTitle: 'title',
   ogType: 'type',
   ogUrl: 'url',
   ogImage: 'image-url',
   // ... other properties
});

Add global scope of dependencies

In large applications, there is a requirement of adding dependencies that will be used in the whole app and we need to access it across the pages.

In our case, it is Mixpanel. We have added Mixpanel analytics and need to inject it into the whole app. In this case, plugins are more handy stuff for easy implementation.

Create a plugins directory and add the mixpanel.js file inside it.

import mixpanel from "mixpanel-browser";

export default defineNuxtPlugin((nuxtApp) => {
  mixpanel.init(MIX_PANEL_TOKEN);
  // provide will inject mixpanel in whole app
  nuxtApp.provide("mixpanelName", mixpanel);
});

And register the plugin in the nuxt.config file.

plugins: [{ src: "~/plugins/mixpanel" }], // You can add multiple plugins

You can access it as $mixpanelName which we had declared in the provide() method of the plugin like below,

// for options api
inject: ["mixpanel"],  

// for composition api
const { $mixpanelName } = useNuxtApp();

Images and other media

Nuxt provides efficient ways to use images and other media with better SEO improvement.

You can replace all the images with the Nuxt-image. For fonts, nuxt has a google-fonts module. You can explore these modules and improve your website’s media performance.

Conclusion

With careful planning and an understanding of the key steps, you can successfully migrate to Nuxt.js, resulting in a web application that stands out in terms of performance, user experience, and developer productivity.

We’re Grateful to have you with us on this journey!

Suggestions and feedback are more than welcome! 

Please reach us at Canopas Twitter handle @canopas_eng with your content or feedback. Your input enriches our content and fuels our motivation to create more valuable and informative articles for you.

That’s it for today, keep exploring and growing.


Code, Build, Repeat.
Stay updated with the latest trends and tutorials in Android, iOS, and web development.
sumita-k image
Sumita Kevat
Sumita is an experienced software developer with 5+ years in web development. Proficient in front-end and back-end technologies for creating scalable and efficient web applications. Passionate about staying current with emerging technologies to deliver.
sumita-k image
Sumita Kevat
Sumita is an experienced software developer with 5+ years in web development. Proficient in front-end and back-end technologies for creating scalable and efficient web applications. Passionate about staying current with emerging technologies to deliver.
canopas-logo
We build products that customers can't help but love!
Get in touch

Let's Work Together

Not sure where to start? We also offer code and architecture reviews, strategic planning, and more.

cta-image
Get Free Consultation
footer
Follow us on
2024 Canopas Software LLP. All rights reserved.