Skip to content

Prerender fails with react and jQuery loaded from npm #209

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

Closed
janroesner opened this issue Mar 13, 2015 · 3 comments
Closed

Prerender fails with react and jQuery loaded from npm #209

janroesner opened this issue Mar 13, 2015 · 3 comments

Comments

@janroesner
Copy link

In order to have CommonJS require() and JEST work, I followed the setup described here. So in app/assets/javascripts I created an application.js with:

//= require components
//= require npm_jquery

Besides a components.js with:

//= require_self
//= require react_ujs

React = require('react');
DemoComponent = require('./components/DemoComponent');

and a npm_jquery.js with:

//= require_self

jQuery = require('jquery');
jQueryUJS = require('jquery-ujs')

When I render my component in my view with prerendering enabled like so:

<%= react_component 'DemoComponent', { name: 'Jon Doe' }, { prerender: true } %>

I receive the following error:

React::Renderer::PrerenderError in Pages#index
Showing /Users/jondoe/react/rails/test-app/app/views/pages/index.html.erb where line #2 raised:

Encountered error "Error: Cannot find module 'function (document, window) {
// jQuery is optional. Use it to support legacy browsers.
var $ = (typeof window.jQuery !== 'undefined') && window.jQuery;

// create the namespace
window.ReactRailsUJS = {
CLASS_NAME_ATTR: 'data-react-class', ...

Rendering w/o prerender set works totally fine and yields expected results. Is this a problem with my setup, or did I encounter a bug?

@janroesner
Copy link
Author

Update: I found a workaround to make prerendering, JEST based testing and CommonJS require work, but I do not know, whether this causes problems, that I do not see at the moment. My current solution:

app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require react_ujs
//= require components

app/assets/javascripts/components.js

React = require('react');
// Explicitely ONLY require components that are used inside Rails helpers
// NOT SubComponents
DemoComponent = require('./components/DemoComponent');

In the app/assets/javascripts/components folder only components are placed, that are inserted into the page via the react_component helper. In here, CommonJS require statements work properly:

app/assets/javascripts/components/DemoComponent.js.jsx

var React = require('react');
var uniq = require('uniq');
var SubComponent = require('../subcomponents/SubComponent');

var DemoComponent = React.createClass({

  render: function() {
    console.log("Uniq: ", uniq([1,2,2,3,3,3]));
    return(
      <div>
         ...
        <SubComponent />
      </div>
    );
  }
});

module.exports = DemoComponent

And subcomponents defined in app/assets/javascripts/subcomponents like:

app/assets/javascript/subcomponents/SubComponent.js.jsx

var React = require('react');

var SubComponent = React.createClass({

  render: function() {
    return(
      <div>
        Hello from SubComponent
      </div>
    );
  }

});

module.exports = SubComponent

JEST specs are defined for top level components and subcomponents in app/assets/javascripts/components/__tests__ and explicitely require the (sub)component like so:

jest.dontMock('../../subcomponents/SubComponent');

describe('SubComponent', function() {
  it('should tell us it is a sub component', function() {
    var React = require('react/addons');
    var TestUtils = React.addons.TestUtils;
    var SubComponent = require('../../subcomponents/SubComponent');
    var subComponent = TestUtils.renderIntoDocument(<SubComponent />);
        expect(subComponent.getDOMNode().textContent).toBe('Hello from SubComponent');
  });
});

With a package.json like:

{
  "name": "rexa-webapp",
  "devDependencies" : {
    "browserify": "~8.1.0",
    "browserify-incremental": "^1.5.0",
    "reactify": "^1.1.0",
    "uniq": "^1.0.1",
    "react": "^0.12.0",
    "react-tools": "^0.12.1",
    "jest-cli": "^0.2.0"
  },
  "scripts": {
    "test": "node ./node_modules/jest-cli/bin/jest.js"
  },
  "jest": {
    "rootDir": "./app/assets/javascripts/components",
    "scriptPreprocessor": "<rootDir>/__tests__/preprocessor.js",
    "moduleFileExtensions": [ "js", "jsx"],
    "unmockedModulePathPatterns": [
      "react"
    ],
    "testFileExtensions": ["js", "jsx"],
    "testPathIgnorePatterns": [ "preprocessor.js" ]
  },
  "license": "MIT",
  "engines": {
    "node": ">= 0.10"
  }
}

all seems to work fine. Inside the browser components work properly w/ or w/o prerendering. JEST can be used to test all components, and require pulls in npm-based and local modules as expected.

Besides the fact that this is a little more manually work to be done, are there any downsides in this approach, that I do not see yet?

@orlando
Copy link
Contributor

orlando commented Mar 15, 2015

@janroesner I'm using the same approach to have JEST with react-rails working together. The problem you had before should be solved with #210. Also you should not put react_ujs in your components.js file. ExecJS doesn't have a document object, so that will raise an error. (probably you figure that out already but I'll just leave this comment here if anyone else has this problem)

@janroesner
Copy link
Author

@orlando: Unfortunately my approach did not work completely. require npm modules from within subcomponents failed and I was not able to find a solution for that. Anyway, your PR fixes the problem, so that the setup described by James Burnett here works just fine. Thx for the hint and your PR.

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

No branches or pull requests

2 participants