Using Tau-Prolog with React - node.js

I am trying to use Tau-Prolog with Node.js and React.
At the step:
session.consult(program);
I get this error message:
TypeError: fs.existsSync is not a function
Here is the code to reproduce on the problem:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
// These alternatives makes no difference:
var pl = require('tau-prolog');
// var pl = require('./tau-prolog/modules/core.js');
// var pl = require('./tau-prolog.js');
class App extends React.Component {
componentDidMount() {
let program = 'fruit(apple). fruit(banana).';
let session = pl.create();
// Until here, it's ok. I get Session {rules: {…}, src_predicates: {…},
// The trouble is at this step:
session.consult(program);
////////
//////// TypeError: fs.existsSync is not a function
////////
}
render() {
return <div>Hello world</div>;
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
Thanks for your help!

You don't require it on server side, except if you want to evaluate the prolog program on server side and request the result.
If you just want to use it with react in the frontend, you can simply load it like any other frontend library by adding it to your html
<script type="text/javascript" src="tau-prolog.js"></script>
<script type="text/javascript" src="tau-prolog/core.js"></script>
<script type="text/javascript" src="tau-prolog/lists.js"></script>
and then either fetch an external .pl file which contains the Prolog code, or use it inline like in the examples or in react.

Related

How to export Javascript class which can be shared by NodeJS and ES6?

I have an Electron app integrated with Flask server. The app has both HTML loaded by Flask server (flask-page.html ES6) and Electron renderer (render-page.html NodeJS).
I want to share a class defined in a file for Flask and Renderer to avoid duplicated code, as class is exactly the same, but with different export/import.
Now, it's defined in 2 files as followings:
sharedclass-nodejs.js
class sharedClass {
sameMethod() {
}
}
module.exports = {sharedClass}
sharedclass-es6.js
export class sharedClass {
sameMethod() {
}
}
load-flask.js
import {sharedClass} from "sharedclass-es6.js"
flask-page.html (Flask server)
<script type="module" src="sharedclass-es6.js"></script>
<script type="module" src="load-flask.js"></script>
load-render.js
const {sharedClass} = require("sharedclass-nodejs.js")
render-page.html (Electron render UI)
<script src="sharedclass-nodejs.js"></script>
Is it possible to define 1 copy of "class sharedClass" in 1 file, such as NodeJS style export, and use it in ES6?

Get URL for EcmaScript module after importing in browser

My start HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="module" src="/way/to/app.js" defer></script>
</head>
<body>...</body>
</html>
My app.js script is an EcmaScript Module and loads another EcmaScript Module:
import Mod from "./path/to/module.js";
...
this is module.js:
// const url = ???
export default class Module {
constructor() {
// console.log(url);
}
}
Does exist any method to get loading URL "/way/to/path/to/module.js" in module.js? Something like these variables in nodejs but for browser:
const dir = __dirname;
const file = __filename;
location.href gives an URL for start html page.
Google Chrome and Firefox both support import.meta:
<script type="module">
console.log(import.meta);
</script>
In my console that prints:
Object { url: "file:///D:/testImportMeta.html" }
I think it's not really suited for production, unless Babel supports it. But if you're not over-concerned with lazy browsers, it works well.
It does not work in Node.JS yet.

Checksum Invalid - SSR props to Client

I'm using the react engine react-engine on GitHub to create a node, express app with react for the views.
For the most part, my app is rendered on the server. However, on one page/express route I require the view to be rendered server-side and then for the React to be fully interactive on the client.
So far I've got the view rendering server-side and then being re-loaded/re-mounted by React on the client.
My problem is that I'm now getting the following error:
bundle.js:357 Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) <section data-reactroot="" data-reactid
(server) <section cl
Here's what my code looks like:
class FormCreate extends React.Component {
render() {
return (
<ReactBlank title="Create new application form" messages={this.props.messages} authUser={this.props.authUser}>
<script dangerouslySetInnerHTML={{
__html: 'window.PROPS=' + JSON.stringify(this.props)
}} />
<div id="app-content">
<Main {...this.props}/>
</div>
</ReactBlank>
);
}
}
FormCreate.propTypes = {
messages: React.PropTypes.array,
authUser: React.PropTypes.object,
form: React.PropTypes.object
};
module.exports = FormCreate;
The above is initially rendered on the server and then the following re-mounts it on the client:
var React = require('react');
var ReactDOM = require('react-dom');
var Main = require('./app/views/shared/builder/Main.jsx');
document.addEventListener('DOMContentLoaded', function onLoad() {
const propScript = document.getElementById('react-engine-props');
const props = window.PROPS;
ReactDOM.render(
<Main {...props} />,
document.getElementById('app-content')
);
});
Can anyone see a problem here?

rendering react on server

I've been trying to figure out how to render react on the server (node/express) and finally found a simple enough tutorial to understand what's going on. But now, after setting everything up, I'm getting an error in the React.render method:
here's my component file:
var React = require('react');
var box = React.createClass({
render: function() {
return (
<div style='padding: 10px'>
this.props.text
</div>
);
}
});
React.render(<box text='testing server side'/>, document.body);
module.exports = box;
I get an error when I run npm start:
document is not defined
how do I get around this? do I need or not need the render method?
to give more context, this box component is being required by another component:
var React = require('react');
var Box = require('../react-jsx/box.js'); //this is the box component
var Component = React.createClass({
render: function() {
return (
<html>
<head>
<title>
React Server Rendering
</title>
</head>
<body>
<Box text='testing'/>
<script src="public/bundle.js"></script>
</body>
</html>
);
}
});
module.exports = Component;
and this is all being used in index.js
require('node-jsx').install();
var React = require('react');
var Component = require('../custom-modules/test-react-server-module.js');
var express = require('express');
var router = express.Router();
router.get('/react', function(req, res, next) {
var markup = React.renderToString(Component());
res.send(markup);
});
module.exports = router;
and if I remove the render method I get this error in the browser:
Cannot read property '__reactAutoBindMap' of undefined
I saw some people saying that may be due to the jsx transformer being old, but I think I have the latest version
I'm out of ideas
First of all, I'd recommend update your React version. The current version exposes two different Top-Level API's: React, which is generally used to create components and ReactDOM, which exposes DOM-specific methods to be used at the top level of your app.
There is to things to point out here:
You are trying to run an code that is supposed to be executed only at the browser. There is no document in NodeJS. I'd suggest using webpack to pack this component files and serve them on browser.
For an isomorphic React application, you need to have a client.js file that calls the render function for the same component you are trying to render inside index.js. Got it?
Understand the ReactDOM.render, as the documentation states:
Render a ReactElement into the DOM in the supplied container and return a reference to the component (or returns null for stateless components).
If the ReactElement was previously rendered into container, this will
perform an update on it and only mutate the DOM as necessary to
reflect the latest React component.
Keep in mind, again, that ReactDOM.render should be only used a few times and generally at the top level of your app, just one time.
Having said this, your box.js should look like:
var React = require('react');
var box = React.createClass({
render: function() {
return (
<div style='padding: 10px'>
this.props.text
</div>
);
}
});
module.exports = box;
For this to properly work, you will need to create a main component main-component-file.js:
var React = require('react');
var Box = require('../react-jsx/box.js'); //this is the box component
var Component = React.createClass({
render: function() {
return (
<html>
<head>
<title>
React Server Rendering
</title>
</head>
<body>
<Box text='testing'/>
<script src="public/bundle.js"></script>
</body>
</html>
);
}
});
module.exports = Component;
Inside your bundle.js you need to make sure that this is being called so the main component tries to re-render:
var React = require('react');
var ReactDOM = require('react-dom');
var Component = require('main-component-file.js');
ReactDOM.render(<Component/>, document.body);
At last but not least: index.js, the server file. Change React.renderToString to ReactDOMServer.renderToString, create a React Element from your main component and use it:
var element = React.createElement(Component)
router.get('/react', function(req, res, next) {
var markup = ReactDOMServer.renderToString(element);
res.send(markup);
});
Don't forget to include the npm package react-dom/server at your index.js.
References used in the article:
React.createElement
ReactDOM.render() docs
ReactDOMServer docs
You should delete this
React.render(<box text='testing server side'/>, document.body);
There is no need for it. What you are essentially telling React to do is render it right then and there.
document.body doesn't exist yet because you are rendering it server-side and you also don't need it because you render the component in the renderToString function upon request in the router. (Also I think #PeterLyons is correct so take a look at his answer too).
Also if you are strictly using React for views only, you might want to take a look at express-react-views. They have a good tutorial of how to use React with Express and you essentially can use it for server-side rendering only. I don't think it's as ideal as using react-router depending on what you're building but it illustrates how React is handling the server-side rendering and works with Express.
You need to use the react-dom/server package's renderToString function in the server environment. This will return the HTML as a string which you can send in your express response.

Render a component from outside ReactJS

From here :
"The only way to get a handle to a React Component instance outside of React is by storing the return value of React.render."
I need to render a React component outside React and the reason for it I'm going to mention below.
In my node.js, expressJS app, I am using 'react-router-component' and 'react-async'.
In app.js -the file which is supposed to be run ,
var url=require('url');
var App=require('./react/App.jsx');
var app = express();
app.get('*',function(req,res){
//}); SEE EDIT 1 BELOW
var path = url.parse(req.url).pathname;
ReactAsync.renderComponentToStringWithAsyncState(App({path:path}),function(err, markup) {
res.send('<!DOCTYPE html>'+markup);
});
});
In App.jsx,
PostList = require('./components/PostList.jsx');
var App = React.createClass({
render: function() {
return (
<html>
<head lang="en">
</head>
<body>
<div id="main">
<Locations path={this.props.path}>
<Location path="/" handler={PostList} />
<Location path="/admin" handler={Admin} />
</Locations>
<script type="text/javascript" src="/scripts/react/bundle.js"></script>
<script type="text/javascript" src="/scripts/custom.js"></script>
</body>
</html>
});
bundle.js is the browserified file from all the .jsx files.
In PostList.jsx,
var PostList = React.createClass({
mixins: [ReactAsync.Mixin],
getInitialStateAsync: function(cb) {
if(typeof this.props.prods==='undefined'){
request.get('http://localhost:8000/api/cats_default', function(response) {
cb(null, {items_show:response.body});
});
}
},
setTopmostParentState: function(items_show){
this.setState({
items_show:items_show
});
},
render: function() {
return (
<div className="postList" id="postList">
**// Things go here**
<div className="click_me" >Click me</div>
</div>
}
});
PostListRender=function(cart_prods){
var renderNow=function(){
//return <PostList cart_prods={cart_prods}></PostList>
React.renderComponent(<PostList cart_prods={cart_prods}></PostList>,document.getElementById('postList') );
};
return {
renderNow:renderNow
}
};
module.exports=PostList;
In custom.js:
$('.click_me').click(function(){
PostListRenderObj=PostListRender(products_cart_found);
PostListRenderObj.renderNow();
$('odometer').html('price');// price variable is calculated anyhow
});
The page shows well.
EDIT 3 Starts
Now I want to render the PostList component on clicking the click_me div .
EDIT 3 Ends
But when I click on the click_me element, the browser shows script busy, console shows
ReactJS - ReactMount: Root element has been removed from its original container. New container
And the Firebug log limit exceeds.
So why I want to render on click from outside react.js:
I have to run the jQuery Odomoeter plugin on clicking the click_me div. The plugin was not developed as a node middleware although it can be installed the way a middleware is installed and the plugin codebase is saved inside node_modules folder.
Edit2 Starts:
As the plugin is not a node middleware, I cannot require it from inside node. However I can perform the click event (code not shown ) from inside node and run the following code there as well :
$('odometer').html('price');// price variable is calculated anyhow
In this case I include the plugin in the browser with <script /> tag and the browserified bundle.js comes after the plugin script . But the animation is not properly shown. So I take to the client side click event in the custom.js.
If I do not require the plugin to be a middleware from inside node
and just include it in the page before the browserified JS file and
perform the click event inside React, then the odometer animation is
not properly shown.
Edit2 Ends:
So what is the way to render the PostList React component outside React ?
EDIT 1 The }); was quite mistakenly placed there
I cannot understand your question description, but this answers the title question:
How you render React components outside of react?
MyComponent = require('MyComponent')
element = document.getElementById('postList');
renderedComp = ReactDOM.render(MyComponent,{...someProps},element);
// => render returns the component instance.
$(document).on('something, function(){
renderedComp.setState({thingClicked: true})
})
Inside of react you can just call the component.

Resources