Why Your Third-Party Plugin Don’t Work in Nuxt and How to Fix it

Christian Nwamba
4 min readAug 2, 2017

--

Pondered over a personal project idea for a while. Ended up using Vue just for fun (no technical reason for this choice). Details of this project are concealed but most importantly, I needed to:

  • Manage state
  • Generate dynamic routes
  • Render to server

SSR (Server-Side Rendering) was my major concern — state and routing could be taken care of in couple of minutes.

The fastest route to take was the Webpack pre-rendering plugin. Not too fast though; if your app is heavy with dynamic routes then this plugin might not be your best choice just as it wasn’t for me

Other than implementing a solution myself with vue-server-renderer, the only option I was left with was Nuxt.

Nuxt for The Lazy

Nuxt website

Yes, if you’ve met me, then you must know how lazy I am. Worst still, my brain just adamantly refuse to take a long route to problems when there is proofed shortcut that’s reliable.

Nuxt allows you to just write your server rendered Vue app without being bordered about the low level implementation. It was inspired by Next, which is widely known in the React community for solving related problems.

SSR Gotchas

Nuxt sounds so interesting you would jump right to it at any given chance. Sadly, SSR got some gotchas and using a tool like Nuxt or Next (as the case may be)does not hide these gotchas; you still need to deal with them.

The first one you are most definite to encounter is trying to access the browser or document objects even before they are ready. Remember, your template is rendered to the server first, before the client. When you try to access these objects too early, the server throws an error like the following depending on what the case is:

> window is not defined

You might want to stay clear from such objects and only access them from lifecycle methods like mounted which ensures that the client is ready. The bad news is, most of the libraries out there that you will import in your project will try to access window or document before app is rendered to browser.

Dealing with this issue took me hours of debugging, google searches, endless open chrome tabs, and sniffing Github issues.

This was my way around it…

First Attempt: Wait for Browser Render

Assuming you have the following component logic:

// Problem herewindow.globalVar = 'global variable'export default {  mounted() {    console.log(window.globalVar);  },}

Sadly, window will be undefined. Most plugin like vue-select (which was what I was using) access the window object so early like this.

Nuxt provides a flag on the process object which you can use to check if or not the browser is set. The above problem will be easily fixed:

if (process.browser) {  window.globalVar = 'global variable'}export default {  mounted() {    console.log(window.globalVar);  },}

Hence, in cases when you are using a plugin that accesses the window object immediately they are imported, then this should work:

let pluginLib;if (process.browser) {  pluginLib = require('plugin-name');}export default {  mounted() {    console.log(pluginLib);  },}

Remember to include the plugin in the build’s vendor array:

// nuxt.config.jsbuild: {  vendor: ['plugin-name']}

This will work for you until your third party library is one that needs to inject a template in the view(which is what most UI libraries do). In my case, it was vue-select. For some reasons the following error was thrown:

> You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.

This led to my second attempt.

Second Attempt: Vue Plugins

With hints I picked up from this issue, I was able to write a plugin that’s only loaded on the client. First create a plugin in the plugins folder:

import Vue from 'vue'import vSelect from 'vue-select';const VueSelect = {  install(Vue, options) {    Vue.component('v-select', vSelect)  }};Vue.use(VueSelect);export default VueSelect;

Then tell Nuxt that this should only be loaded in the browser using the ssr property and setting the value to false .

// nuxt.config.jsplugins: [

{ src: '~plugins/vue-select', ssr: false }
]

Of course, don’t forge to load as a vendor file:

// nuxt.config.jsbuild: {   vendor: ['vue-select']}

Feel free to let me know if you’re stuck with integrating another plugin and I can try to help out.

Cheers!

--

--