Cannot render my react app server side - node.js

I am trying to render a basic react component via node js .
Unfortunately i got some errors. I think this is related to es6.
The problem is i already wrote a lot of code in es6 and now i want to render it in node js. I can't rewrite my entire app, so how to import my components and make them compatible witch node js.
What is what i've tried since now :
const filePath = path.resolve(__dirname, 'index.html')
fs.readFile(filePath, 'utf8', (err, htmlData)=> {
if(err){
return res.status(404).end()
}
const app = renderToString(<ReactApp />)
const RenderedApp = htmlData.replace('{{SSR}}',app)
res.send(RenderedApp)
})
I got this error SyntaxError: Unexpected token <
This is because ReactApp is a react component
i don't know how to import it on my node.
Any solutions ?
thanks

Related

How to process JS file returned from Express response.sendFile()

I have an API which uses Node.js + Express on the backend.
For one of the API endpoints, I'd like to use the Express response object method of "sendFile", documented here:
https://expressjs.com/en/api.html#res.sendFile
The API should return a Javascript file through the sendFile method.
What I can't figure out is how to read in the .js file on the front end so that I can use the JavaScript functions defined in the file. The sendFile portion appears to be working -- it's just the use of the file which I can't figure out.
Here's what I'm doing on the backend:
app.get("/api/member", async (req, res) => {
options = {
root: path.join(__dirname, '/static'),
dotfiles: 'deny'
}
res.sendFile("member.js", options, (err) => {
if (err) {
console.log(err)
next(err)
} else {
console.log('Sent file')
}
})
});
This seems to be working fine, as I can navigate to the endpoint on my localhost and it loads the JS file. The file member.js simply contains some javascript function definitions.
But, I can't figure out how to consume/use the file once it arrives to the front end.
Here's what I have currently on the frontend:
async function refreshJS() {
const url = `${baseUrl}/member`;
const response = await fetch(url, { credentials: "include" });
const script = document.createElement("script")
script.type = "text/javascript"
script.src = response.body
document.head.appendChild(script)
eval(script)
}
I've spent a lot of time looking through the console/debugger to find the text associated with the JS functions -- but they're nowhere to be found.
I've tested this general framework by loading JS files locally through the console and it worked, so I think it's wrapped up in a misunderstanding of where the JS functions live in the API response. For example, if I replace the command above of:
script.src = response.body
with
script.src = "member.js"
then everything works fine provided I have the file locally.
The examples that I've reviewed seem to deal exclusively with sending an HTML file which is loaded on the frontend. But, I can't find supporting documentation from the fetch API to understand how to use the JS file contents.

How to achieve code splitting + SSR with #loadable/component ? Is webpack needed for the server code?

I'm trying to add code splitting + SSR to my React web app using #loadable/component.
My current situation: This is how I've implemented SSR for robots on my website. Since it's just for robots, I'm not using hydrate. Basically, I send either the index.html with the JS bundle's script tags for a regular user, or I send a fully rendered HTML page for the robots, without the need to hydrate.
My goal: I'd like to use #loadable/component to always return SSR pages from my server, and use hydrate to attach my JS bundle. And also achieve code splitting with that.
Here is how I currently build my app (pseudo code):
1. webpack BUILD FOR entry { app: "src/index.tsx" } AND OUTPUT BUNDLES TO MY /public FOLDER
2. babel TRANSPILE WHOLE `/src` FOLDER AND OUTPUT FILES TO MY /dist_app FOLDER
It's basically 2 builds, one of them is using webpack to bundle, and the other one basically transpiles the files from src to distApp.
And this is what my server does (pseudo code)
1. CHECK IF USER IS ROBOT (FROM THE USER AGENT STRING)
2. IF REGULAR USER
res.send("public/index.html"); // SEND REGULAR index.html WITH JS BUNDLES GENERATED BY WEBPACK
IF ROBOT
const App = require("./dist_app/App"); // THIS IS THE src/App COMPONENT TRANSPILED BY BABEL
const ssrHtml = ReactDOM.renderToString(<App/>);
// ADD <head> <helmet> <styles> ETC
res.send(ssrHtml);
The steps described above works just fine for my initial requirements (ssr just for robots).
But after I added #loadable/component to achieve code splitting + SSR, the set up above does not work anymore.
Because now I have dynamic imports on some of my routes. For example:
const AsyncPage = loadable(() => import("#app/pages/PageContainer"));
So my renderToString(<App/>) call comes back mostly empty, because it does not load those AsyncPages.
Over on the docs for Loadable components: server side rendering they have an example repo on how to achieve this.
But their example is kind of complex and it seems they are using webpack inside the server. I'll post what they do on their server below.
QUESTION
Do I really have to use webpack to bundle my app's server code in order to use #loadable/component for SSR like they are showing in their example? Can't I just use some kind of babel plugin to convert the dynamic imports into regular require calls? So that I'll be able to render it the way I was doing before?
It's weird, that they use webpack-dev-middleware. It's like this example should be used just for development. Does anybody know a repo with a production example of this?
import path from 'path'
import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { ChunkExtractor } from '#loadable/server'
const app = express()
app.use(express.static(path.join(__dirname, '../../public')))
if (process.env.NODE_ENV !== 'production') {
/* eslint-disable global-require, import/no-extraneous-dependencies */
const { default: webpackConfig } = require('../../webpack.config.babel')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpack = require('webpack')
/* eslint-enable global-require, import/no-extraneous-dependencies */
const compiler = webpack(webpackConfig)
app.use(
webpackDevMiddleware(compiler, {
logLevel: 'silent',
publicPath: '/dist/web',
writeToDisk(filePath) {
return /dist\/node\//.test(filePath) || /loadable-stats/.test(filePath)
},
}),
)
}
const nodeStats = path.resolve(
__dirname,
'../../public/dist/node/loadable-stats.json',
)
const webStats = path.resolve(
__dirname,
'../../public/dist/web/loadable-stats.json',
)
app.get('*', (req, res) => {
const nodeExtractor = new ChunkExtractor({ statsFile: nodeStats })
const { default: App } = nodeExtractor.requireEntrypoint()
const webExtractor = new ChunkExtractor({ statsFile: webStats })
const jsx = webExtractor.collectChunks(<App />)
const html = renderToString(jsx)
res.set('content-type', 'text/html')
res.send(`
<!DOCTYPE html>
<html>
<head>
${webExtractor.getLinkTags()}
${webExtractor.getStyleTags()}
</head>
<body>
<div id="main">${html}</div>
${webExtractor.getScriptTags()}
</body>
</html>
`)
})
// eslint-disable-next-line no-console
app.listen(9000, () => console.log('Server started http://localhost:9000'))

Can't access NodeJS api from Angular app

I have trouble trying to get to my NodeJs server from my angular app. Here's my router:
app.get('/new12345',function(req,res){
console.log("Http Get Recently Gone from /new12345");
var results = userData;
res.send(results);
});
Here where I try getting to my api.
this.http.get('/new12345').subscribe(data => {
this.resultInArray = data['results'];
}
I am getting this error though:
Error: Cannot match any routes. URL Segment: 'new12345'
Thanks!
You did not specify your api base url. You are currently getting to your angular app (hence the angular router error you are getting).
For example, that might look like this:
this.http.get('http://localhost:3000/new12345').subscribe(data => {
this.resultInArray = data['results'];
}

Router is not defined in KOA2

I have two files, one of them is the app.js and the otherone is api.js.
In the first file I have :
app.use(setHeader)
app.use(api.routes())
app.use(api.allowedMethods())
And in api.js I have:
import KoaRouter from 'koa-router';
const api = new Router();
//Validatekey
const validateKey = async (ctx, next) => {
const { authorization } = ctx.request.headers;
console.log(authorization);
if (authorization !== ctx.state.authorizationHeader) {
return ctx.throw(401);
}
await next();
}
api.get('/pets', validateKey, pets.list);
When I run the project a error message is throw: Router is not defined.
But If I write both files together, the application go fine.
Anybody knows the problem?
I have solved with var Router = require('koa-router')
The import is currently not implemented in nodejs, neither is it supported in the latest ES2015(ES6).
You will need to use a transpiler like Babel to use import in code.I advice that avoid transpiler as it cause performance issues on production just go with require and it will work.
Obviously Nodejs does not support import / export syntax and using require will solve your problem.
However it is possible to make import work on Node.js by using babel transformers.
Look the following answer for more information https://stackoverflow.com/a/37601577/972240

Syntax Error rendering ReactJS view

engine as an alternative to EJS in my node.js app. Anyway I used this example from here: https://github.com/reactjs/express-react-views
var React = require('react');
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
module.exports = HelloMessage;
However I'm getting this error:[SyntaxError: D:\Data\ytko\elbp\views\index.jsx:5
return ;
^
Unexpected token <];
Considering I copied this verbatim I'm slightly confused as to whats going on.
Thanks

Resources