jhamlet / svg-react-loader

Webpack SVG to React Component Loader
MIT License
559 stars 82 forks source link

"Reference Error: React is not defined" with server side rendering. How to implement in an isomorphic context? #31

Open tconroy opened 8 years ago

tconroy commented 8 years ago

Hi!

This is likely just a configuration issue on my part, but I'm getting the following error message when attempting to use this loader in an isomorphic react app:

error:

/Users/Tom/Code/src/svg/circle.inline.svg:3
React.createElement(
^

ReferenceError: React is not defined
    at Object.<anonymous> (circle.inline.svg:1:1)
    at Module._compile (module.js:413:34)
    at loader (/Users/Tom/Code/node_modules/babel-register/lib/node.js:148:5)
    at Object.require.extensions.(anonymous function) [as .js] (/Users/Tom/Code/node_modules/babel-register/lib/node.js:158:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Module.require (module.js:367:17)
    at require (internal/module.js:16:19)
    at Object.<anonymous> (BlockAdComponent.js:3:1)
    at Module._compile (module.js:413:34)

webpack loader config:

      {
        test: /\.inline.svg$/,
        loader: 'babel!svg-react',
      },

contents of SVG file:

<svg
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"
  x="0px"
  y="0px"
  viewBox="0 0 100 100"
  enable-background="new 0 0 100 100"
>
  <circle
    className="svg-inline-circle"
    cx="50"
    cy="50"
    r="48"
  >
  </circle>
</svg>

simplified example of how the SVG is being imported:

import React from 'react';
import Circle from 'svg/circle.inline.svg';

class BlockComponent extends React.Component {

  render() {
    const { config, swipeArrows } = this.props;
    return (
      <div>
        <Circle className="block-ad__circle" />
      </div>
    );
  }
}

export default BlockComponent;

The setup instructions I followed were from this guide (method 2)

Environment is: Node: 5.5.0 NPM: 2.15.9 Webpack: 1.13.1 React: 0.14.0 svg-react-loader: 0.3.7 Express: 4.14.0

A coworker had this working on his local via a simple webpack-dev-server, however while attempting to implement it into an isomorphic react context (express server backened), I am now getting this error.

If you need any other info from me please feel free to ask. Any help much appreciated.

tconroy commented 8 years ago

Any ideas? Think the root issue is it's unclear how to implement this in an isomorphic (server side) environment.

jhamlet commented 8 years ago

@tconroy can you get a look at the transpiled source of circle.inline.svg and post it here?

tconroy commented 8 years ago

@jhamlet sure -- I believe this is it, ripped from the bundle file (please let me know if you need any more samples :) ):

/***/ },
/* 137 */
/***/ function(module, exports, __webpack_require__) {

    'use strict';

    var React = __webpack_require__(11);
    var helpers = __webpack_require__(138)(__webpack_require__(139));

    module.exports = React.createClass({

        displayName: "CircleInline",

        getDefaultProps: function getDefaultProps() {
            return { "version": "1.1", "xmlns": "http://www.w3.org/2000/svg", "x": "0px", "y": "0px", "viewBox": "0 0 100 100", "enableBackground": "new 0 0 100 100" };
        },
        componentDidMount: function componentDidMount() {
            helpers.applyXmlAttributes(this);
        },
        render: function render() {
            var props = this.props;
            var children = props.children;

            return React.createElement(
                'svg',
                this.props,
                React.createElement('circle', { className: 'svg-inline-circle', cx: '50', cy: '50', r: '48' }),
                React.Children.map(children, function (c) {
                    return c;
                })
            );
        }
    });

/***/ },
jhamlet commented 8 years ago

Interesting. You're getting the error on the React.createElement call... not on the createClass call...

In that same source what is /* 11 */ pointing to (I'm assuming its react).

Are you using React in other places (again, I would assume so)? Are they pulling in the same module number (11)?

Something to try: In your node_modules/svg-react-loader/utility/template.txt can you add a line after var children = props.children in the render() method:

var React = require('react');
tconroy commented 8 years ago

@jhamlet: first off -- thank you for your help. hope we can solve this!

/* 11 */ does seem to point to React, and is required extensively throughout the app. I found 30+ references to it. Here is how it is defined:

/* 11 */
/***/ function(module, exports) {

    module.exports = require("react");

/***/ },

I've added in an example implementation to my original post (at the end) showing how I'm actually using the SVG inside a component ( pretty basic ).

Adding the React require to template.txt resulted in the same error (ReferenceError: React is not defined).

tconroy commented 8 years ago

so some minor clarification / correction on my part:

The error is occurring when I try to run our start-dev NPM command. That command looks like this:

"start-dev": "NODE_ENV=dev APP_API_HOST=http://api.domain.com/ APP_STATS_API_HOST=http://statsapi.domain.com:8080 babel-node ./src/server.js",

src/server.js contains the Express server, that does the server-side rendering for the React client.

We have a separate build command, npm run build:server, which produces the transpiled source shared above. That command looks like this:

"build:server": "webpack --config ./cfg/server.js",

I'm not sure how to provide the transpiled source for npm run start-dev since its a server. it is using webpackDevMiddleware with the dev webpack config, which does include svg-react-loader.

jhamlet commented 8 years ago

Interesting.

Are you pre-compiling with webpack before this step?

jhamlet commented 8 years ago

Not sure what to say, or where to go from here...

Is it possible you can create a stripped-down version of your project that reproduces this issue? With that I can then do some debug-runs on my end.

tconroy commented 8 years ago

Hi @jhamlet -- no, no pre-compiling with webpack prior to this step. I will try and create a stripped down version when I have some time this weekend. Thank you for your help.

jhamlet commented 8 years ago

@tconroy on another note: I'm getting ready to publish v0.4.0 as latest. You can try it out with npm install svg-react-loader@next and see if the problem goes away (I removed the need for the babel compiler).

tconroy commented 8 years ago

@jhamlet good to know, thanks. I'll give it a shot. My guess was this issue was being caused somewhere in the babel transpiration so maybe that'll help. For the time being I had to unfortunately remove the loader from the project but really hoping to add it back since it works so well.

jhamlet commented 8 years ago

@tconroy Any progress on this? Did v0.4.0 solve the problem? Did you get the chance to create a smaller sample repo that reproduces the issue?

tconroy commented 8 years ago

hi @jhamlet -- apologies for the delay, been busy and haven't gotten around to this since removing from the project. will keep you posted!

jblok commented 8 years ago

Hi @jhamlet - First off, thank you for your efforts on this loader!

I am getting this same error when running tests with Mocha. My Mocha config is

mocha tools/test-setup.js \"src/**/*.spec.js\" --reporter progress --compilers js:babel-register

It doesn't happen when running the application, just the tests. Version 0.4.0-beta2 didn't fix the issue.

Just wondering if you had had any further thoughts on this issue since August? Thanks very much :)

jblok commented 8 years ago

OK, I worked it out. When testing with Mocha, it's not even using the webpack config. So mocha on it's own just doesn't know how to handle a raw SVG file being imported as it isn't a javascript file. I don't quite understand why it was failing on React.createElement within the SVG as that kind of implies the loader has converted it, but can't find a dependency? Perhaps the error isn't correct?

Either way, I found 2 ways around it. Option 1 is to use mocha-webpack and compile everything with webpack before testing. I didn't go down that path though.

Option 2 is what I have done and is to remove the SVG extension from those that are imported with mocha and use babel-plugin-rewire to overwrite the import statement for the SVG. The whole thing looks like this now:

"test": "mocha tools/test-setup.js \"src/**/*.spec.js\" --reporter progress"

require('babel-register')({
  plugins: ['babel-plugin-rewire']
})
require.extensions['.svg'] = () => null;
import ComponentUnderTest from './ComponentUnderTest'
ComponentUnderTest.__Rewire__('SVGImport', () => <p>SVGPlaceholder</p>);
onvno commented 7 years ago

meet this problem,try:

plugins: [
  new webpack.ProvidePlugin({
    "React": "react",
  }),
],
alexcastillo commented 7 years ago

Thanks @onvno!

mascardoso commented 7 years ago

Hi there. I don't use svg-react-loader but instead svg-sprite-loader. Nevertheless I see that both are bringing the same issues... @tconroy did you manage after all fix your issue. I also use a isomorphic app and I'm getting the same error:

[0]     "stack": [
[0]       "ReferenceError: React is not defined",
[0]       "    at Object.<anonymous> (/front/assets/img/sprite.svg:1:1)",
[0]       "    at Module._compile (module.js:571:32)",
[0]       "    at loader (/node_modules/babel-register/lib/node.js:144:5)",
[0]       "    at Object.require.extensions.(anonymous function) [as .js] (/node_modules/babel-register/lib/node.js:154:7)",
[0]       "    at Module.load (module.js:488:32)",
[0]       "    at tryModuleLoad (module.js:447:12)",
[0]       "    at Function.Module._load (module.js:439:3)",
[0]       "    at Module.require (module.js:498:17)",
[0]       "    at require (internal/module.js:20:19)",

Webpack config:

..
      {
        test: /\.svg$/,
        loader: 'svg-sprite-loader',
        include: path.resolve(__dirname, 'front/assets/img/')
      }
..

jsx-1:

import React from 'react'
import '../../../assets/img/sprite.svg'

const Icon = ({ type, fill, size, padded, id }) => (
  <svg ...>
    <use xlinkHref={`#sprite-${type}`} />
  </svg>
)

export default Icon

jsx-2:

import Icon from '../icon.jsx'

<Icon type='customize' size='--medium' />

Any help would be extremely appreaciated.

stereobooster commented 6 years ago

Here is reproducible example https://github.com/stereobooster/comparison/tree/aphrodite-ssr

git clone https://github.com/stereobooster/comparison.git
cd comparison/examples
yarn install
cd aphrodite
yarn server

ReferenceError: React is not defined
    at Object.<anonymous> (comparison/examples/shared/assets/reply.svg:1:1)

Also requires babel-node (facepalm)

Andrew-Dyachenko commented 6 years ago

@onvno Yep, it's working img-2018-06-04-02-36-24

NorbertNader commented 6 years ago

Similar issue with svg-sprite-loader. I found a solution that I think might help https://github.com/kisenka/svg-sprite-loader/issues/40

hytStart commented 4 years ago

meet this problem,try:

plugins: [
  new webpack.ProvidePlugin({
    "React": "react",
  }),
],

excuse me, can you tell me the reason