Express: Multiple static paths to support multiple react apps in one single server

Created on 30 May 2020  路  6Comments  路  Source: expressjs/express

Express 4.17.1.
I have a simple express server with two built(compressed) React applications. Folder structure as below.

  • clients

    • ops_ui



      • static


        index.html



    • wf_ui



      • static


        index.html



  • server
    index.ts

The short code in server's index.ts:

export const app: Express = express();

const app_build: string = '../clients/ops_ui';
const wf_build: string = '../clients/wf_ui';

app.use(express.static(app_build));
app.use(express.static(wf_build));

app.get('/wf', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: wf_build });
});
app.get('*', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: app_build });
});

The wf_ui app is single route, but ops_ui is using react router, so it can have /home or /orders routes.

This code does not work. Mozilla and Chrome behave differently.

In Mozilla accessing localhost:8097/wf gives proper wf_ui but on the second refresh gives ops_ui. After another refresh it returns wf_ui again and then everything repeats all over again.

In Chrome localhost:8097/wf always give wf_ui app but going back to localhost:8097 still gives wf_ui app. Refreshing just localhost:8097 results in returning wf_ui for some reason. Only doing Hard reset in Chrome will give me ops_ui.

Can anybody explain me, what I'm doing wrong in this setup? How to properly code such situation when I have two independent React compressed application in two separate folders and I want to access WF_UI only if I specify /wf and i want to access OPS_UI when i request any other route(*)

question

All 6 comments

You should probably try using path prefix while using express.static

export const app: Express = express();

const app_build: string = '../clients/ops_ui';
const wf_build: string = '../clients/wf_ui';

// Handle inner paths first
app.use('/wf/*', express.static(wf_build));

// Hand root at last
app.use('/*', express.static(app_build));

// Handle 404 and other paths down here
app.get('*', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: app_build });
});

You should probably try using path prefix while using express.static

export const app: Express = express();

const app_build: string = '../clients/ops_ui';
const wf_build: string = '../clients/wf_ui';

// Handle inner paths first
app.use('/wf/*', express.static(wf_build));

// Hand root at last
app.use('/*', express.static(app_build));

// Handle 404 and other paths down here
app.get('*', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: app_build });
});

Thanks, now there is no strange behaviour with refreshing each route but all static files like css, js, etc return me index.html page contents...So i'm back to this error I've had before:

Uncaught SyntaxError: Unexpected token '<'

Well that depends where the static files located and the URL being called relative to the paths.

If your paths are not right then you will end up with getting the index file for every 404. The example provided is a simple on, but for (any) SPA requirement you should handle all known paths (where resources are available) manually by specifying each of them (or use patterns). And at last you should fall back to 404's.

Assuming most of your codebase is static files, the point where you handle app.get('*', ...) should be the place where your should return a 404 page, not the index.

If this doesn't fix your issue or you need more debugging help, follow up at https://gitter.im/expressjs/express

Thanks @r0mflip . I think your idea helped. So after playing around with the routes I came up with code below:

const build: string = "../clients";
const ops_ui: string = build + '/ops_ui';
const wf_ui: string = build + '/wf_ui';

// WF_UI
app.use('/wf/', express.static(wf_ui));
app.use('/static/js', express.static(build + "/static/js"));
app.use('/static/css', express.static(build + "/static/css"));
app.use('/static/media', express.static(build + "/static/media"));
app.use('/splash.png', express.static(build + "/splash.png"));
app.use('/logo.svg', express.static(wf_ui + "/logo.svg"));
app.use('/manifest.json', express.static(wf_ui + "/manifest.json"));

// OPs_UI
app.use('/loading2.gif', express.static(ops_ui + "/loading2.gif"));
app.use('/loading_small.gif', express.static(ops_ui + "/loading_small.gif"));
app.get('/', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: ops_ui });
});
app.get('/home', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: ops_ui });
});
app.get('/orders', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: ops_ui });
});
app.get('/manualTasks', (req: Request, res: Response) => {
  res.sendFile('index.html', { root: ops_ui });
});

The only extra difficulty it adds during deployment is that I had move all static files from both UIs into one common static folder, luckily all css and js files had random hash in their file names. If previously my folder structure was:

  • clients

    • ops_ui



      • static


        index.html



    • wf_ui



      • static


        index.html



Then now it's:

  • clients

    • static

    • css

    • js

    • media

    • ops_ui

      index.html

    • wf_ui

      index.html

My only question is: is that correct approach or too sloppy?

Well, simply put untill your hierarchy isn't unnecessarily deep and no resources have _duplicates_ of it, you should be just fine.

There's no _correct_ way to do _anything_. Refactor based on whats efficient for your work flow.

My only other suggestion would be to use a Router to map out your static asset paths. Would be a neat refactor.

thanks @r0mflip

Was this page helpful?
0 / 5 - 0 ratings

Related issues

despairblue picture despairblue  路  3Comments

ER-GAIBI picture ER-GAIBI  路  3Comments

nove1398 picture nove1398  路  3Comments

ZeddYu picture ZeddYu  路  3Comments

HafidAbnaou picture HafidAbnaou  路  3Comments