Cannot use npm module react-chartjs with React - node.js

I'm new to npm and React. I have an application that uses a React UI and I want to include some charts using react-chartjs.
In my app.jsx file I try to create a bar chart:
var BarChart = require("react-chartjs").Bar;
var chartData = {
...
};
var CategorySummaryGraph = React.createClass({
render: function() {
return (
<BarChart data={chartData} width="600" height="250"/>
);
}
});
I bundle using gulp and browserify:
var gulp = require('gulp');
var react = require('gulp-react');
var browserify = require('gulp-browserify');
gulp.task('bundle-jsx', function() {
return gulp.src('./myapp/static/jsx/*.jsx')
.pipe(react())
.pipe(browserify())
.pipe(gulp.dest('./myapp/static/js/'));
});
This gives me an error when loading the page in the browser:
Uncaught Error: Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. This usually means that you're trying to add a ref to a component that doesn't have an owner (that is, was not created inside of another component's `render` method). Try rendering this component inside of a new top-level component which will hold the ref.
invariant # react.js:18405
ReactOwner.addComponentAsRefTo # react.js:13256
attachRef # react.js:14174
ReactRef.attachRefs # react.js:14190
attachRefs # react.js:14051
assign.notifyAll # react.js:1045
ON_DOM_READY_QUEUEING.close # react.js:13934
Mixin.closeAll # react.js:16693
Mixin.perform # react.js:16634
batchedMountComponentIntoNode # react.js:11998
Mixin.perform # react.js:16620
ReactDefaultBatchingStrategy.batchedUpdates # react.js:9140
batchedUpdates # react.js:14853
ReactMount._renderNewRootComponent # react.js:12133
ReactPerf.measure.wrapper # react.js:13366
ReactMount.render # react.js:12222
ReactPerf.measure.wrapper # react.js:13366
(anonymous function) # myapp.js:23474
m.Callbacks.j # jquery-1.11.3.min.js:2
m.Callbacks.k.fireWith # jquery-1.11.3.min.js:2
m.extend.ready # jquery-1.11.3.min.js:2
J # jquery-1.11.3.min.js:2
From the error message it seems to me like the BarChart doesn't have a render method... which obviously can't be the case if react-chartjs works at all. I'm not sure where to go with this so any help would be much appreciated.

I had been defining React by including it on my html page:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.js"></script>
What fixed the problem was requiring it instead in my .jsx file:
var React = require("react");
Not sure why this worked but from reading around, perhaps there were multiple initializations and/or definitions of React that were causing conflicts.
Thanks #Daniel for pointing me in the right direction.

Related

How do I fix error with svelte-kit and aws-amplify?

I'm getting an error with svelte-kit and #aws-amplify/auth
import Auth from '#aws-amplify/auth'; causes the following error:
500
global is not defined
node_modules/amazon-cognito-identity-js/node_modules/buffer/index.js#http://localhost:3000/node_modules/.vite/#aws-amplify_auth.js?v=fb9b3a59:4766:5
__require2#http://localhost:3000/node_modules/.vite/chunk-A2XPJTG4.js?v=fb9b3a59:19:44
#http://localhost:3000/node_modules/.vite/#aws-amplify_auth.js?v=fb9b3a59:30155:32
I've tried adding this:
resolve({
browser: true,
preferBuiltins: false,
alias: {
"./runtimeConfig": "./runtimeConfig.browser"
}
}),
but it doesn't seem to do anything. Also I don't know what this runtimeConfig is
It's difficult, global exist in NodeJS and modern browsers but not in web-workers, but because Svelte heavily uses workers it's problem.
https://github.com/sveltejs/svelte/pull/4628 -- This PR introduces globalThis but you need to find a way to change this lib.
Or if you want to use it in SSR only (server-side) you should import and put this code for <script context="module">.
The main issue here is this library because it depends on NodeJS and is not designed especially for browsers.
The solution from this Github issue fixed it for me... add this to the top of your app.html file:
<script>
var global = global || window
var Buffer = Buffer || []
var process = process || { env: { DEBUG: undefined }, version: [] }
</script>

Gulp + Browserify + TypeScript To Browser

My problem is the following:
I use gulp+browserify to compile my TypeScript to JavaScript that you can use on normal HTML pages, the problem is that my class is never available on the browser:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
This is my TypeScript File:
class Test {
public test(): void {
console.log("aa");
}
}
This is my gulpfile
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
gulp.task("default", function () {
return browserify({
//basedir: '.',
debug: true,
entries: ['app/Resources/typescript/Test.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest("web/bundles/framework/js"));
});
The file compiles without problem, and is included in my index.html (the compiled js file).
But when i try:
var t = new Test();
I get the following error:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
I can't resolve it, I have read a lot and I haven't found anything clear, I tried all and nothing worked.
There are a few things missing here:
If you want your class to be accessible outside of your module, you have to export it:
export class Test {
// ...
}
Browserify creates functions on top of the classes you define. So it won't be accessible globally (which is a good thing). Normally you would import it in another file and use it:
// in any TS file that wants to use `Test` class. Make sure this is included in the gulp entries as well
import {Test} from "test";
var t = new Test();
console.log(t);
Or if really want it to be accessible globally, you can attach it to window object:
// In Test.ts file:
(window as any).Test = Test; // This can be useful when debuging. But don't do this in production code.

Present canvas interface in shared code on both server and client

I am trying to write shared code (that runs on both server and client) that uses an HTML canvas.
On the client, this should work perfectly fine. On the server, Node doesn't have a canvas (or a DOM), so I'd like to use the node-canvas plugin: https://github.com/Automattic/node-canvas.
However, I can't work out a way to access it that doesn't make webpack try to bundle node-canvas into my client-side code (which crashes webpack). Is there any way of loading node-canvas in such a way that I can reference it with the same code I'll use in the browser and without making webpack crash horribly?
My current effort, which did not work:
canvas.server.js
import Canvas from 'canvas';
const createCanvas = (width, height) => new Canvas(width, height);
export default createCanvas;
canvas.client.js
const createCanvas = (width, height) => {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
return canvas;
};
export default createCanvas;
canvas.js
let createCanvas;
if (typeof document === 'undefined') {
// SERVER/node
createCanvas = require('./canvas.server.js');
} else {
// BROWSER
createCanvas = require('./canvas.client.js');
}
export default createCanvas;
in use:
import createCanvas from './canvas';
const canvasElement = createCanvas(width, height);
const ctx = canvasElement.getContext('2d');
Unfortunately, webpack still bundles in node-canvas.
Did you try requiring node-canvas only when the code is running in node?
If you do not actually call the require in front-end code, webpack will not bundle it. This means calling the actual require inside aforementioned conditional statement and not at the top of your file. This is important. Also, verify that you did not put node-canvas as an entry point in webpack.
Example:
// let's assume there is `isNode` variable as described in linked answer
let canvas;
if (isNode) {
const Canvas = require('canvas');
canvas = new Canvas(x, y);
else {
canvas = document.getElementById('canvas');
}
// get canvas context and draw on it
Edit after OP provided code example:
I've reproduced the exact structure in this WebpackBin to prove this should be working as explained above. After all, this is a feature of common.js (and other module loaders) and is therefore supported in webpack.
My changes to the code:
Replaced the code in canvas.client.js and canvas.server.js with console.log of what would be called at that line
Fixed wrong use of require with export default (should be require(...).default). Irrelevant, but had to do it to make the code work.
Removed the canvasElement.getContex call. Would not work in the example code and is irrelevant anyway, so there is no point of mocking it.

How to access a closure function in a require.js module?

I am trying to use require.js to load my modules dependencies and so far it is working, but I have a doubt. I've created a little function to test the modules and placed it in a file called panelTest.js:
define(['./panel/View', './panel/TitleView'], function(View, TitleView) {
return function test(container) {
// main view
var panel = new View(container, 'main');
var panelTitle = new TitleView(panel.getContainer(), 'main-title');
panelTitle.setTitle('Properties Panel');
//panelTitle.addCss('pjs-panelTitle');
panel.addView(panelTitle);
// sections
var top = new View(panel.getContainer(), 'top');
panel.addView(top);
var middle = new View(panel.getContainer(), 'middle');
panel.addView(middle);
var bottom = new View(panel.getContainer(), 'bottom');
panel.addView(bottom);
};
});
In the html that uses the modules I included this script tag as shown in the require.js documentation to load panelTest.js.
<script data-main="panelTest.js"
src="require.js"></script>
My question is how can I call the test function from outside the module, since the container parameter it is supposed to come from outside the module.
You have to access the module through the appropriate channels provided by RequireJS. You could do it like this in a script tag that appears after the one that loads RequireJS:
require(['panelTest'], function (panelTest) {
panelTest(/* some value */);
});
Given the code you show, your panelTest module does not seem to really make sense as a "main module" so I would not put it as data-main.
If you want to use it from anther module, put the module in its own file and define it like this:
define(['panelTest'], function (panelTest) {
panelTest(/* some value */);
});

Testing React component with global dependency

I have included a JS dependency (Foo.js) in my index.html file. When I call Foo.js in my React component, it finds the Constructor in the global namespace and instantiates it. This works great when I deploy it, but when I go to build a test around Component.js, the test can't find Foo.js
<!--Index.html-->
<head>
<script src="Foo.js"></script>
</head>
// Component.js
var bar = new Foo(); // Works in deployment but not in Jest tests
When running my test I get this error:
RefererenceError: Foo is not defined
Now I thought I would be clever and in my Component.js file declare Foo to be window.Foo, which worked in getting rid of the undefined dependency in my Jest tests.
// Component.js
var Foo = window.Foo;
var bar = new Foo();
Suddenly my Reference error went away and I was happy. So I continue to write tests and now I get a funky error that I think has to do with that global dependency again.
TypeError: undefined is not a function
I believe that my error is still coming from Jest not properly mocking a dependency that is on the window object. I don't need to test the dependency, I just need it to be defined so I can get to writing tests for the rest of the Component. Does anyone have a thought on what I could possibly be doing wrong?
So I finally figured out how to fix this. In my browser environment and my testing environment I have two completely separate window objects. In my test, before I require in my component I have to set window.Foo to an anonymous function. It will look like this:
// Component.js
var bar = new Foo(); // Works in browser but not in test
// ...Rest of code
// Component.test.js
describe('Component.js', function() {
let Component;
beforeEach(function() {
window.Foo = function() {};
Component = require('./Component.js'); // When it requires in component,
// it will now have Foo declared on the window object
});
});
I have to explicitly declare any window objects in my test environment for any components to find those functions.

Resources