1

I am using sever rendering with my app and came across an issue while using a react extension for dragula library called react-dragula

issue here lies within

import Dragula from 'react-dragula';

for some reason this uses document hence causes error during server side rendering as document is not present, therefore I need a way to only include it once document is available so I can start using it.

Ilja
  • 44,142
  • 92
  • 275
  • 498

3 Answers3

4

There's no way to conditionally import something, but there is a way around. The way I usually go about problems like this, is by creating separate builds for server and client use, and use process.env vars to differentiate the two in the build process. It doesn't take much alteration of your code, but this way it is possible to somewhat mock a dependency.

You could for example do something like this:

import Dragula from './my-dragula-wrapper'

In your wrapper file, use CommonJS require to return the correct module:

/* my-dragula-wrapper.js */
if(process.env.SOME_VAR === 'server'){
  module.exports = function(){}; // Or something, it's not going to be used anyway
} else {
  module.exports = require('react-dragula');
}

Then it's simply a matter of setting the correct process.env.SOME_VAR value in your build process, be it Gulp or Grunt or whatever is cool this week.

gulp.task('env:server', function(){
    return process.env.SOME_VAR = 'server';
});

gulp.task('env:client', function(){
        return process.env.SOME_VAR = 'client';
});

Use this with the Envify transform for Browserify, or similar. And you should be good.

dannyjolie
  • 10,959
  • 3
  • 33
  • 28
2

I don't know if this is a good practice. But you can do this,

componentDidMount(){
    var Dragula = require('Dragula')
}

This will only import dragula on client side. Component did mount is never run from server side.
You'll have to include checks in your render function to see if Dragula exists yet or not. But something like this will work. I just did it.
What I did was,

var something // so that it has scope in all functions 
componentDidMount(){
    something = require('something')
    this.setState({somethingExists: true})
}
render(){
    return(
        <div> {this.state.somethingExists ? <something> : null } </div>
    )
}
Jeff P Chacko
  • 4,908
  • 4
  • 24
  • 32
  • tried that, got babel errors (babel is transpiler I use for es6) – Ilja Apr 13 '16 at 14:34
  • So, You will also need to change your code so that it only renders your new component after it is imported. I've added more code to show how exactly I did it – Jeff P Chacko Apr 13 '16 at 15:17
0

Adding to the dannyjolie suggestion.

You can use try catch instead of setting in gulp/grunt

try {
  if(window) 
     module.exports = require('react-dragula');
}  
catch(ex) 
{
 module.exports = function(){};
}