Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express node worked as pushState enabled server serve any static resource without any path prefix

I am building a single page web application with Ember.js or Backbone.js as front end MVC, express.js(node.js) as back end server.

server/app.js code in short

app.use(bodyParser.json());

app.use(express.static(path.join(__dirname, '..', 'client')));
app.get('*', function(req, res) {
  return res.render('base'); (will sendFile (client/index.html) )
});

It will load up the client/ folder with all the public assets, client folder structure looks like this

- client
   -- index.html ( will be rendered as always )
   -- app (front end mvc code)
   -- assets
      -- images
      -- styles

When html5 pushstate is enabled by front end MVC, express server is always serving all the matching route as well, which in turn render index.html as always when page is refreshed or url is being manually inserted in the browser.

client/index.html (sample code)

<link rel="stylesheet" href="assets/styles/reset.css">
<link rel="stylesheet" href="assets/styles/base.css">

Here are three different URLs cases

localhost:3000/        (root)
localhost:3000/users  || localhost:3000/#/users (hard url)
localhost:3000/users/1    || localhost:3000/#/users/1  ( dynamic segment)

When I defined any static resource as relative path, it works on matching path with root url and hard url on page refresh, it serves resources as

GET /assets/styles/reset.css 304 1ms
GET /assets/styles/base.css 304 2ms

But when I got to localhost:3000/users/1 and refresh the page, I got the wrong resource url, so it failed on loading client/index.html since there are no resources in that path.

GET /users/assets/styles/reset.css 304 2ms
GET /users/assets/styles/base.css 304 6ms

Then I switched to absolute path in client/index.html (sample code)

<link rel="stylesheet" href="/assets/styles/reset.css">
<link rel="stylesheet" href="/assets/styles/base.css">

it works well even in the dynamic segment url localhost:3000/users/1, all resource serve in the correct url path. but I have an html img tag <img src="assets/images/icons/star.png" alt="star"> in front end mvc template which will be rendered when application boots up. When I load up localhost:3000/users/1 on page refresh, here is what I get

GET /assets/styles/reset.css 304 1ms
GET /assets/styles/base.css 304 2ms
GET /users/assets/images/icons/star.png 304 5ms

I tried with absolute path and relative path in front end mvc template (<img src="/assets/images/icons/star.png" alt="star">), it loads with users prefix no matter what.

I found a solution by tbranyen, but it did not quite work for me. I do not need to setup any cluster at all, what I want is my express server to serve any resource without any prefix when any dynamic segment is being matched. So I wrote this middleware, and it fires correct but still loads the static resource with users/ prefix.

// this route uses the ":user" named parameter
// which will cause the 'user' param callback to be triggered
router.get('/users/:user_id', function(req, res, next) {
  console.log('req.params: ', req.params.user_id );
  //console.log('@TODO: need to handle the params here');
  //next();
  return res.render('base');
});

Problem:

When using Express.js as a server, I want every browser request will be handled with response client/index.html, even with dynamic query segment. Currently, whenever url query involves with dynamic query segment /users/:user_id, the response from express server will prefix with users to all the static resources.

For example, when I load the url with dynamic segment localhost:3000/users/1. if i have a resources assets/images/icons/star.png in handlebars template, express server response back /users/assets/images/icons/star.png, but I do not have users folder with the assets. What I want response back /assets/images/icons/star.png.

I tried with absolute path /assets/images/icons/star.png or relative path assets/images/icons/star.png in the handlebars template, it always return with users prefix in the response.

Thanks for any help!

like image 351
MMA Avatar asked Jul 31 '14 14:07

MMA


1 Answers

In the <head> of your base template, add this toward the top:

<base href="/">
like image 165
idbehold Avatar answered Oct 22 '22 20:10

idbehold