Coder Social home page Coder Social logo

connect-history-api-fallback's Introduction

connect-history-api-fallback

Middleware to proxy requests through a specified index page, useful for Single Page Applications that utilise the HTML5 History API.

Table of Contents

Introduction

Single Page Applications (SPA) typically only utilise one index file that is accessible by web browsers: usually index.html. Navigation in the application is then commonly handled using JavaScript with the help of the HTML5 History API. This results in issues when the user hits the refresh button or is directly accessing a page other than the landing page, e.g. /help or /help/online as the web server bypasses the index file to locate the file at this location. As your application is a SPA, the web server will fail trying to retrieve the file and return a 404 - Not Found message to the user.

This tiny middleware addresses some of the issues. Specifically, it will change the requested location to the index you specify (default being /index.html) whenever there is a request which fulfills the following criteria:

  1. The request is a GET or HEAD request
  2. which accepts text/html,
  3. is not a direct file request, i.e. the requested path does not contain a . (DOT) character and
  4. does not match a pattern provided in options.rewrites (see options below)

Usage

The middleware is available through NPM and can easily be added.

npm install --save connect-history-api-fallback

Import the library

var history = require('connect-history-api-fallback');

Now you only need to add the middleware to your application like so

var connect = require('connect');

var app = connect()
  .use(history())
  .listen(3000);

Of course you can also use this piece of middleware with express:

var express = require('express');

var app = express();
app.use(history());

Options

You can optionally pass options to the library when obtaining the middleware

var middleware = history({});

index

Override the index (default /index.html). This is the request path that will be used when the middleware identifies that the request path needs to be rewritten.

This is not the path to a file on disk. Instead it is the HTTP request path. Downstream connect/express middleware is responsible to turn this rewritten HTTP request path into actual responses, e.g. by reading a file from disk.

history({
  index: '/default.html'
});

rewrites

Override the index when the request url matches a regex pattern. You can either rewrite to a static string or use a function to transform the incoming request.

The following will rewrite a request that matches the /\/soccer/ pattern to /soccer.html.

history({
  rewrites: [
    { from: /\/soccer/, to: '/soccer.html'}
  ]
});

Alternatively functions can be used to have more control over the rewrite process. For instance, the following listing shows how requests to /libs/jquery/jquery.1.12.0.min.js and the like can be routed to ./bower_components/libs/jquery/jquery.1.12.0.min.js. You can also make use of this if you have an API version in the URL path.

history({
  rewrites: [
    {
      from: /^\/libs\/.*$/,
      to: function(context) {
        return '/bower_components' + context.parsedUrl.pathname;
      }
    }
  ]
});

The function will always be called with a context object that has the following properties:

  • parsedUrl: Information about the URL as provided by the URL module's url.parse.
  • match: An Array of matched results as provided by String.match(...).
  • request: The HTTP request object.

verbose

This middleware does not log any information by default. If you wish to activate logging, then you can do so via the verbose option or by specifying a logger function.

history({
  verbose: true
});

Alternatively use your own logger

history({
  logger: console.log.bind(console)
});

htmlAcceptHeaders

Override the default Accepts: headers that are queried when matching HTML content requests (Default: ['text/html', '*/*']).

history({
  htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
})

disableDotRule

Disables the dot rule mentioned above:

[…] is not a direct file request, i.e. the requested path does not contain a . (DOT) character […]

history({
  disableDotRule: true
})

connect-history-api-fallback's People

Contributors

arikfr avatar awwit avatar bripkens avatar cgmartin avatar christian-fei avatar dependabot[bot] avatar grifotv avatar helfi92 avatar insanity54 avatar ntkme avatar vladshcherbin avatar wtgtybhertgeghgtwtg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

connect-history-api-fallback's Issues

Add an option to ignore a set of paths

I have a Singel Page App that issues JSON requests, and would like to handle it all from the same node server. It would be neat if an option similar to rewrites could be add so this module would just not touch these routes.

Is there an order in resolving rules ?

Hi,

