Client & Backend deployed separately - 404 error page on refresh despite proxy configuration - express

My project has a frontend and a backend deployed separately from 2 separate Github repos on "render.com".
It also has a Mongoose database for user credentials. But it is not the subject of this question.
All was working fine until I refreshed any page, I got 404 Not Found despite the configured proxy.
For instance, I redirect all my client-side links to "/" so that the user does not get the 404 Not Found page. At least it is more user friendly.
Here are some more details:
Frontend is a Vite react client:
Client Repo: https://github.com/Catevika/catevika_shoplineart-client
Render static site: https://shoplineart-afbr.onrender.com
Backend is an Express server:
Server Repo: https://github.com/Catevika/catevika_shoplineart-server
Render web service: https://shoplineart-api.onrender.com
Routes are managed client-side with react-router V6 but an authRoute for Login / Register.
File structure:
root
.. client
.. dist --> build folder with assets: pictures - ok in Render
.. src
.... api --> for Login
.... (...)
.. vite.config.js --> with proxy - ok in Render thanks to a Vite base URL variable
.. index.html --> outside "public" - specific to Vite
.. main.jsx
.. .env --> ok in Render
.. package.json
.. server
.. (...)
.. index.js
.. .env --> ok in Render
.. package.json --> type: "module" to use the "import" instead of "require"
vite.config.js:
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'https://shoplineart-api.onrender.com',
changeOrigin: true
}
}
},
plugins: [react()]
});
Express index.js:
import express from 'express';
import mongoose from 'mongoose';
import helmet from 'helmet';
import morgan from 'morgan';
import dotenv from 'dotenv';
import cors from 'cors';
import path from 'path';
import authRoute from './routes/authRoute.js';
dotenv.config();
const app = express();
app.use(cors());
mongoose.set('strictQuery', false);
mongoose.connect(process.env.MONGO_URI);
console.log('\x1b[33m', 'MongoDB connected successfully');
app.use(express.json());
app.use(helmet());
app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }));
app.use(morgan('common'));
app.use('/', authRoute);
app.listen(process.env.EXPRESS_PORT, () =>
console.log('\x1b[33m', `Server running on port ${process.env.EXPRESS_PORT}`)
);
if (process.env.NODE_ENV === 'production') {
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, '../client', 'dist', 'index.html'))
);
}
I tried adding secure: false in vite.config.js.
It failed.
What am I missing?
Thanks a lot for your precious help. I am stuck...

Related

swagger express ui strips the prefix and redirects to host

I am not able to load swagger for my nestJS application which is deployed on EKS.
Here is my main.ts
import {NestFactory} from '#nestjs/core';
import {NestExpressApplication} from '#nestjs/platform-express';
import {DocumentBuilder, SwaggerModule} from '#nestjs/swagger';
const swaggerUi = require('swagger-ui-express')
import {AppModule} from './app.module';
import {json, NextFunction, Request, Response} from 'express';
(async () => {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
const options = new DocumentBuilder()
.setTitle('Test')
.build();
const document = SwaggerModule.createDocument(app, options,{ ignoreGlobalPrefix: true
app.use("*/docs",swaggerUi.serve,swaggerUi.setup(document));
// Or
SwaggerModule.setup(`/docs`, app, document);
await app.listen(port, () => {
console.log(`Test service is running on port ${port}...`);
});
})
();
On my local machine the swagger doc loads correctly but when I deploy it to a development environment, it fails
dev url "https://dev-test-api.com/testservice/v1/docs/", it strips the /testservice/v1/ and redirects to "https://dev-test-api.com/docs/ and gives a 404.
I have tried couple of solutions mentioned in https://github.com/scottie1984/swagger-ui-express/issues/183
The forward-prefix option and the redirect too. None seem to work
Another problem I have is that the prefix "testservice/v1" changes as per different sandbox environments and since it is not an environment variable I don't have a way to set the path for swagger file before app is loaded.

Handling endpoints APIs on client side instead of serverMiddleware in Nuxt

I'm on Nuxt 2.15.8 and trying to build an offline app with electron.js and prisma+sqlite for local DB.
In nuxt to hit a local endpoint there is a common way of using serverMiddleware and express like this:
// api.js that will be added to nuxt.config.js file as serverMiddleware
import express from 'express'
const app = express()
app.use(express.json())
export default {
path: '/api',
handler: app
}
which send endpoints beginning with api/ through app handler which I can use to access my BD (the common way to access sqlite3 DB is the same)
// added to api.js
import { PrismaClient } from '../../resources/prisma/client'
const prisma = new PrismaClient()
app.get(`/user/info`, async (req, res) => {
const result = await prisma.user.findUnique({
where: {
id: 1,
},
})
console.console.log(res);
res.json(result)
})
this will work fine on nuxt, also fine on nuxt-electron dev mode. but on built exe file serverMiddleware won't be called. So as it has be done by others (nuxt-electron accessing offline local DB) there must be a way to define endpoints on client side. any idea??
Updated:
as I changed my Nuxt-Electron boilerplate I could access serverMiddleware in exe file but it wont hit the endpoints yet!

Nuxt privateRuntimeConfig access inside Plugin

Nuxt in 2.13 released runtimeConfig and tells us to migrate from dotenv in this article
I created a .env file where i wrote my variables and made sure that is ignored in my .gitignore file.
In nuxt.config.js I added the fallowing
privateRuntimeConfig: {
apiKey: process.env.apiKey,
}
Like this I have access to my apiKey in nuxt.config.js and it works nice. However I use a plugin for google maps where I need to put my apiKey in my plugin js file I created. I'm trying something like this but I cant access to my .env variables.
import Vue from 'vue'
import x5GMaps from 'x5-gmaps'
export default ({ app }) => { Vue.use(x5GMaps, app.context.$config.apiKey) }
Try this:
export default ({ app }) => { Vue.use(x5GMaps, app.$config.apiKey) }
But it just work with publicteRuntimeConfig

Serve * with express-static-gzip

I am trying to serve all routes to express with my dist folder.
app.use(expressStaticGzip('dist'));
app.get('*', (req,res) => {
res.sendFile(expressStaticGzip(path.join(`${__dirname}/dist/index.html`)));
});
When I run this code I got the error:
Internal Server Error
If I use route by route it works:
app.use('/', expressStaticGzip('dist'));
But I need the all routes.
I found the solution:
I switched expressStaticGzip to compression and used express-history-api-fallback:
import fallback from 'express-history-api-fallback';
import express from 'express';
import compression from 'compression';
...
app.use(compression());
const root = `${__dirname}/dist`
app.use(express.static(root));
app.use(fallback('index.html', { root })) ;
And I changed my relative imports at index.html for absolute imports ('./' to '/')

Route after authentication in Ember

According to the docs, I should put routeAfterAuthentication in my config/environment.js file.
My environment.js contains the following:
module.exports = function(environment) {
var ENV = {
modulePrefix: 'client',
environment: environment,
baseURL: '',
locationType: 'auto',
routeAfterAuthentication: 'dashboard',
...
However, it's still not getting redirected to the dashboard route and showing that the index route is not defined.
Am I missing something here?
You will need to include ember-simple-auth key like this
var ENV = {
};
...
ENV['ember-simple-auth'] = {
authenticationRoute: 'sign-in',
routeAfterAuthentication: 'YOUR ROUTE GOES HERE'
}
...
You can also define them by environment inside if (environment === 'development'), but for all environments you can put them after var ENV declaration. It is also important to import application route mixin so that redirect works (app / routes / application.js)
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default Ember.Route.extend(ApplicationRouteMixin, {});