The problem: I cant get React.js to function at all in a requirejs and brunch situation.
I get a mismatched definition error with the react.js library, and react does not show up in the windows object.I am unsure as to what to do, and was hoping some one here had guidance in how resolve this issue. Perhaps I am using this combination of technology incorrectly, maybe it is not possible? Any insight into what I may be doing wrong or suggestions to resolve this problem would be greatly appreciated!
Btw, If I remove the bower reference to react.js, and remove all react.js information from the application, it all works correctly.
See my below edit for some additional comments and findings!
Actual error:
Error: Mismatched anonymous define() module: function (){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;odereq,module,exports){*
The Project file structure is as follows:
Projectname
|-app
|-assets
|-index.html
|-components
|-appinit.js
|-styles
|-bower_components
|-react
|-requirejs
|-node_modules
|-public
|-bower.json
|-brunch.config
The brunch.config file, I believe is pretty standard, here are the contents:
exports.config = {
"modules": {
"definition" : "amd",
"wrapper" : "amd"
},
"files": {
"stylesheets": {
"defaultExtension": "css",
"joinTo": {
"css/app.css": /^app\/styles/,
"css/vendor.css": /^(bower_components|vendor)/
}
},
"javascripts": {
"joinTo": {
"js/app.js": /^app/,
"js/vendor.js": /^(bower_components|vendor)[\\/]/,
"test/js/test.js": /^test(\/|\\)(?!vendor)/,
"test/js/test-vendor.js": /^test(\/|\\)(?=vendor)/
},
"order": {
"before": [
'bower_components/requirejs/require.js'
]
}
}
}
};
Here are the contents for the index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>My Application Test</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="/css/app.css">
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>
<script>
require.config({
"paths": {
"react": "bower_components/react/react-with-addons"
},
"shim": {
"react": {
exports: "React"
}
},
waitSeconds: 10
});
require(["components/appinit"], function (appInit) {
appInit.init();
});
</script>
</head>
<body style="height:100%; width:100%;">
<div id="main-content" style="margin-left: 100px; margin-top: 22px;">
My Main Content Goes Here.
</div>
</body>
</html>
and the contents of the appinit.js file:
define(function() {
var mainModule;
return mainModule = {
init: function () {
console.log("This is a test.");
return mainModule;
}
};
});
The bower.json file contains the following:
{
"name": “brunchreactrequirejstest",
"version": "1.0.0",
"homepage": "",
"authors": [
“person x"
],
"description": “description",
"main": "public/js/app.js",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"requirejs": "~2.1.15",
"react": "~0.12.2"
}
}
EDIT
So I believe I am getting closer to getting this resolved. I just found out that brunch only adds the definition wrappers around non-vendor javascript. So, react.js is being compiled to the vendor.js file without any definition name, so require.js throws the exception of react.js being anonymous. So, perhaps I need to have brunch run r.js on the vendor file during the compilation process? Does this sound correct? How do I go about doing that in brunch?
Possible Solution:
So I have react now functioning in a requirejs(AMD) environment. There is one problem that I see with my approach, and that is that I believe some libraries that work with react expect react to be exposed as a global object.I believe I can probably shim this into the requirejs export.config() by creating a requirejs definition that manually places react into the browser window scope(more on this later.)
Following are the changes I have made that have allowed react to work in an AMD/RequireJS environment:
The (new) brunch.config file:
exports.config = {
"modules": {
"definition" : "amd",
"wrapper" : "amd"
},
"files": {
"stylesheets": {
"defaultExtension": "css",
"joinTo": {
"css/app.css": /^app\/styles/,
"css/vendor.css": /^(bower_components|vendor)/
}
},
"javascripts": {
"joinTo": {
"js/app.js": /^app/,
"js/vendor.js": /^(bower_components|vendor)[\\/](?!react\/)/,
"test/js/test.js": /^test(\/|\\)(?!vendor)/,
"test/js/test-vendor.js": /^test(\/|\\)(?=vendor)/
},
"order": {
"before": [
'bower_components/requirejs/require.js'
]
}
}
},
"plugins":{
"react": {
"harmony": "yes"
}
}
};
The (new) index.html 'head' now only consists of this:
<link rel="stylesheet" href="/css/app.css">
<script src="/js/vendor.js"></script>
<script src="/js/app.js"></script>
<script>
require(["components/appinit"], function (appInit) {
appInit.init();
});
</script>
The build.js file: So this file i created is executed by node.js when I call 'npm start' on the project, which you will see in the package.json file further below:
({
baseUrl: ".",
optimize: "none",
paths: {
react: "bower_components/react/react-with-addons"
},
name: "react",
out: "vendor/react-built.js"
})
basically, it assigns the bower path to the react path, and the name grabs the bower path so that it knows the location of the file that r.js will optimize. The require.js optimized file is then thrown into the vendor folder as react-built.js. If you recall from above, in my new brunch config file, I exclude the bower-react javascript library from being compiled into the final vendor.js file, because i will already be adding the requirejs optimized react library that is generated with this build.js file.
So the scripts section of the NPM package.json file looks like this:
"scripts": {
"start": "node node_modules/requirejs/bin/r.js -o build.js && brunch watch --server"
}
Essentially, when you call 'npm start', r.js is executed with the build.js file passed into it, afterwards brunch is called.
So the next part, as es128 has mentioned, is to get any JSX annotated files to get preprocessed into javascript before brunch wraps them for AMD inclusion.
== Edit So installing the react-brunch plugin via npm works wonderfully. .jsx files get compiled to javascript upon saving the .jsx file. I updated the above brunch-config file with the plugin information. I have yet to shim and export React globally into the window scope, but I believe that may be a different StackOverflow topic since it does not relate to my original question.