Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't require velocity within node.js due to document.createElement calls #474

Open
KyleAMathews opened this issue Mar 21, 2015 · 15 comments

Comments

@KyleAMathews
Copy link

I'm building an isomorphic site using React.js and Velocity for some animations. I'm running into a problem however when rendering pages on the server, pages that require Velocity throw errors on the server due to document not being defined.

@ydaniv
Copy link
Contributor

ydaniv commented Mar 22, 2015

why should you require Velocity on the server?

@KyleAMathews
Copy link
Author

In order to render my React pages on the server.

@ydaniv
Copy link
Contributor

ydaniv commented Mar 22, 2015

Velocity is used for animation, so I'm confused here. How do you use it for rendering?

@KyleAMathews
Copy link
Author

It isn't used for rendering on the server but as I'm using commonjs modules, it still has to be required server-side so that Webpack can bundle it together for sending to the client.

@ydaniv
Copy link
Contributor

ydaniv commented Mar 24, 2015

@KyleAMathews have you tried simply patching this module and replace all requires with a mock?

@Polyrhythm
Copy link

The solution I've had to use repeatedly in other open-source projects used isomorphically is adding an early return in a conditional that checks for window or document or some such. Honestly, this is going to get worse and worse as more people attempt isomorphic apps, so it's probably a good thing to keep in mind.

It would be great if I didn't have to make my own fork of this that is node-compatible. I can't conditionally import modules in my codebase so everything the client uses, the server must also at least be able to require.

@dantman
Copy link

dantman commented May 16, 2015

@KyleAMathews

It isn't used for rendering on the server but as I'm using commonjs modules, it still has to be required server-side so that Webpack can bundle it together for sending to the client.

I'm using React in a similar way (but with browserify). But I just move call require calls for client-only stuff into the actual client-only methods that use them.

Alternatively require('is-browser') would work.

There's a plethora of client-only js libraries that probably will never fix themselves to mock load server-side. And the idea of loading a client-only module server-side that you don't actually use sounds terrible from what I think should be a best practice. So honestly I think the solution is going to have to be something generic, probably related to the loaders. Instead of going around telling libraries they should make their library a no-op when window/document aren't available.

@KyleAMathews
Copy link
Author

Webpack doesn't support conditional requires like browserify does afaik.

Agree that a general workaround would be nice.

@ydaniv
Copy link
Contributor

ydaniv commented May 16, 2015

@KyleAMathews (asking again) have you tried patching the require() of Velocity, e.g. by using proxyquire?

@andrewburgess
Copy link

Just to toss in an additional usage case and show how it might be integrated in a React application: https://gist.github.com/tkafka/0d94c6ec94297bb67091

Something like that should be able to be rendered on the server (the functions componentWillEnter and componentWillLeave that trigger the animation are only called from the client side).

@sogko
Copy link

sogko commented Jun 28, 2015

@KyleAMathews

I have a similar use-case (using velocity-animate in an isomorphic app). You can use conditional require in webpack, but you have to create two separate webpack bundles:, you just need to mock the library

Here's what I've done:

The javascript

var Velocity;
if (typeof window !== 'undefined') {
  Velocity = require('velocity-animate');
} else {
  // mocked velocity library
  Velocity = function() {
    return Promise().resolve(true);
  };
}

// code that uses the library below
...

@psoares
Copy link

psoares commented Sep 4, 2015

#578 I created seems to be related to this issue too. Can't do dojo builds without code modifications, because dojo builds are created on the server through nodejs or rhino.

@Rycochet
Copy link
Collaborator

From a quick look:

Most of the createElement calls are relating to IE8 support. There is one used to help determine browser prefixes. If the prefix detection gets pulled into a separate module and does feature detection then that should clean up things nicely.

@alampros
Copy link
Contributor

For those interested, I was able to get this working by using the (modified) shim (similar to the above solution) from velocity-react and using patched versions of velocity.js and velocity-ui.js.

@pizzarob
Copy link

Something I did that worked well was use webpack's code splitting inside of React's componentDidMount lifecycle method. componentDidMount does not execute server side.

  componentDidMount() {
    import('velocity-animate').then(Velocity => {
      this.velocityScroll = () => {
        Velocity(this.selection, 'scroll', {
          duration: 1000,
          easing: 'easeOutExpo',
        });
      };
    });
  }

https://webpack.js.org/guides/code-splitting-async/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests