I'm an express noob here and building a React App with server using express and client using create-react-app.
What I want to do
I want to update the title and meta tag in the index.html.
So browser requests url -> Server gets request and adds the title and tag to the index.html -> return it to the browser.
Listed my code here
...
app.use(bodyParser.json())
app.use(aMiddleware)
app.use("/api/foo", bar)
app.use(express.static('client/build'));
if (process.env.NODE_ENV === 'production') {
const path = require('path');
app.get('/*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../client', 'build', 'index.html'))
})
}
Questions
Code is functioning, but I don't know how to replace the title/tag in the index.html
How do I update/replace index for environment that is not prod?
Fo prod environment, I use path.resolve(__dirname, '../client', 'build', 'index.html'), then where is index.html for dev environment? I see there is an index.html in public folder, is it the one that got rendered for dev environment?
I tried to add this code before app.use(express.static(...))
app.get('/', function(req, res) => {
// maybe replace string in the index.html (though I don't know where is it
// then res.send(...)?
})
but this never got triggered. Why?
Stuck on this for a while, tried many things, any help would be great.
You can use react-helmet for this... Or switch to Nextjs which is server side.
https://www.npmjs.com/package/react-helmet
I want to deploy CRA bundles to s3 and serve from cloudfront. But index file should be express view (template, I want to add some data to it). All solutions I've found assume serverless or serve CRA index directly from node.
So, I need index to be template and contain cloudfront URLs to bundles. How can I achieve this?
If you need to create and index.html you could do that without template
app.get('/', function(req, res) {
res.type('text/html');
res.send('<html>...</html>');
});
Or with templates like
Jade
doctype html
html
head
title Jade Page
link(href='https://cloudf../css/main.css', rel='stylesheet')
body
h1 This page is produced by Jade engine
p some paragraph here..
Source : https://www.tutorialsteacher.com/nodejs/jade-template-engine
Pug
html
head
title= title
link(href='https://cloudf../css/main.css' rel='stylesheet')
body
h1= message
app.get('/', function (req, res) {
res.render('index', { title: 'Hey', message: 'Hello there!'});
});
https://scriptverse.academy/tutorials/nodejs-express-pug.html
https://stackoverflow.com/a/38047123/3957754
My Heroku app is using React with React Router. I use Switch to navigate through different components, so the URL changes as well (e.g. /room/4141). However, if I reload the page, it doesn't act like if it was a React app, but instead it searches for the mentioned .html file.
I used this Buildpack: https://github.com/mars/create-react-app-buildpack.git but it seems to do nothing in regards with pages being rewritten to index.html.
Is there a way to prevent this behaviour and rewrite all URLs to index.html?
**EDIT:
I'm not familiar enough with express, but here's how the index.html is served.
const express = require("../../node_modules/express");
const app = express();
const server = require("http").Server(app);
const io = module.exports.io = require('../../node_modules/socket.io/lib')(server)
const path = require("path")
app.use(express.static(path.join(__dirname, '../../build')));
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, '../../build')));
console.log("DEBUG HERE", __dirname, path.join(__dirname+'../../build'));
//
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname+'../../build/index.html'));
})
}
//build mode
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname+'../../public/index.html'));
})
That buildpack can be configured via a JSON file:
You can configure different options for your static application by writing a static.json in the root folder of your application.
One of the sample routing configurations looks like it does exactly what you want:
When serving a single page app, it's useful to support wildcard URLs that serves the index.html file, while also continuing to serve JS and CSS files correctly. Route ordering allows you to do both:
{
"routes": {
"/assets/*": "/assets/",
"/**": "index.html"
}
}
I serve my Angular app using an express server.
var express = require('express');
var server = express();
server.use(express.static('./app'));
server.all('*', function(req, res) {
res.sendFile('index.html', { root: './app' });
});
server.listen(8000);
Full gulpfile.js is here.
When I navigate to http://localhost:8000, my Angular app redirects to http://localhost:8000/home, and app.css is served properly (I get CSS in the response).
However, if I refresh the page (http://localhost:8000/home), the response for app.css is index.html.
Why is this happening, and how would you fix that?
DEMO HERE
You need to use an absolute path.
<link rel="stylesheet" type="text/css" href="/app.css">
Otherwise the request to express for app.css from /home will be home/app.css not /app.css.
Is it possible? I would like to set up two different directories to serve static files. Let's say /public and /mnt
You can also set the path that static files will be served to the web from by specifying an additional (first) parameter to use() like so:
app.use("/public", express.static(__dirname + "/public"));
app.use("/public2", express.static(__dirname + "/public2"));
That way you get two different directories on the web that mirror your local directories, not one url path that fails over between two local directories.
In other words the URL pattern:
http://your.server.com/public/*
Serves files from the local directory public while:
http://your.server.com/public2/*
Serves files from the local directory public2.
BTW this is also useful if you don't want static to serve the files from the root of your server but rather from a more qualified path.
HTH
You can also "merge" directories into a single visible directory
Directory Structure
/static
/alternate_static
Code
app.use("/static", express.static(__dirname + "/static"));
app.use("/static", express.static(__dirname + "/alternate_static"));
Both static and alternate_static will be served as if they were in the same directory. Watch out for filename clobbers, though.
It's not possible by one middleware injection, but you can inject static middleware multiple times:
app.configure('development', function(){
app.use(express.static(__dirname + '/public1'));
app.use(express.static(__dirname + '/public2'));
});
Explanation
Look at connect/lib/middleware/static.js#143:
path = normalize(join(root, path));
There is options.root is static root, which you define in express.static or connect.static call, and path is request path.
Look more at connect/lib/middleware/static.js#154:
fs.stat(path, function(err, stat){
// ignore ENOENT
if (err) {
if (fn) return fn(err);
return ('ENOENT' == err.code || 'ENAMETOOLONG' == err.code)
? next()
: next(err);
Path checked only once, and if file not found request passed to next middleware.
Update for Connect 2.x
Links to code are inactual for Connect 2.x, but multiple static middleware usage are still posible as before.
I also faced the same issue but I managed it to resolve it, after a long search for this quest.
Step 1:
Serve the static files in the pathnames of /public and /mnt
app.use('/public', express.static(path.join(__dirname, '<path_to_the_folder_you_want_to_serve_public>')));
app.use('/mnt', express.static(path.join(__dirname, '<path_to_the_folder_you_want_to_serve_mnt>')));
Step 2:
My plan was to deploy two Angular client apps in a single NodeJS server.
So I ran the 'ng build' on both Angular client apps.
I placed one of dist folder in '/public' folder and another dist folder in '/mnt'.
Step 3:
Need to modify the index.html by changing the following things to show the public folder content,
<script src="./public/runtime.js" defer></script>
<script src="./public/polyfills.js" defer></script>
<script src="./public/styles.js" defer></script>
<script src="./public/vendor.js" defer></script>
<script src="./public/main.js" defer></script>
Need to modify the index.html by changing the following things to show the mnt folder content,
<script src="./mnt/runtime.js" defer></script>
<script src="./mnt/polyfills.js" defer></script>
<script src="./mnt/styles.js" defer></script>
<script src="./mnt/vendor.js" defer></script>
<script src="./mnt/main.js" defer></script>
Important Note : Change the .js files path based on the static folder serving path.
Step 4:
In one path, you can serve public and on another you can serve mnt.
app.get('/', function(req, res) => {
res.sendFile(path.join(__dirname, '../public/dist/index.html'));
})
app.get('/', function(req, res) => {
res.sendFile(path.join(__dirname, '../mnt/dist/index.html'));
})
Now you are good to go. Run & Test it.
const express = require('express');
const path = require('path');
const pagesPath = path.join(__dirname, '/cheatsheet');
const cssPath = path.join(__dirname, '/stylesheet');
const port = process.env.PORT || 3000;
var app = express();
app.use("/cheatsheet" ,express.static(pagesPath));
app.use("/stylesheet",express.static(cssPath));
app.get('/',(request,response)=>{
response.send('Hello CSS!!!');
});
app.get('/bad',(request,response)=>{
response.send({error: 'Bad Request'});
});
app.listen(port, ()=> {
console.log(`Server is running on Port ${port}` );
console.log(__dirname);
});
// folder structure
/cheatsheet/index.html
/stylesheet/style.css
To use express.static inside custom middleware:
app.use(customMiddleware())
where
const customMiddleware = function() {
return function(req, res, next) {
// do some dynamic code
// or
return express.static(__dirname + "/public")(req, res, next);
}
}
we can dynamically enable static files in nodejs server with respect to perticular route
app.use("/test", (req, res, next) => {
if (req.session.isAuth === undefined) {
let middleware = express.static(path.join(__dirname, "staticPages"));
middleware(req, res, next);
} else {
next();
}
});
use :dir instead of *
eg
this.app.use('/:microsite', express.static(path.resolve(process.cwd(), 'client/')))