DEV Community

loading...

Leverage Vue and Nuxt to output components natively for websites using other technologies

tommcclean profile image Thomas William McClean ・5 min read

I have been working with VueJS at work and at home for almost 3 years, most often this involves building a fully fledged VueJS application, however there may be occasions when you might want to write a component in VueJS but render it on a website using legacy (PHP) or just different technologies (.NET).

Recently I needed to do just that; here is the story of how I did.

Alt Text

Background

A friend of mine runs a website called ACP (Animal Crossing Portal), a fansite for the very popular Animal Crossing game series. He wanted to release a guide that helps other players determine the value of their in-game characters. It really took off and became the most popular page on his website, drawing a lot of traffic from search engines, and was even featured on websites like EuroGamer and the Metro.

Given the popularity of the page, he wanted to make it more dynamic, more useful for his readers and he asked me to build a component to do just that. ACP is a PHP based website, and naturally I didn't want to go back in time and build a JQUERY based feature; I wanted to use my capabilities in VueJS to create a component that gave the best user experience possible. I also wanted a good developer experience for myself...

The Goal

Ultimately the goal was to be able to write a fully fledged VueJS component, but output it as native HTML, Javascript and CSS so that it could be simply inserted into an existing PHP page.

It needed to hydrate client side so that features responding to user actions would continue to work.

It needed to work well with SEO crawlers, meaning I would probably want to pre-render the HTML, rather than have an empty DIV which is hydrated into the component.

Options

Initially I looked into VueCLI, I knew it had the capability to output as a library, or as a web component; but unfortunately did not support a purely native output that would work in a PHP based site which also met the SEO goals (being pre-rendered).

I then looked into other javascript headless tools; but didn't find anything that was easy to implement and ticked all of the boxes, perhaps I (or you) need to write one; there is definitely a need.

Nuxt was the best option for me, out of the box it supports static generation, I believe the purpose of that was really so you could create documentation based websites, and host it on places like S3 or Github Pages; but it can useful in other cases too. Though I have to admit that while troubleshooting I didn't see anybody else trying to achieve the same thing as me yet.

Implementation

Creating the component was easy, using the generator npx create-nuxt-app I spin up a Nuxt Website and build the component as a page within the project. Naturally this part is the easiest bit if you have experience using VueJS already.

Doing this you can even leverage things like Vuex without any configuration because it comes out of the box with Nuxt. Vuex is very useful for making the whole thing easily testable and less bug prone.

Alt Text

Generating the static output from the Nuxt website was a little bit more challenging, to get my component into the PHP page I wanted to simply copy the rendered output and associated JS files into the PHP page and it 'just work', but I did run into a tricky problem (which I did eventually manage to solve (noted later in the post)).

When you have completed your component, running yarn generate or npm run generate uses the Nuxt out of the box generate tool and compiles your code which is placed in the dist folder. To get this working all you need to do is copy the JS files over to your website, and then copy the markup too.

Alt Text

You could even achieve this copy step by using a task runner like Gulp if your situation requires, certainly in a similar use case, but an otherwise different project; using Gulp we are bringing over the generated output into a .NET based application during compile time meaning we get pre-rendered and styled HTML but also the client side validation we implemented.

Problem and Solution: Route Matching (Universal Mode for pre-rendering)

If you create a page in Nuxt on the route /mypage but want to render it on the PHP website on a route like /villager-tier-list it won't work when using Nuxt in Universal mode (for pre-rendering). Essentially you need to output the Nuxt page on the same route as you intend for it to be hosted on the target website.

If you don't match the route, you will run into a series of very confusing errors, one DOMException error in particular is one of those errors that turns up for a lot of different reasons, when searching online I would find the solutions for everybody else did not work for me; because the underlying issue was different.

When this error comes up, you will see see pre-rendered markup, but any client side actions won't fire and a console error is logged.

Often people using static generation in Nuxt run into the DOMException when they are using invalid markup, or the client side hydration fails due to the DOM nodes not being consistent between SSR and CSR.

In my case it wasn't actually so complicated in the end, it was simply that the component would only work on the route I used to output it so changing the route in Nuxt solves the problem.

What if I don't need pre-rendering

A lot is said about SEO and javascript frameworks not being the best of friends, but if SEO isn't your ultimate goal, you can make things even simpler by turning Nuxt into spa mode and turning the router into hash mode. Doing this enables you to build a CSR component, where route matching is not a problem. It also means less HTML to copy around but you still keep all client side functionality!

Summary

So that's it really, I just wanted to write this post to offer a new option when it comes to adding functionality to a website that might not be built in VueJS from the start. We can use methods like this to add modern features to legacy codebases in an almost micro-service like fashion. This is a method I am looking to use in a few places at work and in personal projects where I might not have the luxury of a node based web environment.

Feel free to drop a comment if you are trying to do something similar.

Discussion

pic
Editor guide