Question: Error: Uncaught ReferenceError: React is not defined

Question

Error: Uncaught ReferenceError: React is not defined

Answers 3
Added at 2016-12-27 15:12
Tags
Question

Overview

I am trying to use Babel and Webpack to build a React app. I know I could use create-react-app but I'd like to learn how these technologies can work together for myself.

When I run yarn run start or yarn run build (see package.json below), Webpack reports to have built the bundle fine. When I run the application in the browser, I get the Uncaught ReferenceError: React is not defined error.

There are a number of questions on SO regarding this same error, but none of the solutions have solved my problem yet.

Question

What piece am I missing to get React, Babel, and Webpack to play together nicely?

Code

package.json

{
  "private": true,
  "scripts": {
    "build": "webpack",
    "start": "webpack-dev-server"
  },
  "dependencies": {
    "react": "^15.4.1",
    "react-dom": "^15.4.1",
    "react-redux": "^5.0.1",
    "redux": "^3.6.0"
  },
  "devDependencies": {
    "babel-core": "^6.21.0",
    "babel-loader": "^6.2.10",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "redux-devtools": "^3.3.1",
    "webpack": "^1.14.0",
    "webpack-dev-server": "^1.16.2"
  }
}

.babelrc

{
  "presets": ["react", "es2015"]
}

webpack.config.js

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: './dist'
  },
  devtool: 'source-map',
  debug: true,
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Test</title>
</head>
<body>
  <div id="root"></div>
  <script src="dist/bundle.js"></script>
</body>
</html>

src/index.js

import ReactDom from 'react-dom';
import React from 'react';
import App from './App';

ReactDom.render(
  <App />,
  document.getElementById('root'),
);

src/App.js

import React from 'react';
import { Component } from 'react';

export default class App extends Component {
  render() {
    return (
      <h1>hello</h1>
    );
  }
}

Observations

  • It seems that Webpack/Babel is expecting React to be available on the global scope, or is ignoring my import React from 'react'; statements.
  • Also, I have yet to find the proper incantation of devtools and debug properties in my Webpack config to actually get source maps working. I don't yet see them in the compiled output.

EDIT

The broken bundle.js is too large for SO (21,000+ lines), so here is a link: http://chopapp.com/#1a8udqpj — it takes several seconds to load and display.

Answers
nr: #1 dodano: 2016-12-27 16:12

You will need to add a query to your module within the webpack.config.js file:

module: {
loaders: [{
  exclude: /node_modules/,
  loader: 'babel',
  query: {
    presets: ['react', 'es2015']
  }
}]
},
 resolve: {
   extensions: ['', '.js', '.jsx']
};
nr: #2 dodano: 2016-12-27 17:12

From my limited experience with React, I wish to make the following observations. First to your question regarding devTools and debug. The debug flag for webpack (according to their official documentation) switches the loaders to debug mode. Then, from what I understand, webpack, when running in a dev environment, does not actually compile the code to hard files, but keeps it in memory. Thus the source maps are also kept in memory and linked to the browser. You see their effect when you open the browser dev tools and view source.

Now assuming you have the dev server configured correctly, I also assume your index.html is located in your source directory. If this is the case, then your script reference should simply point to '/bundle.js' and not 'dist/bundle.js' since there may not be a physical "dist" folder.

I would also suggest dropping the ".js" from your entry point in the webpack.config.js

Just some observations. I hope they are of use to you.

nr: #3 dodano: 2016-12-27 18:12

I know you've already marked this as answered, but since you're trying to learn the in's and out's of webpack et al... Your original problem was that you needed to specify the output.publicPath in your webpack.config.js:

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: './dist',
    publicPath: '/dist'  // <- was missing
  },
  devtool: 'source-map',
  debug: true,
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
}

"path" is the physical path to the folder that contains your bundle.js. "publicPath" is the virtual path (URL) to that folder. So, you don't even have to use "dist". For example, if you used...

  output: {
    filename: 'bundle.js',
    path: './dist',
    publicPath: '/assets'
  },

Your HTML would then point to:

<script src="assets/bundle.js"></script>

Hope that helps!

Source Show
◀ Wstecz