Matt Matt - 1 month ago 26
React JSX Question

Webpack, React-router and React from CDN

I use Webpack for bundling my React application and react-router for routing. ReactJs is loaded from CDN as external library. I get this error message from react-router and I am not sure if it possible to use React loaded from CDN with other react libraries.

PropTypes.js:8

Uncaught TypeError: Cannot read property 'PropTypes' of undefined(…)
(anonymous function) @ PropTypes.js:8
__webpack_require__ @ bootstrap 2b8bebf…:19
(anonymous function) @ index.js:15
__webpack_require__ @ bootstrap 2b8bebf…:19
(anonymous function) @ index.jsx:3
__webpack_require__ @ bootstrap 2b8bebf…:19
(anonymous function) @ bootstrap 2b8bebf…:39
(anonymous function) @ bootstrap 2b8bebf…:39


enter image description here

index.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
<title>Experiment</title>
</head>
<body>
<div id="content">
<!-- this is where the root react component will get rendered -->
</div>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js"></script>

<!-- include the webpack-dev-server script so our scripts get reloaded when we make a change -->
<!-- we'll run the webpack dev server on port 8090, so make sure it is correct -->
<script src="http://localhost:8090/webpack-dev-server.js"></script>
<!-- include the bundle that contains all our scripts, produced by webpack -->
<!-- the bundle is served by the webpack-dev-server, so serve it also from localhost:8090 -->
<script type="text/javascript" src="http://localhost:8090/assets/main.js"></script>

</body>
</html>


index.jsx

import {Router, Route, useRouterHistory, browserHistory} from 'react-router';

ReactDOM.render(
<h1>hello</h1>, document.getElementById('content')
);


webpack.config.js

var webpack = require('webpack');
var merge = require('webpack-merge');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var NpmInstallPlugin = require('npm-install-webpack-plugin');

const TARGET = process.env.npm_lifecycle_event;
console.log("target event is " + TARGET);

var common = {
cache: true,
debug: true,
entry: './src/script/index.jsx',
resolve: {
extensions: ['', '.js', '.jsx']
},
externals: {
// Adapt React to different environments.
'react': {
commonjs: 'react',
commonjs2: 'react',
amd: 'React',
root: 'React'
}
},
output: {
filename: '[name].js',
sourceMapFilename: '[file].map'
},
module: {
loaders: [{
test: /\.js[x]?$/,
loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
exclude: /(node_modules)/
}, {
test: /\.css$/,
loaders: ['style', 'css']
}, {
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}, {
test: /\.less$/,
loaders: ['style', 'css', 'less']
}, {
test: /\.woff$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff&name=[path][name].[ext]"
}, {
test: /\.woff2$/,
loader: "url-loader?limit=10000&mimetype=application/font-woff2&name=[path][name].[ext]"
}, {
test: /\.(eot|ttf|svg|gif|png)$/,
loader: "file-loader"
}]
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
};

if(TARGET === 'dev' || !TARGET) {
module.exports = merge(common,{
devtool: 'eval-source-map',
devServer: {
historyApiFallback: false
},
entry: './src/script/index.jsx',
output: {
filename: '[name].js',
publicPath: 'http://localhost:8090/assets'
},
plugins: [
new NpmInstallPlugin({
save: true // --save
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('dev')
})
]
});
}

if (TARGET === 'build') {
module.exports = merge(common, {
devtool: 'source-map',
output: {
path: './dist'
}
});
}


package.json

"dependencies": {
"babel": "^6.5.2",
"babel-core": "^6.18.0",
"babel-loader": "^6.2.7",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"bootstrap": "^3.3.7",
"css-loader": "^0.25.0",
"file-loader": "^0.9.0",
"history": "^2.0.1",
"html-webpack-plugin": "^2.24.1",
"http-server": "^0.9.0",
"jquery": "^3.1.1",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"node-sass": "^3.10.1",
"npm-install-webpack-plugin": "^4.0.4",
"react": "^15.3.2",
"react-datagrid": "^2.1.1",
"react-dom": "^15.3.2",
"react-router": "^3.0.0",
"sass-loader": "^4.0.2",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.3",
"webpack-dev-server": "^1.16.2",
"webpack-merge": "^0.15.0"
}

Answer

Can you actually specify the environment like that in externals? The docs seem pretty straightforward on how to use it. This is what my externals looks like, and I use React/ReactDOM from CDN and with other libraries no problem:

externals: {
  react: 'React',
  'react-dom': 'ReactDOM'
}

It seems to set the environment you need to use the output.library and output.libraryTarget options, specifically the libraryTarget option as shown in the doc examples.

Comments