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.
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.
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…
router-link
with nuxt-link
in the whole application.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.
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.
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,
yarn add -D tailwindcss @nuxtjs/tailwindcss
css: ["~/assets/css/global.css", "~/assets/css/app.css"],
@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.
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/.
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,
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);
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());
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>
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
});
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();
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.
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.
Let's Work Together
Not sure where to start? We also offer code and architecture reviews, strategic planning, and more.