Entering wrong URL or refreshing in React/Express app causes all pages to error until user returns to homepage - node.js

I have an Express.js app with a React front-end. Everything works until I enter a URL for a non-existing resource (or even add a ? to the end of an existing URL): I get a 500 "Internal server error", and then even navigating to a real URL afterward throws the same error. It will only go back to normal functioning after returning to the homepage (which makes me think the issue may be on the React side, with something I'm not understanding about single-page React apps).
The error I see on the back-end is: TypeError: path must be absolute or specify root to res.sendFile, which corresponds to this bit in my code (where I point Express to the React build files):
app.use(express.static('../client/build'));
app.get('/*', function(req, res) {
res.sendFile('../client/build/index.html');
});
What's the best way of handling (or ideally, preventing) this error? Note that it doesn't crash the app, it just requires revisiting the homepage to reset things.
EDIT
It results in the same error even if I just refresh a (working) page.

Related

Add an express use handler that changes the base route

I have a svelte/sveltekit app. It says you could just your app like so
import { handler } from './build/handler.js';
app.use(handler);
But I already have another app in this express server, eg
app.use(otherhandler)
So I was hoping there was a way to do this
app.use('/newapp', svelte)
And it works, but, my svelte app has an auto redirect to /login if you are not logged in. So then the express app immediately redirects to /login whereas I was hoping it would go to /newapp/login. Is there a way to do this?
When you have a different base, you probably should configure that via config.kit.paths.base which then can be imported from $apps/path and added to the various links and redirects (at the very least in the UI this will be necessary, as stated by the docs).

How to use routes in Shopify app built using Shopify CLI , React and Shopify App Bridge

I have a problem with using routes in my application, it is a template built using Shopify CLI, React and Shopify App Bridge guided by this documentation here.
Every route I trigger does get sent to the _app.js file within my project as I can log most of the output in the console, but I can't get it to actually include paths of subpages in my apps like https://{apphost}/custompage will not navigate to custompage but an error handler and the custompage gets included in the query. The route and pathname fields of the props return
{
...
router: "_error",
pathname: "_error ",
...
}
instead of
{
...
router: "custompage",
pathname: "custompage",
...
}
I expected the above to be the result but it isn't. But the custompage url does however appear in the asPath field like this asPath: "/custompage?hmac={hmac}&host={host}&shop={shop}" pretend everything in {} has actual information.
The query field gets the fields it needs as it does on a working page. So the main issue is just routing.
With this in mind I have concluded that maybe I have issues on my side and triggering the server side routes handler, but I do not know where to start redirecting to exact pages instead of the index page that came with the boilerplate code. And I looked on their documentation but they skip most parts that are required to actually explain handling routing with their boiletplate codes. I do not want to edit major functions because I am worried they might stop the whole app from working but I need to be able to handle routes on the app without getting the An unexpected error has occurred. error when trying to route to subpages. Even extensions to whitelisted urls within my app trigger that error, so I think I need help with adding routing to the app or server.
Can anyone help me figure out what I am missing?
I am still new to Shopify but I can say that working with Shopify is a nightmare.
I am not sure if this is the final solution but for now this works: make sure that all the files you are trying to route to have the same naming as your path.
If you are routing to https://{appURL}/subpath then your JS file should be subpath.js . I currently can only get it to work if the file is in the same folder as my _app.js. If I move the file from ./subpath to /dir/subpath then I need to change the extension to https://{appURL}/dir/subpath in my Shopify app settings. It seems to operate relative to the _app.js file's location so keep that in mind.
If you used the Shopify CLI and shopify node create to create your app then this could help with your routing 400 headache.

NodeJS/Express proper handle of React builds

I would like to know how to properly handle React builds in a Express app. One major issue that I'm having right now is that, when using a browser the React app is always prioritized over other endpoints, even though it is at the end of the express chain.
I add the React build as static folder like so:
app.use(express.static(path.join(__dirname, '/react'), {
etag: false
}));
Also tried to set etag to false so it wouldn't cache the app, but it still opens even when the server is down. I send the react build by using a wildcard GET request at the end of the express chain:
app.get('*', (req, res) => {
res.sendFile(path.join(global.appRoot, '/views/index.html'));
});
There are other endpoints before it, but non of them are accessed through the browser, it just skips to the React build. The endpoints are called fine if Postman is used.
If it still opens when the server is down you have most likely a service-worker installed that is caching URLs with the index.html.
On Chrome, go to Applications tab of the Chrome Dev Tools and check if there are any service workers registered for the domain name you are using.
If there is you can unregister and then try again :)
But make sure that you check your service-worker, because if it is set to intercept all network requests with the html it will happen again.

