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')))
Related
Where I work we have one .net web site with 3 different mvc areas which are for each type of user we work with. Clients, Recruiters and Employees. I'd like to recreate this in vue where it's one vue project but a separate client app, recruiter app and employee app. Using the vue.config.js file I'm able to do that.
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
pages: {
app1: {
entry: 'src/clients/main.js',
template: 'public/client.html',
filename: 'client.html',
title: 'Clients',
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
app2: {
entry: 'src/recruiters/main.js',
template: 'public/recruiter.html',
filename: 'recruiter.html',
title: 'Recruiters',
chunks: ['chunk-vendors', 'chunk-common', 'index']
}
}
})
This works fine when I build a production version of the site with the cli. However I cannot get it to work properly when I run the local dev version. Here's a screenshot of my project (using webstorm).
Before I set up all of the separate apps, when I would run vue-cli-service serve the public index.html file would get the main.js file from the src folder injected into it. I am trying to get the same thing happening for the Clients and Recruiters folder where the recruiters/main.js file get injected into the public/recruiter.html file and so on for clients. For now, I'm guessing because of the vue.config.js file, it no longer injects the src/main.js into the public/index.html file.
Is there a setting for the cli to do this? Or a config file I'm missing?
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.
When you generate a PWA app using vue ui you can expect the following behavior.
All files you have in your dist folder are precached by browsers.
In other words, when you navigate to your app a browser will quietly download all the files and cache it for further use.
The problem here is that browsers will also download async chunks which could never be used by a user. For example, I have an admin-settings route and a regular user does not need to download it at all.
Now I'm trying to disable this behavior, here's modified vue.config.js file:
module.exports = {
chainWebpack: config => {
config.plugins.delete('prefetch-index')
config.plugins.delete('preload-index')
},
pwa: {
workboxOptions: {
exclude: [/.*/],
runtimeCaching: [{
urlPattern: new RegExp('^https://example.com.*'),
handler: 'CacheFirst',
options: {
cacheableResponse: {
statuses: [200]
}
}
}]
}
},
...
}
Right now everything works as expected and browsers do not prefetch resourses. The problem, however, is that when I upload a new version of a file the app is not updated. Browsers still use the previos version of the file.
I'm stuck, any advice, good sirs?
P.S. Figured it out.
This line caused index.html to be also cached.
urlPattern: new RegExp('^https://example.com.*')
After changing it everything works as expected.
urlPattern: new RegExp('^https://example.com/.+')
Now the problem is that the old version of a cached file is not deleted from cache. The size of cache would grow a lot with each new deployment.
Any advice?
I'm working with Webpack 4.43, Vue 2.6.11 & Vue Router 3.1.6
Webpack generates a dist folder with a bundle.js and an index.html.
If I navigate to nested pages through the app links everything works fine, but if I try to reload a nested page, the index.html can't load bundle.js because it tries to find it at the nested page level. For example if I go to localhost:8080/fr/contact it will try to load localhost:8080/fr/bundle.js
I've seen many other related topic but no one ever gives a real answer. Does anyone have a solution?
EDIT: Don't know if it helps, but I just realized that the images don't load in nested pages even when I reach them through the router-links. Same problem: it looks for localhost:8080/fr/my-image.png instead of localhost:8080/my-image.png
Finally solved it by setting publicPath: '/' in my Webpack config (not the Vue config). Here's how it looks:
module.exports = {
...
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
...
}
I have created my project with vue-cli, running 'vue init webpack project-name'. I cannot figure out how to change the page title and the favicon displayed.
Somehow the page title is always 'Vue App' and favicon is the Vue logo. How do I change these? They seems to be generated from somewhere in the webpack config, but I cannot figure out where.
I fixed this by creating a public folder to the project root. Then I moved my index.html and favicon into the public folder.
//This is in the index.html head
<link rel="icon" type="image/png" href="/favicon.png" />
If you're using vue-cli, this is the only way I could find to get the page title to not unprofessionaly flash "Vue App" on load. If someone finds an easier solution, please share!
Create custom-index.html with your own title, then in vue.config.js:
const HTMLWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
new HTMLWebpackPlugin({
showErrors: true,
cache: true,
template: path.resolve(__dirname, 'src/custom-index.html'),
})
],