Illegal import declaration with gulp-react - reactjs

I'm trying to introduce React with ES6 into my app, which is built with Gulp. I can get React working alone, and ES6 working alone. But trying to import crashes my Gulp build. Gulp's error is:
Line 14: Illegal import declaration
My HTML page includes React and the built JS file:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.2/react.min.js"></script>
<script src="js/app.js"></script>
app.js looks like this:
import {Child} from './child.js';
var Parent = React.createClass({
render: function(){
const y = 3; //es6 works
return (
<div>
<div> This is the parent {y}. </div>
<Child name="child"/>
</div>
)
}
});
React.render(<Parent />, document.getElementById('container'));
child.js is in the same directory and looks like this:
var Child = React.createClass({
render: function(){
return (
<div>
and this is the <b>{this.props.name}</b>.
</div>
)
}
});
export default Child;
The part of my Gulp file that compiles ES6 with Babel:
gulp.task('babel', function(){
gulp.src('js/app.js')
.pipe(react())
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist/js'));
});
What am I missing/doing wrong that is preventing me from using import?

You have to apply the es6module option to gulp-react to allow for importing of modules:
.pipe(react({
es6module: true
}))
Then, fix your import statement. Since Child is exported as default, import it like this:
import Child from './child.js';
Note: gulp-react was deprecated in favor of gulp-babel so I suggest using that instead if you're already using it for es2015. use gulp-babel instead and install the react preset for Babel:
npm install --save-dev babel-preset-react
Finally, apply it to gulp-babel:
presets: ['es2015', 'react']

Try
import Child from './child';

Related

Gulp with React not compiling a functional component correctly

