Import library only if document is present (not on server)

1.4k Views Asked by At

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.

3

There are 3 best solutions below

1
On BEST ANSWER

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.

2
On

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>
    )
}
0
On

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(){};
}