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.
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...
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.
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).
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.
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.
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.
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.
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.
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!
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.