So, I work on a SPA with Vue.js, which me and my team used vue-cli to create it. A few weeks back we decided to change it to Vite, since there’s so many benefits developing with Vite rather than with Webpack, and all the problems that we crossed until now were pretty much easy to solve.
But yesterday I crossed with the problem of not being able to reload (specifically) nested routes, as I get the error
GET http://localhost:5173/admin/src/main.js net::ERR_ABORTED 404 (Not Found), which is totally new, so I assume is a Vite-related problem.
Redirecting happens fine, e.g. if I type localhost:5173/admin I am redirected to localhost:5173/admin/home, but as soon as I reload the page, the error above is thrown, as if the server is looking for a admin directory on the root. This happens with every other page that is nested, and the error is not given for parent routes.
For example,
localhost:5173/dashboard will reload fine, but
localhost:5173/dashboard/profile will throw an error on reload (GET http://localhost:5173/dashboard/src/main.js net::ERR_ABORTED 404 (Not Found)).
I already tried some things, since reloading problems are not new with SPA, but nothing worked for me. I tried some different Server Configurations, but adding connect-history-api-fallback dependency to my node.js back-end didn’t solve it, since my back-end is mostly for APIs, and there’s no server-side rendering. I also tried a .htaccess file, not successful as well.
Here’s my .htaccess file:
<IfModule mod_negotiation.c>
Options -MultiViews
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
That’s it, I’m going to leave some sample code so it might help someone see what I couldn’t.
vite.config.js
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
const env = loadEnv(mode, process.cwd());
return {
plugins: [
vue(),
],
server: {
proxy: {
'^/api': {
changeOrigin: true,
target: `http://${env.VITE_IP_API}:${env.VITE_PORTA_API}`,
}
}
}
}
});
src/router/admin.js
// this code is imported on src/router/index.js and spread on the root array
export default [
{
path: '/admin', // works and redirects correctly
name: 'admin',
redirect: {
name: 'homeAdmin'
},
children: [
{
path: 'home', // doesn't work on reload
name: 'homeAdmin',
component: () => import('../views/admin/AdminHome.vue'),
},
],
beforeEnter: async (to) => {
// some api call
}
},
{
path: '/admin/login', // doesn't work on reload
name: 'loginAdmin',
component: () => import('../views/admin/AdminLogin.vue')
}
]
src/main.js
import './assets/styles/styles.scss';
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import axiosInstance from './lib/axios/axiosInstance.js';
import axios from 'axios';
axiosInstance.axios = axios.create({
baseURL: (import.meta.env.VITE_NODE_ENV === 'production')
? `https://${import.meta.env.VITE_IP_API}:${import.meta.env.VITE_PORTA_API}/api`
: `/api`,
withCredentials: true,
timeout: 50000,
});
const app = createApp(App);
app.use(router);
app.use(store);
app.config.globalProperties.$axios = axiosInstance.axios;
app.mount('#app');
Again, I think is worth repeating that I hadn’t had this problem with Webpack. Pages reloaded correctly on refresh.