Error to deploy my Vue3 app to Github Pages - vue.js

I have uploaded my project with Vue3 to Github pages (check my repository), the branch is assigned to gh-pages and I have also uploaded the /dist folder, generated with the:
npm run build command.
I also modified the vue.config.js file with this data from my repository:
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
publicPath: process.env.NODE_ENV === "production" ? "/pokevue/" : "/"
})
I have two questions:
The first is why isn't Vue working/loading in my web, if I followed the instructions in this guide correctly.
The second one is why this route does not show the "home" (it is broken, of course):
https://amoralesdesign.github.io/pokevue/
But when you click on the Pokémon logo it does redirect to my real Home, although if you reload the page it gives a 404.

You need to config your base router points to your github page path:
const router = createRouter({
history: createWebHistory(process.env.NODE_ENV === 'production' ? '/pokevue/' : '/'),
routes
})
The reason when you click on the logo your home page is showing is that in that case, the vue router will match your URL with the home page route.

Related

Issue with Vue application deployed to subdirectory when route changes from publicPath

We have a Vue application that we're deploying to a subdirectory: /deploypath/
Right now, we have vue.config.js as:
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
publicPath: process.env.NODE_ENV === 'production'
? '/deploypath/'
: '/',
transpileDependencies: [
'vuetify'
]
})
Here's what's happening: In index.js (router) I have multiple paths configured to return multiple views and components. When a user is logged in, they can access additional pages. When they're not logged in, they're redirected to a (landing page).
I have multiple routes defined:
const routes = [
{
path: '/deploypath',
name: 'feature1',
component: FeatureOneView,
meta: {
title: 'Feature One',
}
},
{
path: '/deploypath/notloggedin',
name: 'notloggedin',
component: NotLoggedInView,
meta: {
title: 'Landing',
}
}
]
const router = new VueRouter({
mode: 'history',
routes: routes
});
Now, the issue I'm running into is that (after deploying a production build) when I visit /deploypath it works, however any other path (e. g. /deploypath/notloggedin) doesn't work. We have an Ubuntu instance running with nginx.
Are we doing something wrong with the Vue config or is there an issue on the nginx side, or other?
In case it helps anyone, a good buddy of mine helped find a solution:
cd /etc/nginx/sites-available
then:
sudo vim <insert your site's conf file here>
then press "i" to edit and within the top-level server { ... } section paste in (replace "dirname" with the name of the subdirectory you're hosting your Vue application in):
location ^~ /dirname {
try_files $uri /dirname/index.html =400;
}
then press escape (esc) on keyboard, then type ":wq" and press enter to save..
Then run:
sudo service nginx restart
then refresh your browser window and hopefully you see your Vue app!

Is there a way to import a folder structure in Vite

I have a bunch of sub-folders plus a few .vue components in the src/pages folder. With webpack I was able to get a list of the page paths and name with code like this:
export default require
.context("../pages", true, /^\.\/.*\.vue$/)
.keys()
.map(page => page.slice(2).replace(".vue", ""))
.filter(page => page !== "Index")
.map(page => ({
file: page,
title: createTitle(page),
path: slugify(kebabCase(page))
}));
Vite doesn't seem to support this. I tried const pages = import.meta.glob('../pages/*.vue') but this only works for files, not files inside sub-folders.
Any idea how I can achieve this with Vite?
I found a way. It's not perfect but not terrible either:
const pages = import.meta.glob('../pages/*.vue')
const folders = import.meta.glob('../pages/*/*.vue')
const both = {...pages, ...folders}
export default both
This is a refinement:
const pages = import.meta.glob('../pages/**/*.vue')
export default pages
I think you're looking for something like vite-plugin-pages :
installation :
npm install -D vite-plugin-pages
which requires vue-router to be installed :
npm install vue-router
Add to your vite.config.js:
import Pages from 'vite-plugin-pages'
export default {
plugins: [
// ...
Pages(),
],
}
Router config :
import { createRouter } from 'vue-router'
import routes from '~pages'
const router = createRouter({
// ...
routes,
})
There're also other plugin like unplugin-vue-components to resolve components and vite-plugin-vue-layouts to resolve layouts

Multi page VueJS / Express asset issue on production

I'm trying to deploy a VueJS/Express app to Heroku which consists of two App.vue instances using the 'pages' option on vue.config.js. One for the homepage, and then a seperate Vue app for the Saas app itself. Everything works locally in development, but I'm struggling with the server settings in Express for production on Heroku.
When I go to the page 'app' at pat-simplebooks.herokuapp.com/app looking at the sources tab in DevTools the app.js and app.css files returned are both the actual HTML of app.html, hence the app not loading.
The homepage works fine and is calling the 'index' page as expected.
Here is my vue.config.js
module.exports = {
pages: {
index: {
entry: 'src/pages/index/main.js',
template: 'public/index.html',
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
app: {
entry: 'src/pages/app/main.js',
template: 'public/app.html',
chunks: ['chunk-vendors', 'chunk-common', 'app']
}
}
}
And the relevant production settings in Express;
const history = require('connect-history-api-fallback');
if(process.env.NODE_ENV === 'production'){
app.use(history({
rewrites: [{
from: /\/app/,
to: '/app.html'
}]
}));
app.use(express.static(path.join(__dirname, '../../client/dist')))
}
I've tried adding <base href="/ "> to the HTML templates, as well as <base href="/app/" > but to no avail, as suggested in other answers I've found. Also the publicPath webpack option doesn't work for multiple pages as noted in the VueJS docs.
Removing the history redirect setting in Express allows me to navigate to http://pat-simplebooks.herokuapp.com/app.html - which works, however as soon as I refresh the page it redirects back to the 'index' page.
Any help would be great, I've exhausted my Googling skills.
I managed to work it out, incase anyone has the same issue in future.
The connect-history-api-fallback package needed to provided with the htmlAcceptHeaders option to only rewrite the html location, and not the JS/CSS assets.
app.use(history({
rewrites: [{
from: /\/app/,
to: '/app/index.html'
}],
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
}));
app.use(express.static(path.join(__dirname, '../../client/dist')))

VueJS + Webpack Dev Server not able to hot reload url subpaths

My application runs on the subdirectory http://localhost:8080/admin_suffix
suffix is a ENV variable which I can change and define in a .env file.
Once i run the webpack dev server, accessing http://localhost:8080/admin_suffix works.
Clicking on the hyperlinks in the SPA which points other subpaths works too. For example, I can navigate to http://localhost:8080/admin_suffix/subdirectory
However, when i hit reload on http://localhost:8080/admin_suffix/subdirectory, i will get an error "Cannot GET /admin_suffix/subdirectory"
I also cannot enter the subpath into the browser directly to load the page. Only ``http://localhost:8080/admin_suffix` works.
My configuration are as follows:
webpack.base.config.js:
entry: {
main: './src/main',
vendors: './src/vendors'
},
devServer: {
host: '0.0.0.0',
disableHostCheck: true
},
output: {
path: path.join(__dirname, '../dist')
}
webpack.dev.config.js:
module.exports = merge(webpackBaseConfig, {
output: {
publicPath: '/',
filename: '[name].js',
chunkFilename: '[name].chunk.js'
}
});
src/main.js:
const RouterConfig = {
mode: 'history',
routes: Routers,
base: '/admin_suffix/'
}
Enable devServer.historyApiFallback in webpack.base.config.js:
devServer: {
historyApiFallback: true,
// ...
},
This configures webpack-dev-server to fallback to index.html when the route is not found (404).
The Vue app and router are initialized from the main page (index.html), so refreshing the page while on a subroute would normally result in a 404 because the router would not have been setup yet. However, the fallback configuration mentioned above would result in the index.html being served instead, allowing the router to be setup and the subroute to subsequently complete.

404 when reloading a Vue website published to Github pages

I have deployed the contents of my /dist folder in the master branch of christopherkade.github.io, which has deployed my website succesfully.
But when I navigate using the navbar (christopherkade.com/posts or christopherkade.com/work) and reload the page I get an error by Github pages:
404 File not found
Note that my routing is done using Vue router like so:
export default new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/work',
name: 'Work',
component: Work
},
{
path: '/posts',
name: 'Posts',
component: Posts
},
{ path: '*', component: Home }
]
})
And my project is built like such:
build: {
// Template for index.html
index: path.resolve(__dirname, '../docs/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../docs'),
assetsSubDirectory: 'static',
assetsPublicPath: '/',
/**
* Source Maps
*/
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
What could be causing this issue?
But when I navigate using the navbar (christopherkade.com/posts or
christopherkade.com/work) and reload the page 404 File not found
Let me explain why 404 File not found is being shown
When christopherkade.com/posts is triggered from web browser, the machine to which the domain christopherkade.com is mapped is contacted.
The path /posts is searched in its server. in your case, i believe the route for /posts doesn't exist in the server. As the result 404 is displayed
There are few ways to fix this
To prevent the browser from contacting the server when triggering the request christopherkade.com/posts, you can keep mode : 'hash' in your route configuration
How mode : 'hash' works? This is one way to fix your issue
mode : 'hash' makes use of default browser behavior which is to prevent http request from triggering the details that exists after #
As the result, when you trigger christopherkade.com/#/posts , christopherkade.com is being triggered by the browser and once response is received the /posts route from the route config is invoked.
Lets assume that you have control over the server and you are adamant
that you need # to be removed from the URL
Then what you could do is to configure server in such a way that server responds with the same page everytime any paths is being sent. Once response is received in the browser, route will automatically kicked off.
Even in your current program, the routeConfig gets kicked off when you click any links (like work,posts) in your page. This is because the browser behavior is not being invoked at this point.
In your case, you use github for hosting this app with mode: 'history' i myself have to look for a specific solution to workaround this. i will update my answer once i get it.
i hope this was useful.
You can fix this issue by a simple workaround. I combined all the insights from reading multiple issues about this and finally this is what helped me fix this problem.
Solution Logic - You just need a copy of index.html with the name 404.html in the dist folder
Steps to fix
Go to you package.json file, under scripts add a new script called "deploy" like below, you just need to execute this everytime after you build your page. It will automatically take care of the issue.
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"deploy": "cd dist && cp index.html 404.html && cd .. && gh-pages -d dist"
},
This will copy the index.html & rename it 404.html and pushes dist folder under the branch gh-pages and after that your script will appear in the vue ui like below
or
If you are using git subtree push --prefix dist origin gh-pages method to push, then edit the deploy script in package.json to below
"deploy": "cd dist && cp index.html 404.html
and then execute the below git command. PS, don't forget to execute this script before manually using npm script method or from the vue ui
git subtree push --prefix dist origin gh-pages
This actually happens since your browser makes a request to christopherkade.com/posts URL which doesn't exist (this route is defined in Vue application running from index.html).
If you were running your own server, you would probably configure it to render your index.html page for any request URI, so your Vue application would be loaded from any path and handle routing by itself.
Speaking of GitHub pages, you can't just configure them to act the same way I described, but fortunately, there is a workaround which uses custom 404 page:
https://github.com/rafrex/spa-github-pages
As a workaround, I duplicated the index.html and renamed it to 404.html.
In this way, if the page is reloaded, you still get the correct page however this is served through the 404.html file.
As a workaround I have created folders for each route (with a script) and placed the index.html in all of them.
404s still don't work.
If you use Nuxt, this fixes the problem.
layaouts/blank.vue
<template>
<nuxt />
</template>
pages/redirect.vue
<template>
<div></div>
</template>
<script>
export default {
layout: 'blank',
fetch({base, redirect, query}) {
const param = query.p
if (param === undefined) {
return redirect('/')
}
const redirectPath = '/' + param.replace(base, '')
return redirect(redirectPath)
}
}
</script>
static/404.html
<html>
<head>
<script>
var pathName = window.location.pathname;
var redirectPath = '/<repository-name>/redirect';
location.href = redirectPath + '?p=' + encodeURI(pathName);
</script>
</head>
</html>
https://gist.github.com/orimajp/2541a8cde9abf3a925dffd052ced9008
Very simple perfect solution just follow the below instruction
Add a _redirects file inside the /public folder like /public/_redirects
After that add /* /index.html 200 into the _redirects file
I think with this solution your redirect problem will be solved