I have the following gulpfile.js:
var gulp = require('gulp'),
babel = require('gulp-babel'),
concat = require('gulp-concat'),
react = require('gulp-react'),
sass = require('gulp-sass'),
jsxToJs = function() {
//gulp.src('src/**/*.js')
gulp.src('./src/sections/header/header.js')
.pipe(react())
.pipe(babel({
presets: ['es2015']
}))
.pipe(concat('javascript.js'))
.pipe(gulp.dest('./'));
};
gulp.task('jsxToJs', jsxToJs);
gulp.task('build', ['jsxToJs', 'styles']);
gulp.task('watch', function () {
gulp.watch([
'./src/**/*.js',
'./src/**/*.scss'
], [
'jsxToJs',
'styles'
]);
});
gulp.task('default', ['build', 'watch']);
And I'm trying to compile the following functional React component:
let Header = (props) => {
return(
<div />
);
};
However, when I run the javascript.js file created by gulp I get the following error:
Uncaught TypeError: e.render is not a function
If I convert the component back to the old way of doing things like this (which is how I found it as I'm revisiting an old problem):
var Header = React.createClass({
render: function() {
}
});
Then it works.
Looking at the compiled JS shows me this - where I can see that render is being compiled out correctly with the old syntax, but for the new syntax, while it's being ESfivified it's not being reactified:
// not working
"use strict";
var Header = function Header(props) {
return React.createElement("div", );
};
// working
"use strict";
var Header = React.createClass({ displayName: "Header",
render: function render() {
return React.createElement("div", );
}
});
I've checked that I've installed my gulp requires correctly and I'm using Node 6.10.2. My gulp file has some extra things for scss in that I've removed for this question.
A couple of other points:
I'm not using a bundling tool like browserify as I think it's overkill for this project - so no imports or exports.
I'm just loading HTML pages that do JSONP to an endpoint and load a script on page that includes the JSON - this is done in a getInitialState in the page level HOCs.
Can anyone explain what I'm doing wrong?
The solution turned out to be pretty simple.
Babel requires presets to be provided in order to transpile.
I had the es2015 preset, but not the react one. Therefore react specific tranpilations were not occurring. This addition fixed the problem:
.pipe(react())
.pipe(babel({
presets: ['es2015', 'react']
}))
The mistake I was making, that sent me down the wrong rabbit hole in Google, was assuming that failing to reactify was something to do with the gulp-react function - silly me.

Standalone React Component with Webpack

I've got a component I'd like to share/reuse in some projects. I'm trying to build/bundle this component so it doesn't take the large setup that react normally does (webpack/babel/npm/ect).
I want to
Include React/ReactDOM from a cdn somewhere on an html page.
Include my component js file (we'll call it standalone.js).
Little bit of initialization code to render this into the dom. No Babel, No Webpack, No JSX.
That's all.
I feel like I've gotton pretty close, though am stuck on item 3. I cannot figure out how render my component to the DOM.
Here's the relevant part of demo html page:
index.html (relevant parts)
<div id="app" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.1/react-dom.min.js"></script>
<!--My Component -->
<script src="build/standalone.js" type="text/javascript"></script>
<script>
// I believe I'm doing something wrong here
var myComponent = new MyLibrary.default();
var myStandaloneElement = React.createElement(myComponent, { message: "Testing Standalone Component" });
ReactDOM.render(myStandaloneElement, document.getElementById('app'));
</script>
standalone.jsx
import React, {PropTypes} from 'react';
class Standalone extends React.Component {
render() {
return <p>{this.props.message}</p>;
}
}
Standalone.PropTypes = {
message: PropTypes.string.isRequired
}
export default Standalone;
webpack.config.js (relevant parts)
var config = {
entry: APP_DIR + '/standalone.jsx',
output: {
library: 'MyLibrary',
libraryTarget: 'umd',
path: BUILD_DIR,
filename: 'standalone.js'
},
module: {
loaders: [
{
test: /\.jsx?/,
include: APP_DIR,
loader: 'babel'
}
]
},
externals: {
react: 'React',
"react-dom": 'ReactDOM'
},
}
With trying to render the component with basic html I've tried a bunch of variations of similar things. Looking in my debugger, I can tell the object is something 'close' to a react-type object. I just don't know what to do with it.
Any pointers appreciated
You should not instantiate components with a new, rather they should be instantiated with React.createElement factory. So you just pass reference to the element class/function to createElement, see modified part of yout html:
...
// get reference to my component constructor
var myComponent = MyLibrary.default;
var myStandaloneElement = React.createElement(myComponent, { message: "Testing Standalone Component" });
ReactDOM.render(myStandaloneElement, document.getElementById('app'));
...
On a side note, to simplify debugging while in development (and only in development!) I suggest to use non minified version of react.js and react-dom.js, they are located under node_modules, for instance:
<script src="/node_modules/react/dist/react.js"></script>
<script src="/node_modules/react-dom/dist/react-dom.js"></script>
You may want to consider exposing your React component as a webcomponent, such as with https://www.npmjs.com/package/reactive-elements
<body>
<my-react-component item="{window.someValue}"></my-react-component>
</body>

react-virtualized, SystemJS and CDN

I would like to use react-virtualized in a web application via cdnjs and SystemJS.
From all the examples that I have seen, it seems that react-virtualized and react libs are loaded locally, then bundled with Webpack before being included in a web page. Now I would like to use it via cdnjs without Webpack by simply importing it with SystemJS. But when I tried that I am getting errors saying that it can't find React.
I was wondering if anyone has tried this before, and whether this is supported at all by react-virtualized. Thanks.
UPDATE:
For clarity, I have included some code to show what I am trying to do.
index.html:
...
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.0-alpha.1/system.js"></script>
<script>
System.config({
map: {
"react":"https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.js",
"react-dom":"https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.js",
"react-virtualized":"https://unpkg.com/react-virtualized/dist/umd/react-virtualized.js"
}
</script>
</head>
...
main.jsx:
import React from 'react';
import ReactDOM from 'react-dom';
import {Table, Column} from 'react-virtualized';
...
What you are doing is possible using the UMD build of react-virtualized. You can see an example of that being done here. In order for it to work though, you'll need to also import UMD builds of react-with-addons and react-dom since react-virtualized depends on them.
For example:
<script src="https://unpkg.com/react/dist/react-with-addons.min.js"></script>
<script src="https://unpkg.com/react-dom/dist/react-dom.min.js"></script>
<script src="https://unpkg.com/react-virtualized/dist/umd/react-virtualized.js"></script>
The react-virtualized UMD build expects React and ReactDOM to be loaded in the global space.
Alternately there should be a way with SystemJS to expose react-dom and react-with-addons as globals for libraries like react-virtualized to consume. I'm not a SystemJS user, but I think it might be something like this:
System.config({
meta: {
'path/to/react-virtualized.js': {
globals: {
React: 'path/to/react-addons-shallow-compare.js',
ReactDOM: 'path/to/react-dom.js'
}
}
}
});
It's been a while, but I had some time to look at this again. Thanks to #brianvaughn's suggestion, I have managed to resolve this with the following:
System.config({
meta: {
"react-virtualized": {
exports: "ReactVirtualized",
format: "global",
globals: {
React: "react",
ReactDOM: "react-dom"
}
}
},
map: {
"react": "https://unpkg.com/react#16/umd/react.production.min.js",
"react-dom":"https://unpkg.com/react-dom#16/umd/react-dom.production.min.js",
"react-virtualized":"https://cdnjs.cloudflare.com/ajax/libs/react-virtualized/9.10.1/react-virtualized.min.js",
}
})
main.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import * as ReactVirtualized from 'react-virtualized';
let Table = ReactVirtualized.Table;
let Column = ReactVirtualized.Column;
let AutoSizer = ReactVirtualized.AutoSizer;
...

How to get ReactJs to integrate with Webpack?

Basically, I have just been through this simple tutorial, and now I want to get it to use React so I can see that display.
When I had this code:
module.exports = "It works from.js.";
It worked fine. But now I have this:
var React = require('react');
var ReactDOM = require('react-dom');
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('content')
);
and it is complaining at line 9 point at the unexpected token < and I need an appropriate loader. anyone know what this loader may be?
thanks
Yeap, you are right you need babel-loader for your JSX code. Also if you use ES6 syntax with React you also need babel-core & babel-preset-es2015 & babel-preset-react npm's modules. After that incude all of them into your webpack.config.js file as below:
module.exports = {
//.. some stuff before
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loaders: ["babel"],
query: { presets: ['es2015','react'] }
}]
}
//.. another stuff
}
Also i leave a link for you, with tutorial how to use ise.
I hope it will help you.
Thanks

