Snap.svg: Error loading Snap with webpack

When loading Snap (from the dev branch) with webpack.

var Snap = require('snapsvg');

browser throw error Uncaught TypeError: Cannot read property 'on' of undefined

from line 1625 in svg.js

...
// default
eve.on("snap.util.getattr", function () {
    var att = eve.nt();
...

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Reactions: 28
  • Comments: 47 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Thanks everybody. I had some troubles moving this to the webpack config because I am still earning my webpack black belt. So I thought I would drop here what I did end up getting to work:

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

I published snapsvg-cjs so you can npm install snapsvg-cjs for use with webpack.

Once this project works out of the box with webpack I’ll deprecate my snapsvg-cjs

Here is another recipe

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

Another solution

npm install snapsvg

And use this loader config:

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

Currently the npm version is still 0.4.0. Can it be bumped to 0.4.1 please? Seems it was published 11 months ago?

Any plans on supporting webpack sans workaround?

Thanks, @alfonsomunozpomer! I responded there. But getting something working was easier than I expected. In case anyone’s interested, here’s some code:

import Snap from 'snapsvg-cjs'

const doSnapStuff = (el, svgCode) => {
   let container = Snap(el)
   let s = Snap.parse(svgCode)
   let n = s.select('g.node')
   n.node.onclick = function(a,b,c,d){console.log({a,b,c,d}); n.select('div').node.style.backgroundColor='red'}
   container.add(s)
}
export default class Mermaid extends Component {
   svgRender() {
      let svgDiv = this.svgDiv
      getTheSvg(  // accepts props and callback, callback accepts svgCode
        this.props, 
        (svgCode) => {
          doSnapStuff(svgDiv, svgCode)
        }
      )
  }
  componentDidMount() {
    this.svgRender()
  }
  componentDidUpdate(prevProps, prevState) {
     if (!_.isEqual(prevProps,this.props)) {
       this.svgRender()
     }
  }
  render() {
    return  <div ref={d=>this.svgDiv=d}>
            </div>
  }
}

I found the answer not long afterward. It was because the mix plugins with file-loader I end up modifying wepack.config.js, excluding .svg.js pattern from file-loader, and then use a combination of @hybrisCole and @NicholasTuck

See fix for Webpack 4.x with Imports Loader 1.x https://github.com/adobe-webplatform/Snap.svg/issues/639

Another solution, worked for me: import * as Snap from 'snapsvg'; and remove the second group from regex:

before:

{
    test: /\.(eot|woff2?|svg|ttf)([\?]?.*)$/,
    use: 'file-loader'
}

after:

{
    test: /\.(eot|woff2?|svg|ttf)$/,
    use: 'file-loader'
}

and imports-loader:

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

Big thx to @harryworld for thought about file-loader

I would really appreciate if anyone could post all the steps required to get this working in one place

I just can’t get rid of the feeling that I am constantly developing software in the entirely wrong way. Every time I introduce a dependency I need to change Webpack’s configuration and sometimes introduce another loader or plugin. I’m not sure if Webpack helps or just gets in the way. Why not just go back to copy/pasting .js files and writing <script> tags? This entire modules idea is just an venture.

@88mpg wasn’t abandoned just neglected! Just released v0.0.6 which has 0.5.1

@mjisican,

In Expression Atlas we use Snap and React. Have a look at a component that displays a SVG anatomogram here: https://github.com/gxa/anatomogram