I'm trying to get this to work with react dev server. I have my landing pages under the / path and I want everything to be rewritten to landing-pages.html except if a more specific rule follows. For example if i have a rule to rewrite /admin to admin.html, I want it to take precedence over the / rule.

Currently I manage to get one or another, but not both working at the same time.
Thanks !

Log showed it was redirected successfully, but actually it wasn't?

screen shot 2016-03-17 at 16 56 55 1

I'm using historyApiFallback with my express server which serves a React-App in the 'static' folder. And the express server only provides APIs for the React App.

I just enabled history api fallback

...
app.use(express.static(path.join(__dirname,'static')))
app.use(historyApiFallback({ verbose: true}))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(apiRoutes)
...

something like this.

It's normal if i request "http://localhost:port", the React-App is loaded, but it i request something else, the result is shown as the picture above.

how could it happen?

Redirection causes download for SHTML-files

If using middleware that performs serverside-parsing of the target file (say, index.shtml), the file in question will just be downloaded, instead of parsed and served as I would've expected and/or hoped.

A middleware setup like this for BrowserSync:

const browserSyncSSI = require('browsersync-ssi');
const historyFallback = require('connect-history-api-fallback');

browserSyncConfig.server.middleware = [
    browserSyncSSI({
        baseDir: basePath,
        ext: '.shtml',
        version: '1.4.0'
    })),
    historyFallback({ index: "/index.shtml" }))
];
// and so on and so forth...

... will just result in me getting the raw file instead of the parsed one, and by forced download at that. I do realize the trouble and potential loops-of-death of getting the script to basically ask the localhost for a "parsed" version instead of the raw file (if there aren't better methods?), but it would greatly enhance the usability of this module. I am using SHTML for HTML scaffolding when a content delivery service has yet to be established, and being able to redirect to a pre-parsed version of the code would be a lot better than having to maintain two files (a pre-compiled version for this module to digest, and the actual SHTML-file), or just doing everything in plain HTML instead.

So, consider this a "what do I do"-request. Is there a way of getting hold of the pre-parsed version, without compiling it myself in some way?

static/js notfound

app.use(express.static(path.resolve(__dirname, config.outputDir)));
app.use(express.static(path.resolve(__dirname, './../files')));
app.use(history({

}));

app.use(express.static(path.resolve(__dirname, config.outputDir)));
app.use(express.static(path.resolve(__dirname, './../files')));

when i set this. it found static/js/xxx.js not found
image

Rerouting insecure requests with express

This is less of a bug and more that I'm just trying to understand best practices with the package. Currently I'm using this with a fairly simple express server that serves up a Webpacked Vue SPA.

My server could be abstracted to look like this:

// Dependencies
var path = require('path')
var http = require('http')
var https = require('https')
var server = require('express').express()

// Attach middlware
server.use(history())

// Create servers and listen for requests
http.createServer(server).listen()
https.createServer(sslCert, server).listen()

// Redirect requests to https
server.use(function(req, res, next) {  
  if(req.secure || process.env.NODE_ENV == 'dev') {
    next()
  } else {
      res.redirect('https://' + req.headers.host + req.url);
    }
})  

// serve client directory
server.use(express.static(path.join(__dirname, '../client/dist')))

This works in every case other than one in which I enter http://[hostname] into the browser.
http://[hostname] is passed to the else statement in the Redirect requests to https block and the req.url is /index.html resulting in http://[hostname]/index.html

Currently I'm just hacking around this by checking if req.url == '/index.html' and, if so, redirecting to the https://[hostname] but it feels like that can't be the best solution. Is there an option somewhere I'm missing or a better approach to this generally? Everything is working as expected I just feel like I'm missing a piece of information.

Thanks for the package, generally! So easy to use and has saved me so much time <3

npm warning

When I install npm packages I'm now seeing the following warnings:

npm WARN unmet dependency [src dir]/node_modules/browser-sync/node_modules/browser-sync-ui requires connect-history-api-fallback@'0.0.5' but will load
npm WARN unmet dependency [src dir]/node_modules/connect-history-api-fallback

I'm assuming this is because of the work we did?

dont't fallback to index page if browser doesn't want html

It's unreasonable to serve html for non-html requests with status code 2xx. so connect-history-api-fallback shouldn't redirect to index page if browsers don't explicitly accept html, thus options.htmlAcceptHeaders should default to ["text/html"] from ["text/html","*/*"] since most dependents(at least those I 'm using) and developers don't set that option and most browsers' request header 'accept' contains "text/html"

