Adding Snap.svg to Vue.js and Nuxt.js Projects

Getting Snap.svg Working with Vue.js

Out of the gate, there’s some hurdles because Snap mounts itself on the browser’s window object, so if you’re trying to load Snap through WebPack (as opposed to just including it in a project using a conventional script tag), you need to do some gymnastics to get WebPack’s JavaScript loader to feed the window object into Snap’s initialization logic. You can find an overview of the problem in this GitHub issue which illustrates the obstacles in the context of using React, but the issues as they relate to Vue.js are the same.

I’m assuming you have a Vue.js webpack project that you started with vue-cli or from a template that has everything basically running okay, so you’ve already got Node and webpack and all your other infrastructure in place.

For starters, you’ll want to install Snap.svg and add it to your project dependencies, so from a terminal window open and sitting in the directory where your project’s package.json/package-lock.json sit…

npm install --save snapsvg

That will download and install a copy of the Snap.svg source into your node_modules directory and you’ll have it available for WebPack to grab.

Normally you’d be able to use a package installed like this by using an import statement somewhere, and you’d think you could do this in your Vue project’s main.js file, if you start down this path you’ll get the window undefined issue described in that GitHub link above.

The tricky bit though is getting WebPack to load the Snap properly, and to do that we’ll need a WebPack plugin that lets us load as a JavaScript dependency and pass some bindings to it. So, in that same directory install the WebPack imports-loader plugin…

npm install --savedev imports-loader

To tell the imports-loader when it needs to do its magic, we have to add it to the WebPack configuration. I changed my webpack.base.conf.js file to include the following inside the array of rules inside the module object…

 module: {
   rules: [
      ...
       {
       test: require.resolve('snapsvg'),
       use: 'imports-loader?this=>window,fix=>module.exports=0',
       },
      ...
     ]
   },

Now we can load Snap.svg in our JavaScript, but imports-loader uses the node require syntax to load the file. So in our main.js, we can attach Snap.svg by telling WebPack to invoke the exports loader like this…

const snap = require(`imports-loader?this=>window,fix=>module.exports=0!snapsvg/dist/snap.svg.js`);

…and then attach it to our root Vue instance, still in main.js, something like this…

const vueInstance = new Vue( {
 el: '#app',
 snap,
 router,
 axios,
 store,
 template: '<App/>',
 components: { App }
} );

export { vueInstance };

There is some redundancy in that require() call and the way we setup the module resolution in the WebPack configuration. I’m fuzzy about why I seemed to need this in both spots, but it works so I’m running with it. If you have insights they’d be appreciated; let me know in the comments.

2 Replies to “Adding Snap.svg to Vue.js and Nuxt.js Projects”

  1. Hi,

    I’ve installed vuejs-cli and created a project, with the most recent version of the cli. I have no webpack.base.conf.js file.

    Do you know how to get the project configured?

    Thank you very much!

    1. It’s automatically created into ./build/webpack.base.conf.js when you build the project.

      Sorry for the late answer.

      Currently I still haven’t integraded Snap.svg into my project as it’s currently so simple that I preferred plain canvas plotting.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.