Enabling html5 mode with AngularJS and a external NodeJS server - javascript

So I've read almost every SO answer/question to this topic, but still I have many questions in my head.
First, the problem:
I have an AngularJS app with html5 enabled, so I can get rid of the '#' sign.
$locationProvider.html5Mode({ enabled: true, requireBase: true });
$locationProvider.hashPrefix('!');
This is the important part in my index.html:
<!DOCTYPE html>
<html ng-app="application" ng-controller="ApplicationController as app">
<head>
<meta name="fragment" content="!">
<title>LivingRoomArt</title>
<meta charset="UTF-8">
<base href="/index.html" />
I am communicating with a NodeJS server which is using express:
router.route('/events')
.post(authController.isAuthenticated, eventController.postEvent)
.get(eventController.getEvents);
// Register all our routes with /api
app.use('/api', router);
// Start the server
app.listen(process.env.PORT || 5000);
So, the usual problem:
After reloading, I am getting an 404 from the server. I get the concept of this here, the suggested solution everywhere:
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
res.sendfile('index.html');
});
});
The thing is, I don't have an index.html file on my server, neither do
I want to duplicate it on my server.
So how do I tell Node to handle requests properly without storing html-files on my server?
I am hosting the Node app on Heroku, if this helps.

When you say you don't serve static files, you're saying that the node.js API isn't right?
I guess you end up with two distinct urls, let's call them http://api.com and http://client.com.
I don't understand why your API should handle the 404. Do you load http://api.com in your browser and expecting your index.html? If it's really your use-case, I would advice a simple routing to declare in your API like:
app.all('/*', function (req, res) {
res.redirect('http://client.com');
});
Which will redirect all requests not catched by your previous routes declaration to your client website.
Then, there is two options:
If the server that serves your static files is another Node.Js server using express, you could perfectly do the sendfile, since you now have access to the index.html
If you're using Nginx, (which I strongly recommend if you don't) for the statics, you could do a configuration like this to redirect all failed requests (missing files / routes) to the index.html
server {
listen 80;
root /app/www;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}

Related

nodejs config on subdirectory

