New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yeoman Server and Backbone/BBB pushState #468

Closed
michael-cantera opened this Issue Sep 16, 2012 · 14 comments

Comments

Projects
None yet
8 participants
@michael-cantera

Backbone Boilerplate is set up to use pushState, so there are no hashes in the URLs. When Yeoman Server tries to live-reload a BBB app, it triggers a 404 because the hash-less path isn't recognized.

This is fixable with Apache via mod_rewrite, but Yeoman can't see the rewrite since it's doing its own thing server-wise.

Is there a way to configure Yeoman for something similar to a mod_rewrite, or better yet, to check Apache rewrite rules before doing a live reload?

(Or if someone knows a better way entirely rather than mod_rewrite, that would be great too.)

latentflip added a commit to latentflip/yeoman that referenced this issue Sep 16, 2012

@latentflip

This comment has been minimized.

Show comment
Hide comment
@latentflip

latentflip Sep 16, 2012

Contributor

Just hacked together a solution for this (see the referenced commit).

If you add a server.rewrite option to Gruntfile.js that contains mod_rewrite rules, they'll get run before anything else in the yeoman server.

server: {
  rewrite: [
    "^/posts$ / [L]",                                                               
    "^/posts/.*$ /"
  ]
}

The rules get applied in order, and it supports the [L] terminator.
I guess you could have this pulled in from a .htaccess file too if you wanted.