Chrome:
	Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Safari:
	Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Firefox:
	Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Internet Explorer:
	Accept: text/html, application/xhtml+xml, image/jxr, */*

See also my history-api-fallback solution for Nginx React-router and nginx

error 404 when refreshing page

Hello, I have this error when I refresh page

localhost:9000 -> 404
localhost:9000/path1 -> 404
..etc

I set up my express js like this

app.js

     const history = require('connect-history-api-fallback');
     const connect = require('connect');

     app.use(history());

This is my router setup(vuejs)

   `import VueRouter from 'vue-router';

   import AddVue from '../components/code/addVue';
   import Code from '../components/code/Code';
   import Home from '../components/code/Home';
   import Google from '../components/code/Google';

  Vue.use(VueRouter);

  const NotFound = { template: '<div>Ariba Ariba Ariba Not Found</div>' }
  //const Google = { template: '<div> <h1>Google </h1></div>'}
  const routes = [
  {
      path: '/',
      name: 'Home',
      component: Home
  },
 {
     path: '/addVue',
     component: AddVue
     //beforeEnter: Auth.requireAuth
 },
 {
     path: '/puta/:name',
     component: Code
 },
 {
     path: '/google',
     component: Google
 },
 {
     path: '*',
     component: NotFound
 }
]
const router = new VueRouter({
  mode: 'history',
   routes
});

export default router`

Any idea to solve this?

URL with embedded URL - Issue with "://"

Hello,

I am trying to use this plugin with URLs that contain another URL to identify a particular object, such as:

http://localhost:4200/elements/edit/http://example.org/1, where "http://example.org/1" is an identifier of an object in my domain.

I am using this configuration:

historyApiFallback({
   verbose: true,
   rewrites: [
      {
         from: /^.*\/elements\/edit\/.*$/,
         to: function(context) {
            return '/#/';
         }
      }
    ]
});

When trying lo load the previous URL, the log shows the message “Rewriting GET /elements/edit/https://example.org/1/ to /#/”, which seems to be correct. However, it looks like the rewriting is not doing anything because the browser returns a white page with the “Cannot GET…” message.

I have realized that the problem is the “://” substring. If this substring is removed from the second URL (e.g., trying to get http://localhost:4200/edit/example.org/1) the behavior is correct.

Is there any way to solve this issue?

hisotryApiFallback rewrites don't work

Hi there, recently I met a problem with rewrites, following is my config:

historyApiFallback: {
      rewrites: [
        { from: /^\/$/, to: '/index' },
      ],
    },

I want to rewrite path / to another appointed path /index, and other path fallback to default index.html, but fails, and I try with curl , when I curl localhost:3031/ it returns the default index.html content, but curl localhost:3031/index it returns what I want.

Please let me how to fix it or is there a workaround way ?

connect-history-api-fallback doesn't work with gulp-connect developer server

I’m trying to use it with Gulp like this:
var gulp = require('gulp'),
connect = require('gulp-connect'),
historyApiFallback = require('connect-history-api-fallback');

gulp.task('server', function() {
connect.server({
root: 'app',
livereload: true,
middleware: function(connect, opt) {
return [ historyApiFallback ];
}
});
});

However, the server http://localhost:8080/ gives no response. No errors in the terminal, merely get timeout in browser.
When I remove middleware like bellow, everything is perfect:
gulp.task('server', function() {
connect.server({
root: 'app',
livereload: true
});
});

Option to rewrite only if original file not found

My 'Single Page Application' is actually split into a few smaller 'Single Page Application's. As such, I need to specify rewrite rules so that I can redirect to the appropriate index.html file. For example:

        historyApiFallback({
          rewrites: [
            { from: /\/app\/login/, to: '/app/login/index.html'},
            { from: /\/app\/membercenter/, to: '/app/membercenter/index.html'},
            { from: /\/app\/knowledgebase/, to: '/app/knowledgebase/index.html'}
          ]
        })

However, when I do this, it loads the 'index.html' file (whichever it may be) instead of loading files that actually exist at other sub paths. For example:

/app/login/app.js

Is there a way to make it only follow the rewrite rules if the original file is not found? An option, perhaps? Or, maybe specifying the rewrites as I have done above is the wrong approach and instead maybe there is a way to add multiple indexes? Something like:

index: {
  '/app/login': '/app/login/index.html',
  '/app/membercenter': '/app/membercenter/index.html',
  '/app/knowledgebase': '/app/knowledgebase/index.html'
}

Any suggestions?

Option to allow URLs that contain a dot (.) to be rewritten

Hi there,

I've got a use case that is a little different:

My view URLs may actually contain dots as part of the URL (because I pass quoted URLs as a path parameter). For this to work I'd need the following:

  • a config option that disables the rule "don't rewrite if route contains a dot"
  • the content of #22 to be merged

Would you be willing to consider this use case?

Cheers,

Jannik

Dynamic content in index.html

I am using transformer-proxy module to load and edit value in index.html on startup. I see that with index property we can override the default index.html and it accepts a file name. Is there a way to pass html content to index property?

Serving index.html from memory?

Hi, so I use webpack-dev-server, and I use a the html-webpack-plugin. As a result, the index.html is served from the cache memory along with the rest of the javscript files. How can I use your middleware to still handle hitting 'refresh' on http://locahost:8080/some/route?

Question: How to properly rewrite URLs?

Hi,

I'm using this library which works really well on my JavaScript single page application. I've got the code below to do my rewrites. As you can see, all I'm doing is removing the first part of the url path so my static assets get served appropriately from index.html. I must admit I feel embarrassed as it seems am repeating myself quite a lot. I think I'm missing a regular expression that can deal with that in a more elegant way. Another requirement that just came up is that I'll have the first part of the url as a dynamic string i.e. /john/edit or /mary/edit. Not sure how to do the rewrite in this case?

        {
            from: /^\/tags\/js\/.*$/,
            to: function (context) {
                return context.parsedUrl.pathname.replace('/tags', '');
            }
        },
        {
            from: /^\/tracks\/js\/.*$/,
            to: function (context) {
                return context.parsedUrl.pathname.replace('/tracks', '');
            }
        },
        {
            from: /^\/tags\/css\/.*$/,
            to: function (context) {
                return context.parsedUrl.pathname.replace('/tags', '');
            }
        },
        {
            from: /^\/tracks\/css\/.*$/,
            to: function (context) {
                return context.parsedUrl.pathname.replace('/tracks', '');
            }
        },

Cannot read property 'headers' of undefined - Koa

Here's a basic Koa index.js:

var koa = require('koa'),
    app = koa(),
    serve = require('koa-static'),
    favicon = require('koa-favicon'),
    gzip = require('koa-gzip'),
    historyApiFallback = require('connect-history-api-fallback');


app.use(gzip());
app.use(favicon(__dirname + '/client/app/img/favicon.ico'));
app.use(serve(__dirname + '/client'));
app.use(historyApiFallback());
//start server
var server = app.listen(5000, function() { 
    console.log('Koa is listening to http://localhost:5000'); 
});

But when I run the server I get this error:

...node_modules/connect-history-api-fallback/lib/index.js:13

var headers = req.headers;                                                    
                   ^                                                           
TypeError: Cannot read property 'headers' of undefined
at historyApiFallback (.../node_modules/connect-history-api-fallback/lib/index.js:13:20)

Normalize rewrites

I was wondering if we could normalize the rewrite to prefix a file with / when missing:

rewrites: [
  { from: /\/soccer/, to: 'soccer.html'}
]

would become:

rewrites: [
  { from: /\/soccer/, to: '/soccer.html'}
]

This would avoid issues like neutrinojs/neutrino#1274 (comment). Thank you.

How to handle multi level routes? e.g. /foo/bar - /foo/bar/baz etc

I've been trying to get my head around this but I couldn't find a way to do it, I'm using Vuejs for the client and I have a few routes /foo, /foo/bar, /foo/bar/baz the first route /foo works perfectly with this setup:

const express = require("express");
const app = express();
const history = require("connect-history-api-fallback");

app.use(history({ verbose: true }))
app.use(express.static("dist"));
app.listen(8080, "192.168.0.103");

this is the output from the console when you request localhost:8080/

Rewriting GET / to /index.html
Not rewriting GET /js/runtime.f7cf0276fe79edfd2f62.js because the path includes a dot (.) character.
Not rewriting GET /js/router.a0c4fca3337e1422cf49.js because the path includes a dot (.) character.
Not rewriting GET /js/vendor.387eab05f2364a6ef284.js because the path includes a dot (.) character.
Not rewriting GET /js/app.9bd5bbbb4614a89f1c6b.js because the path includes a dot (.) character.

those are the files from my build and untill now I have no problem with those files, so far so good. Now Vue has this thing where you have a catch-all route that renders a component if none of the routes match by doing this:

{
    path: "*",
    component: () => import(/* webpackChunkName: '404' */ "../components/404.vue")
}