I have a sub-domain and I publish my server.js on this directory. everything work fine. but I want to running my server.js inside a directory(because I want to run my react.js project on sub directory). for example:
web.example.com/sr
web is my subdomain and sr is my directory.
but my routes not worked at all:
web.example.com/sr/user/1
I got this error message:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot POST /sr/user/1</pre>
</body>
</html>
Should I make any changes or is there any config to do this?
You can't do deployment-level configs to serve your react app to the subdir /sr. Every call to your.domain.com/sr/* will end up in your server and pass /sr/* to it (and not simply /*.
You'll have to code your server to serve your React app. If you bundle your react app to index.html and bundle.js, you'll have to write something like this (if you're using express, which you probably do):
app.get(/\/sr\/\.js/, (req, res) => res.sendFile(`${__dirname}/bundle.js`));
app.get(/\/sr\/*/, (req, res) => res.sendFile(`${__dirname}/index.html`));
If you're using react-router, you'll have to set it up too so as to take into account the leading /sr in your URL.

Serve static index.html and API on same port

I'm using Node/Express as an API proxy server and want to know if it's possible to render HTML (index.html) page for all GET routes as well as expose API endpoints on the same port. I'm using client side routing (react-router).
For example:
// Always return the main index.html, so react-router render the route in the client
app.get('*', (req, res) => {
const html = renderHTML(req, res);
res.send(html)
});
// Expose API
app.all('/api/*', (req, res, next) => {
proxyRequest(...)
});
The problem is that doing when doing a GET request, the first app.get() catches it (for example: fetch('/api/accounts')).
I need to be able to make any request to any API endpoint route (besides /) and have the client send any method (GET, PUT, POST...).
Can I serve index.html to all client routes and have GET endpoints on the same port? Can I serve html to all routes except ones prefixed with /api/?
If you expose your endpoints first and then serve your html, it should do the job.
// Expose API
api.all('/api/*', cb);
// Serve HTML
api.get('*', cb);
Make a directory called public.
Put your HTML and supporting files in it.
app.use(express.static(path.resolve('./public')));
//Your API routes here
The express.static will serve the static HTML files and then you can add your route statements. This will work on the same port.

Cannot refresh page in production when compiled with webpack

I am building an app using node.js + express.js + react.js and I'm using webpack to compile the client side code. The problem I am having is after my client side code is compiled with webpack and I run my app, I cannot refresh the page.
My code:
My webpack compiles my files into /dist/index.html, my app runs on port 3000, and all client side routes are prefixed with /admin.
app.get('/', function(req, res) {
res.render('dist/index.html');
});
When I go to localhost:3000 in the browser and click around the links, the app works fine. However, if I go to, as an example, the about page:
localhost:3000/admin/about
And I refresh, I get the error Cannot GET /admin/about.
I believe the reason is my express router only knows about the / route... so If I refresh directly onto a route like /admin/about, express doesn't know what to render so my solution was to include a "catch all" route:
app.get('*', function(req, res) {
res.render('dist/index.html');
});
However, this keeps giving me the Error: Failed to lookup view "dist/index.html" error.
Can someone help?
Thanks in advance!
After research, I found the solution isn't res.render but res.sendFile:
res.sendFile(path.join(__dirname, '/dist/index.html'));

Setting up static assets paths, routing endpoints with koa and various middleares

Question:
How can I set up my static files so that both directories are visible to my index.html.
How can I send my index.html when you hit the default route using koa-router vs. just a .json file when I make an AJAX Get request?
Requirements:
I need static directories to be visible in my apps src/index.html
node_modules needs to be open for js libs.
src/assets needs to be open for images.
I need a router for 2 purposes :
1) serving up the initial index.html
2) CRUD endpoints to my DB.
Notes: I'm totally willing to add/subtract any middleware. But I would rather not change how I organize my directories.
Directory Structure:
Middleware:
koa-static // cant serve node_modules + src directory.
koa-send // can send static files but then breaks koa-static
koa-router // cannot
app.js
var serve = require('koa-static');
var send = require('koa-send');
var router = require('koa-router')();
var koa = require('koa');
var app = koa();
// need this for client side packages.
app.use(serve('./node_modules/'));
// need this for client side images, video, audio etc.
app.use(serve('./src/assets/'));
// Will serve up the inital html until html5 routing takes over.
router.get('/', function *(next) {
// send up src/index.html
});
// will serve json open a socket
router.get('/people', function *(next) {
// send the people.json file
});
app.use(router.routes()).use(router.allowedMethods());
// errors
app.on('error', function(err, ctx){
log.error('server error', err, ctx);
});
app.listen(3000);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Morningharwood</title>
</head>
<body>
<h1>suchwow</h1>
<img src="./assets/image1.png" alt="butts"> <!-- will 404 with routing -->
<script src="./node_modules/gun/gun.js"></script> <!-- will always 404 -->
<script>
var gun = Gun(options);
console.log(gun);
</script>
</body>
</html>
Well. it happens that I'm developing a similar kind of app
There's no problem on using koa-static to serve you static content and koa-router for you api endpoint. I never used koa-send directly. but I think you doesn't need too, given your set up
The only thing that matters is the order when attaching middleware to koa app. Try to attach koa-static first for your assets ( and maybe even index.html) and later use the koa-router for your api. Requests trying to get some static file never reach the router. and this way the router only responsibility will be serving your api
If that's not posible ( for example, because you have a bunch of non-static html files to server, consider taht you can have more than one router per app, even nesting one inside the other
( If the answer is not enough, give some time to cook a simple example. I'll post it as soon as possible)
EDIT: added a quick and dirty example here. Probably it doesn't work out of the box, but it's enough to get the idea

Full stack javascript routing explanation needed

I've scaffolded a full stack Mongo, Express, Angular, Node app using yeoman with the Angular Fullstack generator
It has created a server/app.js file, which executes a routes.js to handle resources being served by the express server.
The meat of routes.js looks like this:
// Insert routes below
app.use('/api/things', require('./api/thing'));
app.use('/api/users', require('./api/user'));
app.use('/auth', require('./auth'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
My question is how any file other than index.html gets served to the browser. I've tested, and for example the file "http://localhost:9000/assets/images/yeoman.png" does get returned to the browser. But how? From what I am reading in the routes.js, a request to that png should return the text of index.html
I'm a bit confused by this and would really appreciate an explanation.
Thanks!
If you go into config/express.js you will see something like this:
app.use(express.static(path.join(config.root, 'public')));
Which should be self-explanatory.
UPD. With routes you can overwrite this behaviour for specific files (if you really need it).

Categories

Resources