node.js sharing javascript file between client and server - node.js

I want a JavaScript file to be included in my client as well as server.
Having some issues. Please help me.
Code:
require('app.js');
or
<script src='app.js'></script>
Which one should I use?

You can use Browserify to bundle your node module then import that js file with:
<script src='app.js'></script>
The require() function will now be on the global namespace and you can call the following to make the module available to use:
var app = require('app.js');
Note: in Browserify you'll need to export the module you want to import using require.

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

Writing WebSocket client with TypeScript running both on browser and Node.JS

I am writing a typescript code that would run in a web-browser and would be tested with Node.JS.
My client code looks like below.
import * as WebSocket from 'ws';
export class SomeClient {
constructor(url) {
this.ws = new WebSocket(url);
}
send(data: any) {
this.ws.send(data);
}
}
I had no problem in writing a unit test code using mocha/chai.
However, trying to bundle this code, browserify includes all the 'ws' node module and the size of the output file is almost 100kb. If I remove the import 'ws' statement, the bundle file size shrinks less than 1kb. But, in this case, the Node.JS test complains with 'WebSocket is not defined' error.
I think, this is because WebSocket is natively supported in web browsers but not supported in Node.JS and the external 'ws' module is required to run properly.
How can I make a bundle with the minimum size for web browsers yet can use in Node.JS???
Try isomorphic-ws:
npm i isomorphic-ws -s
or universal-websocket-client:
npm install --save universal-websocket-client
I struggled with the same problem, best solution I could find was to use isomorphic-ws create a decs.d.ts in my typescript rootDir with the following content
declare module "isomorphic-ws";
and then use it inside typescript like that:
import { IsoWebSocket } from "isomorphic-ws";
var ws = new IsoWebSocket("wss://echo.websocket.org") as WebSocket;

how to use node module with es6 import syntax in typescript

I have a typescript project which has uses one of our node modules which normally runs in our front-end. We are now looking to use this module in node on our server.
The module uses es6 import syntax import { props } from 'module/file'
When I include a ref in typescript using either of the following methods
import { props } from 'module/file';
var props = require('module/file');
I get the following error from typescript
unexpected token 'import'
(function (exports, require, module, __filename, __dirname) { import
It's a big job to re-write the module, and I've tried using babel with babel-plugin-dynamic-import-node, as well as SystemJS.
The problem with these systems is that they are all asynchronous, so I can't import the module in the standard fashion, so I would need to do a whole bunch of re-write when we get to the point that I can use import natively in node.js.
I can't be the first person to have this issue, but I can't seem to find a working solution.
--------------- update with set-up -------------
In response to #DanielKhoroshko's response. The original module I am trying to import is normally packaged by webpack in order to use on the front-end. I am now trying to use this same module both server-side and in the front-end (via webpack on the front-end) without re-writing the imports to use require and without running webpack to bundle the js to use on the server.
To be clear, the original module is written in JS, our service which is trying to use this module is written in typescript and transpiled. When the typescript tries to require the old module which uses import, it is at this point that we are running into the issue.
------------------ some progress ---------------------------
I've made some progress by creating a file in my imported module which uses babel in node.js to transpile the es6 code into commonJS modules.
I've done this via
var babel = require("babel-core")
var store = babel.transformFileSync(__dirname + '/store.js', {
plugins: ["transform-es2015-modules-commonjs"]
});
module.exports = {
store: store.code
}
I can now get the store in my new node.js project. However, the submodules within the store.js file are not included in the export.
So where in my module, it says
import activities from './reducers/activities';
I now get an error
Cannot find module './reducers/activities'
How can I get babel to do a deep traversal to include the sub-directories?
unexpected token 'import' means you are running es-modules code in environment that doesn't support import/export commands. If you are writing you code in TypeScript it's important to transpile it first before building for the browser or use ts-node to run it server-side.
If you are using webpack there are loaders ts-loader and awesome-typescript-loader
What is your setup?
To describe the module you would need to create an activities.d.ts file in the same folder where the js-version (I understood it is called activities.js and containers a reducer) resides with the following (approx.):
import { Reducer } from 'redux';
export const activities: Reducer<any>;
#Daniel Khoroshko was right in many ways, I ended up finding #std/esm which lets you import es6 modules and worked find for fetching the included imports as well.
var babel = require('babel-register')({
presets: ["env"]
});
require = require('#std/esm')(module);
var store = require('ayvri-viewer/src/store');
exports.default = {
store: store
}
I had to run babel to get a consistent build from es6 to node compatible es5

How to use Webpack loaders in a Node app?

Is there a way to use Webpack loaders in a Node app / Run a Node app in a Webpack environment?
For instance I've got a webpack config that has a style-loader. In my Node app I do the following:
import style from 'style.css'
console.log(style.someClass)
I wanna run it like $ node app.js
I've got an idea that might work, based on the Webpack NodeJS API. What if we put the code that we want to be able to use the Webpack environment (with the configured module loaders) into a module:
appModule.js:
import style from 'style.css'
console.log(style.someClass)
And require it with the following:
app.js:
import Webpack from 'webpack'
import MemoryFS from 'memory-fs'
...
webpackConfig.entry = 'appModule.js'
webpackConfig.output = 'appModule-out.js'
let compiler = Webpack(webpackConfig)
let mfs = new MemoryFS()
compiler.outputFileSystem = mfs
compiler.run(function (err, stats) {
require(webpackConfig.output)
})
Probably it won't work because the require looks for the output on the physical FS... Can we require from the memory FS? I have not tried it yet - Any idea?
Webpack loaders aren't transpilers or interpreters, they simple gather assets that are then handled off to something like SASS or a text concatenator; within the confines of Webpacks environment.
Thus it is not possible to reuse them in the way you want, because while you can of course import and call them (they're still just functions + classes), they don't convert CSS to JSON objects (they don't do this) as you have written in your desired example.
It looks like you just need a JS implementation of a css parser - have a look at https://github.com/reworkcss/css
You should be able to create a compilation targeting the node environment which you can ultimately run by simply calling node output.js and this will immediately execute the entry point module.
Be aware, in case that you're using a newer version of Node.js, that Webpack doesn't support the ES2015 module syntax, so you'll have to configure Babel for Node.js as well to transform the modules.

ES6 React server-side rendering, how to import a React Component?

I'm transpiling ES6 to ES5.
BabelJS for the NodeJS Express server files and server-side rendering output to a directory build/server/.
Browserify + babelify for the ReactComponents output to a build/client/bundle.js file
When trying to import a React Component from build/client/bundle.js to a build/server/ file the app crashes because I'm importing an untranspiled ReactComponent.
How could I import the ReactComponent without duplicating the code in the server (re-using the code from the client/bundle.js)?
You have a few solutions:
Your server code doesn't need to be pre-compiled. If you run it with babel-node, it will be compiled on-the-fly.
You could bundle your server code. I don't know any resource on how to do it with browserify, but here's a very good resource to get started with webpack for your backend.
You could build your client code alongside your server code.

Resources