so, for example if you type/go/refresh localhost:8080/fou the history middleware redirects back to / and when the scripts are loaded, Vue say, Hey! I don't know this path I'll render the 404 component instead, that's fine Vue will render the component. I don't actually know how Vue do this: store /fou route somewhere to be aware of after the server has sent the index.html.

The problem comes when I type/go/refresh for example localhost:8080/foo/bar whether or not these route exists in my Vue router I get a 404 only from the script you see above, it perfectly renders the index.html but none of these files and because the content of this particular route depends on those files I see nothing.

files1
files2console

It says: refused to execute script because its MIME type ('text/html') so I went and add to my config its MIME type to: htmlAcceptHeaders: ['text/javascript', 'application/javascript'] and now there is no errors in the console and I get this instead: Cannot GET /foo/bar not only this I cannot go to localhost:8080/foo either but I can go to localhost:8080/ just fine.

Then I tried:

app.use(
  history({ htmlAcceptHeaders: ["text/javascript", "application/javascript"] })
);
app.use(express.static("dist"));
app.use(
  history({
    verbose: true,
    rewrites: [
      {
        from: /^\/(.*)\/(.*)\/?$/i,
        to: context => {
          let path = context.parsedUrl.pathname.replace("/foo", "");
          return `./dist${path}`;
        }
      }
    ]
  })
);

