choojs / choo

:steam_locomotive::train: - sturdy 4kb frontend framework
https://choo.io/
MIT License
6.78k stars 595 forks source link

Usage with http-server #712

Open rook2pawn opened 3 years ago

rook2pawn commented 3 years ago

Expected behavior

from my package.json

"start": "http-server -o -c-1 -p 8080 --proxy http://localhost:8080/ ",

This indeed loads up the app properly at http://127.0.0.1:8080/ However

  function joinView(state, emit) {
    return html`<body>
      <div><h4>Join!</h4></div>
    </body>`;
  }
  function lobby(state, emit) {
    return html`<body>
      <div>
        <h4>Lobby</h4>
        <a href="/join">Join</a>
      </div>
    </body>`;
  }
  app.use(devtools());
  app.use((state) => {
    state.logger = false;
  });
  app.route("/join", joinView);
  app.route("/", lobby);
  app.mount("body");

If i click the link "Join" from within the app, the router properly pushStates to /join and renders the joinView but if I reload so that the browser tries to request /join... i run into a loop because I'm trying to force http-server to do a catchall and serve my index.html which just has a simple div.

<html>
  <head>
    <script src="bundle.js"></script>
  </head>
  <body></body>
</html>

What precisely should I do to handle navigating directly to /join? Without the proxy statement /join doesn't exist because its not really something available outside the SPA. @YerkoPalma

rook2pawn commented 3 years ago

Ah, https://stackoverflow.com/questions/39744309/node-http-server-to-respond-with-index-html-to-any-request

has a good discussion on this topic and the question mark is really important here and will solve it.

http-server --port 8080 -P http://localhost:8080?

Do you think its worth having a section devoted to running a SPA server with choo?

I also want to point out that I use something like in my package.json

"start": "http-server ./web -o -c-1 -p 8080 --proxy http://localhost:8080?"

And that if you do something like this, make sure you point your src or other local lookups to / first otherwise the proxy would load src="bundle.js" to the proxied path.

   <script src="/bundle.js"></script>

Also, it is common to have a BE resource that you want proxied and I want to share how I did this for comment or to help others.

const http = require("http"),
  httpProxy = require("http-proxy");

const proxy = httpProxy.createProxyServer();
const server = http.createServer(function (req, res) {
  if (req.url.indexOf("/api/") > -1)  {
    proxy.web(req, res, { target: "http://127.0.0.1:5150" });
  } else {
    proxy.web(req, res, { target: "http://localhost:8080" });
  }
});

server.listen(5050);

Now your proxy sits behind a router where all requests go into your http/s server on 5050 then requests either go to http-server or they are marked as back-end with /api/. When requests go to http-server, the catch-all redirect works for your SPA. The only thing you have to manage is the cookie path in your set headers if you use cookies in your Backend node server and you rewrite the url after the if statement to check for /api/

Now you have both SPA with catchall redirect and BE proxying logic with http-proxy. The author of http-server don't really have a clear focus on serving SPA needs so I think this method might be fill in some needed gaps.