-
Notifications
You must be signed in to change notification settings - Fork 752
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
Allow serving one file for all urls (single page app mode) #204
Comments
👍 |
2 similar comments
+1 |
+1 |
Using a middleware I manage to solve this problem. This is the example that I'm using (specific for my case): var fs = require("fs"),
path = require("path"),
url = require("url"),
gulp = require("gulp"),
browserSync = require("browser-sync");
// The default file if the file/path is not found
var defaultFile = "index.html"
// I had to resolve to the previous folder, because this task lives inside a ./tasks folder
// If that's not your case, just use `__dirname`
var folder = path.resolve(__dirname, "../");
gulp.task("server", function() {
browserSync({
files: ["./css/*.css", "./js/*.js", "./index.html"],
server: {
baseDir: "./",
middleware: function(req, res, next) {
var fileName = url.parse(req.url);
fileName = fileName.href.split(fileName.search).join("");
var fileExists = fs.existsSync(folder + fileName);
if (!fileExists && fileName.indexOf("browser-sync-client") < 0) {
req.url = "/" + defaultFile;
}
return next();
}
}
});
}); |
Or if you are using coffee files: fs = require("fs")
path = require("path")
url = require("url")
gulp = require("gulp")
browserSync = require("browser-sync")
# The default file if the file/path is not found
defaultFile = "index.html"
# I had to resolve to the previous folder, because this task lives inside a ./tasks folder
# If that's not your case, just use `__dirname`
folder = path.resolve(__dirname, "../")
gulp.task "server", ->
browserSync
files: ["./css/*.css", "./js/*.js", "./index.html"]
server:
baseDir: "./"
middleware: (req, res, next) ->
fileName = url.parse(req.url)
fileName = fileName.href.split(fileName.search).join("")
fileExists = fs.existsSync(folder + fileName)
if not fileExists and fileName.indexOf("browser-sync-client") < 0
req.url = "/#{defaultFile}"
next() |
@lucasmotta thanks for the snippet! A little modification to suit my needs + it works great +1 for native support in browser sync |
Thanks @lucasmotta you solution works well for me too. |
@lucasmotta thanks and high-five! ✋ |
I'm a little bit reluctant to add things to core unless they are used by 70/80%+ of use-cases... @lucasmotta - perhaps you could publish your middleware as a tiny package on NPM - then I can add some documentation advising people to use it... |
I didn't know if this is better to natively manage this case or distribute an NPM package. But this is a must have feature. @lucasmotta Thank for the middleware 👍 @shakyShane I'm not so sure that so few people will be interested by this. This is not an isolated use case. |
+1 |
@lucasmotta thanks you a lot! |
@lucasmotta That did it for me too thanks! |
+1 |
Would be great to just have an option on the server. Something like: server: {
{
always: "index.html"
}
} |
ok, this is getting some momentum now. I've not needed this myself, so forgive my ignorance - but are we literally just talking about that middleware that @lucasmotta posted above? and would |
The need for this comes from Single Page Application: routing is done on the client side. So you always deliver index.html and a javascript framework (AngularJS or EmberJS for example) handles the routing. |
@lucasmotta example works great. Another option could be |
👍 for |
(Obviously images, js/css files and other static content still need to be served up normally.) |
You need to configure some static path to allow serve image/css... |
The script actually looks for files before serving |
so do we have the |
Tried using connect-modrewrite as a middleware? |
+1 @marcgibbons |
👍 up for this I have a repo of tasks that I require on my projects when I need them. If I have to use the middleware with this I have to resolve potentially complicate paths, which I don't want really want to :/ Also this is a pretty important feature for SPA imho |
The connect-history-api-fallback package also seems to work: historyApiFallback = require('connect-history-api-fallback')
server: {
baseDir: "...",
middleware: [ historyApiFallback() ]
} |
Does anyone know if if there is a CLI equivalent to I'm thinking something along the lines of: |
@lukejacksonn just create a file called var browserSync = require("browser-sync").create();
browserSync.init({
files: ["app/css/*.css"],
server: {
baseDir: "app",
middleware: [ historyApiFallback() ]
}
}); then in your npm script, just do |
@shakyShane that worked, thanks. It would be awesome to see this built in and exposed through the CLI. I'm going to fork and have a play around this weekend! |
@thunderkid I had the same problem as you ("worked only for urls that are one level deep") and solved it by adding I discovered this solution on https://www.bountysource.com/issues/22575141-404-not-found-if-hashbang-false |
@lukejacksonn +1 |
Yeah... I am failing to understand that as well. I, personally, am partial to |
You could use connect-modrewrite to solve this.
|
I have been experiencing the same error as @thunderkid, with It actually works okay if I navigate to the links using the application's For example:
@jgatjens Do you have a different configuration that the one stated above? |
I'm having the same as @thunderkid and @jesusoterogomez and unfortunately i cant use the |
@antonsamper Probably related: angular/angular.js#8934 |
@Sukram21 yes definitely related, i came across that a few days ago. It's a shame the the polyfill doesnt work on Chrome |
@thunderkid |
@danukhan I remember it was working for all the levels with |
@jgatjens The issue was that the resource urls (js and css) weren't correctly setup. The following post led me to the answer: http://stackoverflow.com/questions/10865480/mod-rewrite-to-index-html-breaks-relative-paths-for-deep-urls Basically rather than having my resources as src="res/abc.js", I needed a leading slash like this: src="/res/abc.js" |
@jgatjens I'm facing same issue as originally mentioned here while deploying my app in tomcat. i.e., When I type localhost:8080/myapp/page1, I get 404 message. I would like to redirect it to localhost:8080/myapp/index.html as the solution for browserSynch. Do you know how can I do this for tomcat? |
@danukhan you probably want to use http://tuckey.org/urlrewrite/. In my case, I used the htaccess redirects in prod. |
@lucasmotta come here dude, you need a "wottle of bine". Thanks |
Did you add a option for this yet? I don't feel like installing an entire module to achieve this, any suggestion? |
Hi, I have used gulp to build my client angularJS application. After i deployed into IIS i'm getting an issue. My page is working fine when navigate through menu's. But when i refresh by page (or) copy and paste the URL its giving me 404 error. |
@velkumars you problably are with html5 mode enabled, so you need configure your server to redirect all requests to your index.html look here, has IIS configuration other option, if you cant configure the server, is disable html5 mode, and use a hash in paths, but is a old way :D |
@darlanmendonca, thank you. i did the same way |
@lucasmotta - this was work like charm in my case..great thank you.. ` var defaultFile = "index.html"; // I had to resolve to the previous folder, because this task lives inside a ./tasks folder
});` |
I discovered that the suggested middleware script has an issue when the url path contains Here is an improved version that worked better for me: function(req, res, next) {
var fileName = url.parse(req.url).pathname;
var fileExists = fs.existsSync(folder + fileName);
if (!fileExists && fileName.indexOf("browser-sync-client") < 0) {
req.url = "/" + defaultFile;
}
return next();
} |
I applied @lucasmotta 's solution and I could solve my case, but I'm facing another issue with "routes" option:
I would like to inject all bower_components into index file to check some configurations in bower.json file for debug instead of merging them into a vendor.js file same as gulp build, and I don't want to store bower_components in app folder, so that, I would like to route bower_components to BrowserSync. but I don't why I can not load the bower file with routes option when I use lucasmotta's middleware. |
Hello, I'm facing a problem when implementing either @lucasmotta or @Mobe91 solutions using React Router and Webpack for deeper routes. Specifically for a route like this: When the browser is refreshed in that route (for code changes or manual refresh) I get the following console errors:
The browser is actually finding the files, but the issue is that those files are actually the I can actually go to every route in the app, regardless of the url (for example there's no issue when I use a Using the history api fallback doesn't work neither, in fact it doesn't even get the right url. This is an example of how the request looks on reload: I'll try with some regular expression to try to get rid of everything that comes before But if someone has some more generic solution (mine would work only for my specific case) it'd be great!!. |
Hello again, I found a solution but just for my particular case, but it shouldn't be too hard for everyone to create their own though. Just some regular expressions and it works. In my specific case I have my compiled files in the var folder = path.resolve(__dirname, "./build"); Then, since the issue happens when reloading in a subfolder I created some code to check for more than one forward slash and to see if the request is a file with middleware: function (req, res, next) {
var fileName = url.parse(req.url).pathname;
var fileExists = fs.existsSync( folder + fileName );
// test the file name for a .ico file
var faviconTest = fileName.match( /\/favicon\.ico/g );
// test the file name for sub-folders
var subfolderTest = fileName.match( /\//g ).length > 1;
// test to check if the requested url is a file or not
var isCssJsFile = fileName.match(/\/css|\/js/g);
if ( !fileExists && fileName.indexOf("browser-sync-client") < 0 && !faviconTest ) {
// if the we're in a subfolder and the request is a file (JS|CSS)
// create a new filename without anything previous to the file folder
if ( subfolderTest && isCssJsFile ) {
// create a new file name using the file type
var newNameRegEx = new RegExp( isCssJsFile[0] + "(.+)", "g" );
// request the new filename
var newFileName = fileName.match( newNameRegEx )[0];
req.url = newFileName;
} else {
// we're requesting the base folder so we need the regular index file
req.url = "/" + defaultFile;
}
}
return next();
} The code just checks if the folders are there. If you have a different folder structure the code should adapt to that. Is working fine so far on windows. Finally keep in mind that if you're requesting other files, those folder should also be included. An image's source included directly in the Best, |
I've tried Rodrigo's solution with tricking req.url. Even though browser shows no problem, js/css/image files come empty. This is my implementation. Project file structure:
Browsersync init:
|
Hi,
as many developers nowadays use Backbone, AngularJS etc. to build single page applications that consist of e.g. a /index.html page + pushstate routing, it would be great to have an option to make browser-sync serve one file. ("404/catchall/fallback" page you might also call it).
Maybe an option called {cachall: "/filename.html"} ?
The text was updated successfully, but these errors were encountered: