How to render a React component with a express router? - html

So I have began my project as a React single page application. But it turns out it would be more convenient to have a basic back-end for rendering the pages and have a real routing.
Plus I have some variables that need to be accessible from all pages, and putting them as props to all the components is really heavy. So sending them with the pages could be a solution.
So I added Express, and I can now render a basic HTML page with it.
But I don't know how I am going to link my react component to this html file. Or pass it the needed variables.
I used react-router-dom but it doesn't support page refreshing. And it doesn't help with having global variables needing to be accessible from all components.
Here in my index.js you can see how I render my basic html file, and also at the end and commented, how my react component was rendered before adding express.
app.use(express.static('public'));
router.get('/', function(req, res, next) {
res.sendFile('./public/views/loginView.html' , { root : __dirname});
});
app.use(router);
app.listen('8080');
// const wrapper = document.getElementById("app");
// wrapper ? ReactDOM.render(<App />, wrapper) : false;
Here my loginView.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<!-- links and scripts -->
<title>The login page</title>
</head>
<body>
<div id="app">
content
</div>
</body>
</html>
Is there a simple way to link my html file with its react component and render it ?
If not, is there another way to make some variables (which are not constants) accessible from every react component (maybe react-redux) ?

So with React you want to create a production ready bundle. This normally involves splitting the bundle up so you aren't serving a 5+Mb file to the user to download (using 4G for example with poor connection would take too long) and minifying and uglifying the code (so no one steals your code). These bundled javascript files would then be hosted on your server with reference to them in the HTML file.
The express app would then go along the lines off any route just display the HTML file e.g. router.get('*', (req, res) => res.send('index.html)).
I would recommend using webpack to create the bundle as it helps with the splitting and minifying etc. Take a look at webpack for development and production aswell as create-react-app for quick project setup.

Related

Should I add my html code to index.html or App.js on my react app?

I'm just starting React and I'm confused on how to start adding my previous static website code into the react app. My react app contains a folder called public and a file in it called Index.html and it seems the changes in Index.html effect the website. But I've seen lots of videos and online forms where people add their website code into the App.js file located in src using JSX instead of the public folder.
I have 3 html files in my old static website and I'm wondering where to put the code from these files.
I also have node.js as the backend server but don't know if that should effect the answer.
Thank you :)
I would consider transforming the HTML code into JSX and make components out of it, that way your set up better for future changes.
If you want to keep as HTML code, you can implement it as an <iframe src={"yourComponent"}/> into your App.js.
Keep in mind that your HTML code should be stored in the public folder, the path that you put in the iframe will start at the public folder.
For example, you have a folder html in your public folder:
export default function YourComponent(){
return <iframe src={"/html/yourcode.html"} />
}

How to Merge React App into existing Website with existing HTML structure

We have a <html> file stored on AWS S3. The file contains header and footer information.
This file has it's own build pipeline, we collect some data from a database and generate the HTML and upload to S3.
We would now like to include a bundled React App into this HTML page. I.e. within the body of the page will be the bundled react application.
The React App is built on the latest create-react-app setup and therefore, babel and webpack are pre-configured. The react build creates all the relevant files if the app was hosted without the above setup.
Is there a way to merge the two pages?
**Notes: Specifically looking for a merge as part of the build process. **
We have one project that generates a header html and publishes it onto an S3.
We have triggers that might trigger this to regenerate at specific times/after changes etc.
We have a React App that is bundled with babel/webpack in a production build and produces the output HTML/bundle js etc. All minified and hashed, so the file names are bundle.randomhash.js etc.
We need to merge the two outputs. The html file from S3 needs to include the React App within its body/html.
Ideally in a pipeline/build process. So if one changes, the merge is re-compiled/re-run.
I think you are looking for an automatic way of merging two outputs, one being your existing HTML with header and footer generated from your existing build process and triggered via a database.
The second being your react app which is a well finished final output that comes out of your create-react-app build infrastructure.
In such a case, I would recommend to use this very popular tool called gulp-inject. gulp-inject takes a stream of source files, transforms each file to a string and injects each transformed string into placeholders in the target stream files.
An example is given below:
Let's say your target file is called index.html like this
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
Your gulpfile.js script would look like this to achieve a new index.html with new insertions automatically based on this script.
var gulp = require('gulp');
var inject = require('gulp-inject');
gulp.task('index', function () {
var target = gulp.src('./src/index.html');
// It's not necessary to read the files (will speed up things), we're only after their paths:
var sources = gulp.src(['./src/**/*.js', './src/**/*.css'], {read: false});
return target.pipe(inject(sources))
.pipe(gulp.dest('./src'));
});
Your final output of your index.html would look like this after running gulp index:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:css -->
<link rel="stylesheet" href="/src/style1.css">
<link rel="stylesheet" href="/src/style2.css">
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<script src="/src/lib1.js"></script>
<script src="/src/lib2.js"></script>
<!-- endinject -->
</body>
</html>
The basics of converting an existing HTML file and inserting it with ReactJS code is given below. I think if you apply these principles and use the gulp-inject tool, you can achieve wonders.
https://reactjs.org/docs/add-react-to-a-website.html
Your exact build automation maybe driven by your own tool such as Jenkins or such similar tools where you could chain one event with the other. For example, you could check whenever a new HTML file is automatically generated by your Database Triggering on AWS and once that event is received, you could trigger either the Gulp-Inject script if you already have the React Component(s) ready or trigger the Create-React-App to freshly build the React Component and then apply the Gulp-Inject script to inject your React Component or React Code into the index.html or whatever the name of your html page.
The npm package for gulp-inject can be found here.
https://www.npmjs.com/package/gulp-inject
Hope this helps. Let me know.
If you like the answer, you can accept it.
To do this you need to host your js, css, and media files from your react build folder in an S3 bucket and add the following to the code.
<html>
..... your static html code
<div id="the id used to bootstrap your react app (from the index.html file in the public folder)"></div>
......
links to all the files in your JS, CSS And media files from the react build folder
</html>
I would suggest to use hosted images (you can host them on S3 as well) and assets as much as possible so you don't need to add the media file links on by one in the html file.
You may want to look at this link on how to bundle all files into one file when building your react app (I haven't tried this part).

Using Static HTML landing page template with Angular 6 application

I have an Angular 6 app hosted on say example.com (dist folder being served using say port 5000) and a landing page folder with its HTML, CSS, JS files being served on say port 6000 and hosted on example.com/welcome
Is there any way I can merge these two such that example.com uses landing page static folder and example.com/#/* (Angular app uses hash in routing) uses dist folder?
I do not want to merge landing page into a component in Angular app due to clashing of CSS, and other issues.
I need landing page to be loaded without loading Angular app first and without changing any URL/routing logic of Angular app.
Solutions I tried:
Following code works but loads angular app first and then loads landing page. What I want is that landing page needs to be loaded first.
app.use('/welcome',express.static(__dirname + '/landing'));
app.use(express.static(__dirname + '/dist'));
app.get('/',(req,res)=> {
res.redirect('https://example.com/welcome');
})
I tried to make home component of Angular app redirect to /welcome but that too requires loading of Angular app first before the landing page.
Any solution around Express/Nginx?
I would try to separate angular files and landing page files each in a different directory within the static directory.
app.js:
// serve static files
app.use(express.static(path.join(__dirname, 'public')));
// serve angular app
app.get('*', (req, res, next) => {
// Landing page exception
if (req.originalUrl === '/welcome') {
return next();
}
res.sendFile(path.resolve('public/dist/index.html'));
});
// serve landing page
app.get('/welcome', (req, res) => {
res.sendFile(path.resolve('public/welcome/index.html'));
});
angular router:
if (!window.location.hash && window.location.pathname === '/') {
// redirect the request to GET /welcome
}
public/welcome/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Landing Page</title>
</head>
<body>
</body>
<!--static files can be accessed at public/welcome/-->
<script type="text/javascript" src="welcome/test.js"></script>
</html>
This answer partly solves the problem. I tried to implement a solution based on the idea given by #mas and it worked. Below is what I changed:
server.js:
app.use('/welcome',express.static(__dirname + '/landing'));
app.use(express.static(__dirname + '/dist'));
Now adding a script in Angular app's root index.html before <app-root> (preferably before the body contents):
angular's index.html:
<script>
if (!window.location.hash && window.location.pathname === '/') {
// redirect the request to GET /welcome
window.location.href = "https://example.com/welcome";
}
</script>
When the browser encounters a script tag when parsing the HTML, it stops parsing and hands over to the Javascript interpreter, which runs the script. The parser doesn't continue until the script execution is complete. Thus, angular's index.html redirects users to landing page before loading the angular app on the user's browser.
This implementation partly solves the problem in the following ways:
Loading of static landing page without loading angular app before it.
No change in the URL/routes of the angular app
It doesn't solve the problem of wanting to load the landing page on same URL i.e. https://example.com and still redirects users to a different path: https://example.com/welcome
Now, if the user hits the domain, it will immediately load the static landing page.

how to build a React application as a widget inside another website

I have been building SPAs (Single Page Applications) using React. Whenever I start a new project, I use create-react-app. So far so good.
I now have received a request to load a React application as a widget within an existing HTML page.
My question: how do I achieve this? I can refer to the react files using the CDN links as well as Babel however I am having trouble wrapping my head around packaging this all up using Browserify or Webpack.
Any of you have experience with this already? Perhaps you can share with me what works best.
I have tried googling this with not much luck.
Thank you.
Just add lines to webpack.config.js
...
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
plugins: [...],
....
to exclude React from bundle and then add it at page before your bundle
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<script type="text/javascript" src="/scripts/app.bundle.js"></script>
(it will mount as usual to specified HTML element)

Express Layouts EJS with different file paths

I am just starting with Express and express-ejs-layouts. I have a layout.ejs file that has the common parts of my web app. This works great for pages that are at http://localhost/path1/path2, but I would also like to use this for the root index page of my app (i.e.: http://localhost/
The problem is the links for the CSS and JS files:
<link href="../../stylesheets/main.css" rel="stylesheet" type="text/css">
This doesn't work for http://localhost/
Should I break this out and add it to each view template with the correct pathing? How have people done this in the past?
You can use absolute URLs for static files (eg. href="/public/css/" ) to avoid this issue.
For Node.js/Express.js web applications, it's convenient to create a public folder at the root, where you put all your static files.