Unable to access ExpressJS route via href link

I'm not sure if this is a security feature or if I'm missing something obvious. I need to access one of my ExpressJS routes directly via a standard link on the page.
If I type the URL in to my browser location bar, I get the desired result. However, if I put that exact URL in a standard link on one of the pages on the site, the route never gets hit.
EDIT: Even if I pull this out of the router and add directly to app.js I get the same results. I'm simply trying to use Passport's Facebook authentication. The first route looks like this:
router.get('/login/facebook', function(req, res, next) {
passport.authenticate('facebook')(req, res, next);
});
I realize the req function wrapper is not needed, I was using it for debugging so I could see when the route gets called.
If I set a breakpoint there, it works fine if I just type the "/api/login/facebook" URL into my browser, but if I put the exact URL in a link on the page, the route never gets hit.
It turns out this was caused by Angular's routing mechanism intercepting the links. I found the solution here:
How to get Angular UI Router to respect "non-routed" URLs

ExpressJS incorrectly rewriting paths when navigating directories

I've run into a maddeningly inconsistent issue with Express in a Node application where I am not able to correctly navigate through the built-in directory rendering due to a URL rewrite. It's easier to explain with code:
var express = require('express');
var app = express.createServer();
app.use("/public", express.static("/web/content"));
app.use("/public", express.directory("/web/content"));
app.listen(8888);
Using the uber-simple express server above the contents of /web/content are displayed as a list of links when you navigate to localhost:8888/public. So, for example:
..
index.html
header.jpg
js (folder)
css (folder)
From there if I click on index.html or header.jpg they display correctly, but clicking on the either folder will navigate to (for example) localhost:8888/js, even though the link clearly leads to localhost:8888/public/js. Upon further inpection it's revealed that the request is sent out for the right path (/public/js), but the server returns a 301 - Moved Permanently response that then redirects the browser to /js, which proceeds to display an error page because the content cannot be found. (No, really?)
Attempts to request a specific file beneath these folders (ie: localhost:8888/public/js/main.js) works fine and does not have the same issue.
The maddening part is that it was doing this on my dev box for a while and then simply... stopped. Not sure why. When attempting to deploy, however, the production server started having the same issue even though I can no longer reproduce it in my dev environment. Does anyone know why Express seems so intent on rewriting my URLs to the wrong thing?
Turns out the answer was pretty simple, and I only missed it because of my browser cache. After digging through the Express (well, technically Connect) code and sprinkling it liberally with console.log(), I traced it down to some code in the static middleware that was detecting that the directory contained an index.html file and was attempting to display that instead. Somehow that code got the wrong path, and the invalid redirect happened.
The real problem, though, was that the static handler was acting before the directory middleware could, which is a direct result of the order in which the middleware was declared. As such simply flipping the middleware declaration like so:
app.use("/public", express.directory("/web/content"));
app.use("/public", express.static("/web/content"));
fixed the issue.
Now, I had actually tried this before but did not realize that the 301 that I was sent previously had been cached, and so the browser was redirecting me before even touching the server. After flipping the order AND emptying my cache, I was able to navigate thde directory structure correctly.
Sigh If I had a dollar for every "bug" I've encountered caused by browser cache...

Resources