and I get the same result. Does anybody knows how to properly get this middleware working? it is has to do with my webpack config? or I'm doing it wrong? I searched a lot on how to solve this from various sources and even different frameworks before I come here and I just cannot get it to work with express, I also post it in the Vue forum with no answer. I'll appreciate any help on this.

This is my distribution folder if helps
dist

Is there a way to get the original path?

I got the following code:

app.use(history());
app.get('/index.html', (req, res) => {
  ...
}

Is there any way to get the original path (before rewrite) inside the handler for /index.html path?

Typo in README.md

Small typo: npm install --save history-api-fallback should be npm install --save connect-history-api-fallback. You omitted connect- from the package name.

Exceptions for particular routes

How to not rewrite particular routes like /auth/google?
Is there a way to add own exclusion for some routes?

My temporary solution - use history only for specified routes, not for all app like app.use(history)

Doesn't work when a route is reloaded

I set up a simple express app to use connect-history-api-fallback. Here's my code:

const express = require('express');
const history = require('connect-history-api-fallback');
const PORT = process.env.PORT || 3000;
const path = require('path');
//Set my public folder to the dist folder
const public_dir  = path.resolve(__dirname, "dist");

const app = express();

app.use(express.static(public_dir));

app.use(history());

app.listen(PORT, () => console.log(`App started on port ${PORT}`))

I have a vue application which has a route - /about to display the about page.
When loaded initially in the browser, the routes work as expected but whenever I reload a route in my vue app, for example '/about', I get a Cannot GET /about which means a request was still sent to the server.

Please how can I solve this? Thank you.

URL with dots

Hello,

I'm using historyApiFallback as a middleware with browserSync to debug an Angular.js one page application.

Some of the URLs have dots in them /library/version-2.3.4, which is a criteria for historyApiFallback to not serve index.html.

Is there a way to get around this limitation?

Thanks.

Issue with last dot happening before last slash

Hello, I am affraid the commit 7af0bc7 has brought an unexpected issue. Let me explain:

I am doing a call to an API with an URL of the form:

/apis/core.py/endpoint

I am using a proxy to target this call to another server.
Before the changes from 7af0bc7 everything was working properly cause no rewrite was being applied to the url, and the proxy worked as expected.

Now, this type of url doesn't meet the following validation due to the last dot happening before the last slash:
pathname.lastIndexOf('.') > pathname.lastIndexOf('/')

After this addition, my call to the API fails.
If I revert the code to how it was everything works OK.

I think maybe there could be a better approach to this?
Cheers!

Fix dots in URL not being rewritten

I have a problem with some of my URL's containing a JWT. JWT's have a dot in them, and it's currently causing my URL's not to get rewritten.

The culprit are these lines https://github.com/bripkens/connect-history-api-fallback/blob/master/lib/index.js#L59-L67

I understand they are in there for filenames, but perhaps the check can be made a bit better, like test if the dot is in the last 5 characters of the url, and then assume it's a file. Or actually check if the file exists.

Url's like this should still get rewritten:

http://localhost:8080/email/verify/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjU2YTA1NjMwMjEyNTEzMDcxYzhkZjk5ZSIsImlhdCI6MTQ1NDAyNzU3NywiZXhwIjoxNDU0MjAwMzc3LCJhdWQiOiJodHRwOi8vYm9va2luZ3Byby5uei9hcHAiLCJpc3MiOiJodHRwOi8vYm9va2luZ3Byby5uei9hcGkifQ.VaTeu7ZxepyOiHI3DtFFw0iqzBY7lzVa22lfQKxRsHM

HEAD requests are not accepted

Hello,

Currently, it appears that this does not accept HEAD requests with the default configuration, which results in 404 errors for those requests.

Is there a way to allow this through configuration currently? If not, would it maybe be worthwhile to add support for HEAD requests as well since they're basically simplified GET requests for header info?

Hoping someone can point me in the right direction here.

Appreciate your time.

Middleware only redirecting one level deep

So, I expect I'm missing something here. I'm using the middleware with the default settings, in conjunction with gulp and browser-sync, to power an AngularJS app on my local machine. It works great for some routes but I can't seem to get it to work for routes more than 1 level deep.

For example: http://localhost/users will work, but http://localhost/users/1 redirects back to /users and I lose the 1.

I have the app running on another server where the app works properly, so I'm sure that my Angular routing is set up correctly and there's no redirection happening within the app.

Any suggestions as to where I might be going wrong here? Here's my gulp task if it helps. Most of the config is passed in but I don't think it would be affecting the middleware.

browserSync = require 'browser-sync'
history = require 'connect-history-api-fallback'

module.exports = (gulp, ui, config, $) ->
  ->
    browser = config["#{ ui.id }Browser"] = browserSync.create()

    browser.init
      server:
        baseDir: ui.paths.src.dir

      # Support Angular's HTML5 Mode.
      middleware: [ history() ]

      host: config.host
      port: ui.port
      notify: false
      ui: false

How can i redirect this req to my declare path?

Hello , I have some problem from useing this middleware.
there is my folder:

|-statics
   |-js
      |-vender.js
|-server
   |-router
   |-views
       |-index.html
|-server.js

there is my server.js:

const express = require('express');
const path = require('path');
const history = require('connect-history-api-fallback');
const proxy = require('express-http-proxy');

const env = process.env.NODE_ENV;
const isDeveloping = (process.env.NODE_ENV != 'production');

const port = isDeveloping ? 8000 : process.env.PORT;

const app = express();
app.use('/statics', express.static('statics'));
app.use(express.static('statics'));
app.all('/api/*', proxy('http://api.ilovelook.cn'));


// i think this middleware redirect req to get '/statics/' path .
// beasuse when i move 'index.html' into 'statics' , it work right
// so my answer is how to fix this problem?
app.use(history({
    index: './server/views/index.html',
    verbose: true
}));

app.listen(port, function onStart(err) {

    if (err) {
        console.log(err);
    }
    console.info(`Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`);
});

URL with ending slash.

I'm using connect-history-api-fallback with browserSync.

    browserSync.init({
        server: "./dist",
        middleware: [history({
            index: "/about.html",
            rewrites: [
                { from: /\/about/, to: "/about.html" },
                { from: /\/projects/, to: "/projects.html" }
            ]
        })]
    });

If I'm at http://localhost:3000/about, it will load about.html correctly. About is a folder, so I'm trying to change the regular expression to /\/about\//, but if a navigate to http://localhost:3000/about/, this time the page will not properly load.


I'm an idiot. Solved.

Fallback to closest index.html

Hi,
I'm developing a website containing multiple SPAs along some static files in single project. The directory structure is as follows:

/
|- /SPA1
|   |--- index.html
|
|- index.html
|- foobar.html

I want to serve all /foo/bar with index.html and /SPA1/foo/bar with SPA1/index.html. Is there any way to achieve this?

Application crashing after adding disableDotRule: true

After adding disableDotRule:true the entire application is crashing.
Console error: Uncaught SyntaxError: Unexpected token <
The application works without issues when disableDotRule is false or absent.

This is my dev-server.js

import express from 'express';
import morgan from 'morgan';
import history from 'connect-history-api-fallback';
import proxy from 'http-proxy-middleware';
import bodyParser from 'body-parser';

import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';

import webpackConfig from '../webpack.config';
import api from '../src/test/api/api';

const app = express();
app.use(morgan('dev'));

const compiler = webpack(webpackConfig);

app.use(history({
  index: '/index.html',
  disableDotRule: true,
}));
app.use(webpackDevMiddleware(compiler, {
  noInfo: true,
  publicPath: webpackConfig.output.publicPath,
  stats: {
    colors: true,
  },
}));

app.use(webpackHotMiddleware(compiler, {
  log: console.log, // eslint-disable-line no-console
}));

// set up proxy
try {
  const proxySettings = require('./proxySettings.default'); // eslint-disable-line global-require, import/no-unresolved
  Object.entries(proxySettings).forEach((entry) => {
    const [contextPath, proxyConfig] = entry;
    app.use(contextPath, proxy(Object.assign({}, proxyConfig, {
      onProxyRes: (proxyRes) => {
        const setCookie = proxyRes.headers['set-cookie'];
        if (setCookie) {
          // eslint-disable-next-line no-param-reassign
          proxyRes.headers['set-cookie'] = setCookie.map((cookie) => cookie.replace(/; Secure/, ''));
        }
      },
    })));
  });
} catch (e) {
  if (!e.message || e.message !== "Cannot find module './proxySettings'") {
    console.error(e); // eslint-disable-line no-console
  }
}

// set up mock api
app.use(bodyParser.json());
api.defineApi(app);

// start express server
const listener = app.listen(8181, () => {
  const address = listener.address();
  // eslint-disable-next-line no-console
  console.log(`Dev server listening on ${address.address}:${address.port}`);
});

Problem with static assets

I had to add this code to fix the static path of my website

app.use(history({
  rewrites: [
    {
      from: /^\/articles\/static.*$/,
      to(context) {
        const staticPathWithHistory = context.parsedUrl.pathname.replace('/articles', '');
        return `/${staticPathWithHistory}`;
      },
    },
  ],
}));

when I go on the page https://mywebsite.com/articles/:id

Dealing with trailing slashes

Hi,

connect-history-api-fallback seems to disable Express's ability to handle trailing slashes, which normally just get removed.

For example:

It seems like there must be some simple way around this, but I haven't been able to find one. Is there?

Thank you! A full snippet from my code is below, if that helps clarify things.

app.use(
  history({
    rewrites: [
      {from: /\/signup\//, to:'/signup'}
    ]
  }),
  express.static(path.join(dirname, 'some/directory'))
);

Serve different index.html for subdomain

Hey, I'm using webpack-dev-server with history api to serve pages. By default, it gives index.html and I want to make it work this way:

url -> given file

localhost:4000 -> index.html
admin.localhost:4000 -> admin.html

I was able to serve different page for different pathname, but can't make it work for a subdomain. Is it somehow possible?

Option to allow for dots in url

I have angular app that have urls like:

/app/apache/1.0.2/details

and when I refresh the browser I got error Cannot GET /app/apache/1.0.2/details because of this code:

    if (parsedUrl.pathname.indexOf('.') !== -1) {
      logger(
        'Not rewriting',
        req.method,
        req.url,
        'because the path includes a dot (.) character.'
      );
      return next();
    }

it would be nice if the library include an option to disable this behavior.

mistakenly rewriting non extension files as extensioned files

It seems that regardless of what I set disableDotRule to it disables the dot rule. By that I mean that if a route does not have an extension it still treats it like it's a file and does not route it to index.html as it should but instead attempts to route the file.

I'm sure I'm missing something small, please let me know what it is I'm missing.

This is my current setup

import path from 'path';
import history from 'connect-history-api-fallback';
import { static as expressStatic } from 'express';

const staticBaseRoute = '/public';
const staticFilePath= path.join(__dirname, '..', '/public/dist/');

app.use(
  history({
    verbose: true,
    index: path.join(staticBaseRoute, '/index.html'),
    disableDotRule: false,
    rewrites: [
      {
        from: /^\/(?!api\/).*/i,
        to(context) {
          const { pathname: pathName } = context.parsedUrl;

          const resultPath = path.join(staticBaseRoute, pathName);

          console.log(
            `HISTORY: routing from\n${pathName}\nto\n${resultPath}`,
          );
          return resultPath;
        },
      },
    ],
  }),
);

app.use(staticBaseRoute, expressStatic(staticFilePath));

expected behaviour

  • / -> /public/index.html -> ${__dirname}/../public/dist/index.html
  • /login -> /public/index.html -> ${__dirname}/../public/dist/index.html
  • /css/main.css -> /public/css/main.css -> ${__dirname}/../public/dist/css/main.css
  • /api/users/:id -> express route

actual behaviour

  • / -> /public/index.html -> ${__dirname}/../public/dist/index.html
  • 🚫 /login -> /public/index.html -> ${__dirname}/../public/dist/index.html
  • /css/main.css -> /public/css/main.css -> ${__dirname}/../public/dist/css/main.css
  • /api/users/:id -> express route

Let some path fall through for express / koa to handle?

I want my local server serving the static index.html file to also serve some api on a particular endpoint?

Let's say, on a '/api/search' I want my server to talk to a service to tell me the results?

Can 'rewrites` be only used to serve other static files or can it create a hole in the history fallback middleware so the defined routes can actually talk to servers?

Nested routes with / not working

If the nested route has / then it is not working when I request to the nested route directly.

But React-router works with /

I am not sure if this is a issue, please investigate.

Invalid URL after second slash

If I enter URL like this: localhost:3000 it serves me index.html which is ok
If I enter URL localhost:3000/admin it serves me admin page which is ok
If I enter URL localhost:3000/invalidpage it serves me index.html again which is also ok
But if I enter localhost:3000/admin/invalidpage it tryes to get the invalid page, which is not ok.

So how do I set it up so that it serves index.html even after I enter invalid page after second "slash", or third etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.