@michael-cantera if you want to try it, you can pull my branch into your yeoman git repo (if you've cloned it down and installed that way), or if you installed it via npm, I think you'd need to follow the instructions for using yeoman from git master here: https://github.com/yeoman/yeoman/wiki/Additional-FAQ

Contributor

latentflip commented Sep 16, 2012

Just hacked together a solution for this (see the referenced commit).

If you add a server.rewrite option to Gruntfile.js that contains mod_rewrite rules, they'll get run before anything else in the yeoman server.

server: {
  rewrite: [
    "^/posts$ / [L]",                                                               
    "^/posts/.*$ /"
  ]
}

The rules get applied in order, and it supports the [L] terminator.
I guess you could have this pulled in from a .htaccess file too if you wanted.

@michael-cantera if you want to try it, you can pull my branch into your yeoman git repo (if you've cloned it down and installed that way), or if you installed it via npm, I think you'd need to follow the instructions for using yeoman from git master here: https://github.com/yeoman/yeoman/wiki/Additional-FAQ

@addyosmani

This comment has been minimized.

Show comment
Hide comment
@addyosmani

addyosmani Sep 16, 2012

Member

I'm wondering whether we should be documenting this over including it in the gruntfile by default. Leaving open to consider further.

Member

addyosmani commented Sep 16, 2012

I'm wondering whether we should be documenting this over including it in the gruntfile by default. Leaving open to consider further.

@latentflip

This comment has been minimized.

Show comment
Hide comment
@latentflip

latentflip Sep 16, 2012

Contributor

@addyosmani my pull-request hasn't modified the default gruntfile, but just added the relevant code to deal with the rewrite config in yeoman's cli/tasks/server.js

Of course happy to consider where or how this change gets made, but I can see it tripping quite a few people up as a smooth first experience with using yeoman and single page apps.

Contributor

latentflip commented Sep 16, 2012

@addyosmani my pull-request hasn't modified the default gruntfile, but just added the relevant code to deal with the rewrite config in yeoman's cli/tasks/server.js

Of course happy to consider where or how this change gets made, but I can see it tripping quite a few people up as a smooth first experience with using yeoman and single page apps.

@addyosmani

This comment has been minimized.

Show comment
Hide comment
@addyosmani

addyosmani Sep 16, 2012

Member

cc @mklabs for thoughts on this being added to server.js.

Member

addyosmani commented Sep 16, 2012

cc @mklabs for thoughts on this being added to server.js.

@mklabs

This comment has been minimized.

Show comment
Hide comment
@mklabs

mklabs Sep 16, 2012

Contributor

mod rewrite functionality sounds great, and I like the API. 👍

Contributor

mklabs commented Sep 16, 2012

mod rewrite functionality sounds great, and I like the API. 👍

@addyosmani

This comment has been minimized.

Show comment
Hide comment
@addyosmani

addyosmani Sep 16, 2012

Member

@mklabs If you're happy with this landing, we can merge :)

Member

addyosmani commented Sep 16, 2012

@mklabs If you're happy with this landing, we can merge :)

@michael-cantera

This comment has been minimized.

Show comment
Hide comment
@michael-cantera

michael-cantera Sep 18, 2012

I can't seem to get Yeoman/Grunt to see the rewrite rule, even when using a regexp that's almost identical to the one @latentflip included in the docs:

server: {
    rewrite: [
        '^posts/(.*)$ / [L]',
        '^users/(.*)$ / [L]'
    ]
}

(Note this example from the docs is slightly different from the one in this thread. I've tried them both and several variations.)

I assumed I didn't have the regexp correct until I stripped it down to be essentially the same as the example:

server: {
    rewrite: [
        '^posts/(.*)$ / [L]',
        '^#posts/(.*)$ / [L]'
    ]
}

Not only is the hash not added, but the 404 error says Yeoman is still looking for /posts, indicating that the rewrite isn't registering at all.

Could it be that server.rewrite needs to be in a specific location within Gruntfile.js? I put it just before the watch configuration and have tried it elsewhere as well.

Just to confirm, I am working with @latentflip's modified version of /cli/tasks/server.js. And also confirming that everything is working fine with my build. For reference, here is the Apache rewrite I'm trying to transform:

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /#$1 [R,L,NE]

Any help is appreciated. Hoping it's not just a noob regexp problem. :)

I can't seem to get Yeoman/Grunt to see the rewrite rule, even when using a regexp that's almost identical to the one @latentflip included in the docs:

server: {
    rewrite: [
        '^posts/(.*)$ / [L]',
        '^users/(.*)$ / [L]'
    ]
}

(Note this example from the docs is slightly different from the one in this thread. I've tried them both and several variations.)

I assumed I didn't have the regexp correct until I stripped it down to be essentially the same as the example:

server: {
    rewrite: [
        '^posts/(.*)$ / [L]',
        '^#posts/(.*)$ / [L]'
    ]
}

Not only is the hash not added, but the 404 error says Yeoman is still looking for /posts, indicating that the rewrite isn't registering at all.

Could it be that server.rewrite needs to be in a specific location within Gruntfile.js? I put it just before the watch configuration and have tried it elsewhere as well.

Just to confirm, I am working with @latentflip's modified version of /cli/tasks/server.js. And also confirming that everything is working fine with my build. For reference, here is the Apache rewrite I'm trying to transform:

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ /#$1 [R,L,NE]

Any help is appreciated. Hoping it's not just a noob regexp problem. :)

@latentflip

This comment has been minimized.

Show comment
Hide comment
@latentflip

latentflip Sep 18, 2012

Contributor

Hi @michael-cantera. There seem to be a few issues:

Firstly, the example rule that is in the code comments in my fork is in fact wrong, and won't ever work, but the one I posted further up this thread should work. The omission is a leading slash before the url to match: ^/posts/(.*)$ not ^posts/(.*)$. Sorry about that, I'll get my comment fixed.

I am however a little confused as to what you want to do. If you are using pushState, why are you trying to redirect to urls with #'s in them?

Here's the use-case I was thinking you were looking for, is this not what you are after?


  • Say you have a blog app, using backbone and pushState
  • Your single page backbone app exists at http://mydomain.com/ as a single index.html file
  • If a user goes to the http://mydomain.com homepage, and clicks a blog post, they would get shown the blog post by backbone, and backbone would use pushState to update the url to http://mydomain.com/posts/1
  • The user then shares the link to the blog post with a friend.
  • Now the friend, who hasn't been on your site, clicks the http://mydomain.com/posts/1 link.
  • Since your app is a single page app, that only actually exists as an index.html file at http://mydomain.com/, the url they are trying to access (http://mydomain.com/posts/1) doesn't exist.
  • So you need a mod-rewrite rule that says "if a users requests any path that looks like /posts/:id serve up the index.html file anyway, but leave the url in the browser as is, because the backbone app in index.html will deal with routing the user to the correct blog post.
  • So in your .htaccess file you add something like RewriteRule ^/posts/(.+)$ / [L].

And since you want the same thing to work in development with yeoman you open this issue.


Is that what you are trying to do? Or am I missing something?

Cheers

Contributor

latentflip commented Sep 18, 2012

Hi @michael-cantera. There seem to be a few issues:

Firstly, the example rule that is in the code comments in my fork is in fact wrong, and won't ever work, but the one I posted further up this thread should work. The omission is a leading slash before the url to match: ^/posts/(.*)$ not ^posts/(.*)$. Sorry about that, I'll get my comment fixed.

I am however a little confused as to what you want to do. If you are using pushState, why are you trying to redirect to urls with #'s in them?

Here's the use-case I was thinking you were looking for, is this not what you are after?


  • Say you have a blog app, using backbone and pushState
  • Your single page backbone app exists at http://mydomain.com/ as a single index.html file
  • If a user goes to the http://mydomain.com homepage, and clicks a blog post, they would get shown the blog post by backbone, and backbone would use pushState to update the url to http://mydomain.com/posts/1
  • The user then shares the link to the blog post with a friend.
  • Now the friend, who hasn't been on your site, clicks the http://mydomain.com/posts/1 link.
  • Since your app is a single page app, that only actually exists as an index.html file at http://mydomain.com/, the url they are trying to access (http://mydomain.com/posts/1) doesn't exist.
  • So you need a mod-rewrite rule that says "if a users requests any path that looks like /posts/:id serve up the index.html file anyway, but leave the url in the browser as is, because the backbone app in index.html will deal with routing the user to the correct blog post.
  • So in your .htaccess file you add something like RewriteRule ^/posts/(.+)$ / [L].

And since you want the same thing to work in development with yeoman you open this issue.


Is that what you are trying to do? Or am I missing something?

Cheers

@fitzchak

This comment has been minimized.

Show comment
Hide comment
@fitzchak

fitzchak Oct 3, 2012

The following doesn't work for me:

rewrite: [
'^/(.+)$ / [L]',
'^/(.+)$ /'
]

I want the server to return index.html for any URL.

fitzchak commented Oct 3, 2012

The following doesn't work for me:

rewrite: [
'^/(.+)$ / [L]',
'^/(.+)$ /'
]

I want the server to return index.html for any URL.

@simplyzaki

This comment has been minimized.

Show comment
Hide comment
@simplyzaki

simplyzaki Oct 9, 2012

@latentflip I am using your version of server.js along with yeoman bbb project type. The rewrite rule seems to work but the index.html doesn't get served. Instead I get "404 Error: / Not Found". Any way to get this work ?

@latentflip I am using your version of server.js along with yeoman bbb project type. The rewrite rule seems to work but the index.html doesn't get served. Instead I get "404 Error: / Not Found". Any way to get this work ?

@fitzchak

This comment has been minimized.

Show comment
Hide comment
@fitzchak

fitzchak Nov 6, 2012

What is the status of this?
I want to use this, can it be merged?

fitzchak commented Nov 6, 2012

What is the status of this?
I want to use this, can it be merged?

@latentflip

This comment has been minimized.

Show comment
Hide comment
@latentflip

latentflip Nov 6, 2012

Contributor

@fitzchak It's gone a bit stale to be honest, the main unresolved questions are in this comment: #469 (comment)

Contributor

latentflip commented Nov 6, 2012

@fitzchak It's gone a bit stale to be honest, the main unresolved questions are in this comment: #469 (comment)

@spacenick

This comment has been minimized.

Show comment
Hide comment
@spacenick

spacenick Dec 10, 2012

I would love that awsell! Nothing new atm ?

I would love that awsell! Nothing new atm ?

@sindresorhus

This comment has been minimized.

Show comment
Hide comment
@sindresorhus

sindresorhus Jan 31, 2013

Member

The BBB generator is on hold until this is resolved and we find a maintainer: backbone-boilerplate/grunt-bbb#89 (comment)

Member

sindresorhus commented Jan 31, 2013

The BBB generator is on hold until this is resolved and we find a maintainer: backbone-boilerplate/grunt-bbb#89 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment