How to share code between node and react? - node.js

I use React on server rendering, so the react code need to be used both in node and client, on client side I use browserify.
now suppose I have a component:
var item = React.createClass({
//code here
})
in order to use this component in node I have to require React first, so the component will be
var React = require('React');
var item = React.createClass({
//code here
})
but if I use this component in client via browserify, the React librray will be required, in this case my build js file will be too big. I know I can ignore React in browserify like
browserify -i React
but if I ignore the React then the code:
var React = require('React');
will cause an error "undefined is not a function"
any idea how to avoid this?

You can put your vendor packages in a separate bundle:
browserify -r react -r underscore > vendor.js
And then declare that those dependencies will be provided by an external bundle (or multiple):
browserify -x react -x underscore main.js > bundle.js
And include both in your page:
<script src="vendor.js"></script>
<script src="bundle.js"></script>
You don't need to rebuild the vendor bundle(s) when you build your main bundle (unless you've upgraded dependencies). Usually you don't actually need to do this, and if you're concerned about build times in development: watchify is a a good replacement/addition.
When something is -r'd you can also require it in a plain script tag. This means that there's now a require global, which may clash with other scripts on the page.
<script>
var React = require('react');
</script>

If you're already including React via a separate <script> tag, use the browserify-shim transform to rewrite your require('react') call to use the global React variable.
Add the following config to your package.json:
"browserify-shim": {
"react": "global:React"
}
Use the transform when bundling:
browserify -t browserify-shim lib/index.js -o build/index.js
The bundled version should look something like this:
var React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null);
Alternatively, you can omit the need for the -t browserify-shim argument by adding some browserify transform config to your package.json
"browserify": {
"transform": [ "browserify-shim" ]
}

Related

Cannot use JSX with nodejs ESM module loader

I attempted to run a simple block of code featuring React "render" method , but the browser didn't display the text.
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(<h1>Hello World</h1>,document.getElementById('root'));
I'm using VS Code as editor therefore I typed the "Run and Debug Node.js" command. It came up with the warning below
(node:3004) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
Setting "type:module" in the package.json file solved the problem but on the other side another problem arised
(node:18968) ExperimentalWarning: The ESM module loader is experimental.
warning.js:32
SyntaxError: Unexpected token '<'
at Loader.moduleStrategy (internal/modules/esm/translators.js:81:18)
at async link (internal/modules/esm/module_job.js:37:21)
That won't allow me to write any tags whatsover. What am I missing and how can I solve it? Below is the index.html file and the file structure
<html>
<head>
<title> React Test</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
JSX isn't a valid JavaScript syntax and it isn't part of any ECMAScript specification as well at the current time. NodeJS supporting ESM does not mean it supports JSX natively.
JSX are expected to be transpiled into a valid JavaScript on build/compile time using tools like babel. If you are using React, the most simple way to do this is to use babel with #babel/preset-react, which will transpile all JSX into React.createElement() calls. You can then run the code generated by babel using node.
To give you a clearer picture, here is a Babel online REPL that you can play with to see how your code are transpiled by babel.
A common setup for react apps that is going to be run on the browser is like:
Use webpack to bundle your app
Configure webpack to use babel-loader so it transpiles your code into something that browsers can run
Use the generated javascript bundle on browser
I don't understand why you have .vscode folder in your src folder and it contains index.html and index.js files.
I think you need to move your index.js file from .vscode folder to src and delete .vscode folder. Or just create a new app with npm.
that folder structure came out after using create-react-app?
btw, try to return the component with React.createElement()
return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);
as docs says "The render method returns a description of what you want to see on the screen. React takes the description and displays the result. In particular, render returns a React element, which is a lightweight description of what to render. Most React developers use a special syntax called “JSX” which makes these structures easier to write. The syntax is transformed at build time to React.createElement('div')."
check this out
https://reactjs.org/docs/react-api.html#createelement
----- add on
You can now import .js file in node v12.x, in 2 steps:
after adding the following line in your package.json file:
// package.json
{
"type": "module"
}
you need to add --experimental-modules flag when launching the script:
node --experimental-modules index.js
https://nodejs.org/api/esm.html#esm_commonjs_json_and_native_modules

summernote is not working in laravel with npm

I am new in laravel. I installed npm before some days. And now I need editor in my application. So I have installed it via npm using "npm install summernote --save-dev" command. And add below lines in my app.js
require('./bootstrap');
require('summernote');
require('summernote/dist/summernote.css');
require('summernote/dist/summernote.js');
require('jquery');
$(document).ready(function() {
$('#content_editor').summernote();
});
and then compiled the assets via "npm run dev" command. But it will display 2 textarea, one that is in my html and second is summernote textarea. It is not displaying toolbars and other things. It is displaying only textarea.
Can anybody please help me to resolved this problem. I am newly learning laravel. So, I don't have deep knowledge of packages. I just want to display it without including css and js to header. I need it via webpack.
This code in app.js with Laravel 8 does work:
require('./bootstrap');
require('summernote');
require('summernote/dist/summernote.css');
require('summernote/dist/summernote.js');
import $ from 'jquery';
window.$ = window.jQuery = $;
$(document).ready(function () {
$('.summernote').summernote();
});
The trick is in webpack.mix.js configuration file. It should appear something like:
const mix = require('laravel-mix');
let path = require('path');
mix.webpackConfig({
resolve: {
alias: { jQuery: path.resolve(__dirname, 'node_modules/jquery/dist/jquery.js') }
}
});
// Into app.js, you require 'summernote' as always
mix.js('resources/js/app.js', 'public/js');
Source: https://laracasts.com/discuss/channels/javascript/summernote-and-webpack

Browserify document is undefined

i just found browserify, which sounds really cool. However i try to append a canvas element to the body(filename : Renderer.js):
window.document.body.appendChild(this.canvas)
module.exports = Renderer
And i also have a main.js
var Renderer = require("Renderer.js")
var r = new Renderer();
So i build the bundle like this:
browserify main.js -o bundle.js
And when i start the project:
node server.js
I get the following error message
ReferenceError : document is not defined (if only document.body)
And window is not defined (when window.document.body)
Can someone explain this behaviour and how to fix it?
Did you try to run that browserify code on the server? Please do not, as in the server there is not window element, whereas node only has global. Instead, you need to use your browser to download the browserified code and execute on your browser.
Note that, browserify library is mainly to bundle packages for client to use require styled call.

Render react component on node server, with webpack

I have a react component. <myFooter>. It is a simple footer.
import React from 'react';
import './my-footer.scss';
export default class myFooter extends React.Component {
render() {
return (
<footer className="col-xs-12">
hello !
</footer>
);
}
}
I want to render it from the server-side. On the backend, I have an express server. For that I wrote this:
import myFooter from '../components/my-footer.jsx';
app.get('/footer', function(req, res) {
var string1 = ReactDOMServer.renderToString(myFooter);
res.send(string1);
});
Now the problem is that server cannot read sass files. For client side rendering, I am using webpack. Webpack builds everything and gives a bundle file.
But i'm not sure what happens if its the server side. How can I compile using webpack. If I can, will i need to compile my app for each request on node server ?
You need 2 webpack builds:
1 to build the client
1 to build the server.
When building the server, use css-loader/locals instead of css-loader in your webpack configuration.
Read through this issue for more details: https://github.com/webpack/css-loader/issues/59

How to use node module in client code?

I've installed ReactJs module in my nodejs application, so React appeared in node_modules directory. But I can't use it in client javascript because there is no reference.
So what is the best way to add such a reference ?
(Of course I can manually copy react.js script to scripts folder and add reference manually but it leads to code duplication and looks ugly)
Browserify is the tool you are looking for. It takes Node modules and wraps them so you can require() them in client side JavaScript code.
Example from Browserify's readme
Whip up a file, main.js with some require()s in it. You can use
relative paths like './foo.js' and '../lib/bar.js' or module paths
like 'gamma' that will search node_modules/ using node's module
lookup algorithm.
var foo = require('./foo.js');
var bar = require('../lib/bar.js');
var gamma = require('gamma');
var elem = document.getElementById('result');
var x = foo(100) + bar('baz');
elem.textContent = gamma(x);
Export functionality by assigning onto module.exports or exports:
module.exports = function (n) { return n * 111 }
Now just use the browserify command to build a bundle starting at
main.js:
$ browserify main.js > bundle.js
All of the modules that main.js needs are included in the
bundle.js from a recursive walk of the require() graph using
required.
To use this bundle, just toss a <script src="bundle.js"></script>
into your html!

Resources