WebPack with React Uncaught Reference Error

I'm very loosely following the example here up until the point where it starts running the dev server.
I have a test React component (in scripts/test.jsx):
/** #jsx React.DOM */
var React = require('react');
var Test = React.createClass({
render: function(){
return <h1>HI!</h1>
}
});
module.exports = Test;
I have a webpack.config where I'm using the jsx loader against the source directory (It's basically the same as the one in the example except I'm adding the library properties).
I run webpack and it generates the bundle file like I expect, however, when I try to use the component in an html file (after including the bundle.js script reference) I get the following in console: "Uncaught ReferenceError: Test is not defined".
The HTML contains the following:
<div id="hi">
</div>
<script type="text/jsx">
/** #jsx React.DOM */
React.renderComponent(
<Test />,
document.getElementById('hi')
);
</script>
Am I doing something incorrect to use a component that is defined in CommonJS style against an html page that isn't technically using a module loader (I'm trying to treat this test as if it's someone who is trying to load the component without any type of structured module loader)?
The output of the webpack is available here
EDIT 2: The full example code is available as a github repo
Yeah, you'd be better off following the example and requiring Test from a .jsx file rather than inlining it in the HTML.
Otherwise, Test needs to be exported as a global, so you'd need to follow similar conventions to the browserify --standalone flag, which looks to be something like this:
output: {
library: "Test",
libraryTarget: "umd"
}
http://webpack.github.io/docs/webpack-for-browserify-users.html#standalone
Edit: After looking at your GH repo, you have:
<script src="bundle.js" type="text/js"></script>
instead of
<script src="bundle.js" type="text/javascript"></script>
so it wasn't loading bundle at all. Further, you can't have 2 separate copies of react, the way you have it currently you're requiring React from within webpack, and then you're also loading it on the page. You should either export a function which takes the React object, or use the global to be able to use it outside of the bundle.
For example this would work:
/** #jsx React.DOM */
module.exports = function(React) {
var Test = React.createClass({
render: function(){
return <h1>HI!!</h1>
}
});
return Test;
};
and then:
/** #jsx React.DOM */
React.renderComponent(
Test(React)(),
document.getElementById('hi')
);
or this
/** #jsx React.DOM */
var Test = React.createClass({
render: function(){
return <h1>HI!!</h1>
}
});
module.exports = Test;
and then:
/** #jsx React.DOM */
React.renderComponent(
<Test />,
document.getElementById('hi')
);
Though I can't imagine most folks consuming a React package are going to be loading it with a script tag, and you generally don't want globals, so it's probably best to just use the CommonJS style require and let people figure out shimming or whatever.

Resources