Vue crash when ssl is active - ssl

I have a project that cointains a couples of vue components. The main file loads the components when are needed by lazy loading them.
import Vue from 'vue'
const DateFiled = () => import('./components/DateField')
const ItemClone = () => import('./components/ItemClone')
...
Vue.component('date-field', DateFiled);
Vue.component('item-clone', ItemClone);
...
const app = new Vue({
el: '#app'
});
This work on development, but on production it only work when the ssl is off. if i turn it on i get an error
mixed content the page at was loaded over https but requested an insecure...
The error show that it try to get the chunks from http://localhostjs/js/chunks/0.bundle.js, why this happens only when ssl is on?
how can i solve this?
i have tried to add the url in the webpack like this
mix.config.webpackConfig.output = {
chunkFilename: 'js/chunks/[name].bundle.js',
publicPath: process.env.APP_URL,
};
and have tried to set APP_URL to
APP_URL=https://example.com/
APP_URL=/
APP_URL=https://example.com/public/
But none of those worked. the server is apache on centOs

Related

Vue 3 external component/plugin loading in runtime

I am designing an architecture for the Vue 3 app with distributed module-based ownership. Module system will be represented with plugins (seems like the most appropriate solution allowing vuex module and vue-router dynamic injects). Each such module/plugin will be developed by dedicated team working within isolated repos. We cannot use npm package-per-plugin approach as deployment process should be isolated as well, and with npm approach core app team will have to rebuild app each time npm package plugin has updates. This means we will have to load such plugins/pages at runtime via http.
So far this approach by Markus Oberlehner seems like some sort of the way to go - it uses custom Promise based solution for webpack's missing "load external url script at runtime" functionality. While it works fine with Vue 2, Vue 3 gives VNode type: undefined error.
The above mentioned article offers the following webpack external component loading solution:
// src/utils/external-component.js
export default async function externalComponent(url) {
const name = url.split('/').reverse()[0].match(/^(.*?)\.umd/)[1];
if (window[name]) return window[name];
window[name] = new Promise((resolve, reject) => {
const script = document.createElement('script');
script.async = true;
script.addEventListener('load', () => {
resolve(window[name]);
});
script.addEventListener('error', () => {
reject(new Error(`Error loading ${url}`));
});
script.src = url;
document.head.appendChild(script);
});
return window[name];
}
But above, as I said, does not work with Vue 3 defineAsyncComponent mechanism.
// 2.x version WORKS
const oldAsyncComponent = () => externalComponent('http://some-external-script-url.js')
// 3.x version DOES NOT WORK
const asyncComponent = defineAsyncComponent(
() => externalComponent('http://some-external-script-url.js')
)
So I have two questions:
Are there any known better solutions/suggestions for above architectural specification?
Is there any working webpack dynamic external import solutions tested with Vue 3 out there?
UPD: Here is small reproduction repo
We solved this problem together via chat.
Components built via the Vue 3 vue-cli rely on Vue being available in the global scope. So in order to render components loaded via the technique described in my article, you need to set window.Vue to a reference to Vue itself. Then everything works as expected.
update:
If import vue from vue/dist/vue.esm-bundler and set to global, then no need to change webpack / Vite config, and no need to load vue from cdn.
import * as Vue from 'vue/dist/vue.esm-bundler';
window.Vue = Vue;
Besides setting window.Vue, some other webpack or Vite configuration should also be set, otherwise some error is presented in console: vue warn invalid vnode type symbol(static) (symbol)
Vue3 + webpack:(https://github.com/vuejs/vue-next/issues/2913#issuecomment-753716888)
// index.html:
<script src="https://cdn.jsdelivr.net/npm/vue#3.0.4"></script>
// vue.config.js
configureWebpack: config => {
...
config.externals = { vue: 'Vue' }
...
}
Vue3 + vite:(https://github.com/crcong/vite-plugin-externals)
// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'
export default {
plugins: [
viteExternalsPlugin({
vue: 'Vue'
}),
]
}

How do I optimize my app.js file when using Vuejs

I am looking for help in understanding what are the best practices people are using for a VueJs app that is not an SPA. In my project I have multiple pages and currently I'm treating every page as an SPA. But I'm noticing that my app.js size is increases after adding a new page. This is what I have so far
require('./bootstrap');
var Vue = require('vue');
import GlobalMixins from './mixins/GlobalMixins'
import VueFlashMessage from 'vue-flash-message'
import PortalVue from 'portal-vue'
import Treeselect from '#riophae/vue-treeselect'
Vue.prototype.$eventHub = new Vue(); //global event bus
Vue.mixin(GlobalMixins);
Vue.use(PortalVue);
Vue.use(VueFlashMessage,{
messageOptions: {
timeout: 7000,
important: false,
autoEmit: true,
pauseOnInteract: true,
createShortcuts: false,
}
});
// shared components
Vue.component('navigation', require('./components/navigation.vue').default);
Vue.component('loader',require('./components/shared/custom_loader.vue').default);
Vue.component('treeselect',Treeselect);
//parent components only for each page
Vue.component('goals', require('./components/goals/index.vue').default);
Vue.component('dashboard', require('./components/dashboard/index.vue').default);
Vue.component('twitter', require('./components/twitter/index.vue').default);
Vue.component('trends', require('./components/trends/index.vue').default);
Vue.component('settings', require('./components/settings/index.vue').default);
..........
..........
..........
require('./filters');
window.onload = function () {
new Vue ({
el: '#app'
});
}
I'm compiling my assets using laravel-mix and even after running npm run prod app.js size is around 2MB. How can I optimize this?
PS: gzip compression is already enabled on my servers.

Vue local config file per App installation

I am new the Vue.js and I am trying first steps with an app. So for understanding the basics, I want a local config file per App installation to customise some needed variables in the code.
So in my main.js I tried the following:
import Vue from 'vue'
import App from './App.vue'
let config;
try {
config = require('../config.json');
} catch (e) {
config = require('../public/config.json');
}
Vue.config.productionTip = false;
Vue.prototype.$localConfig = config;
new Vue({
render: h => h(App)
}).$mount('#app');
This is working, until I build the production version with the dist folder. If I open the config.json in the root of the dist and change a property value, I see always the first defined values from the development env. So is webpack making there some caching? Is this at all the right way of handling such a local config file per App installation?
Maybe someone could give me some tips on this.
Doing config = require('../config.json'); is the same as import config from "../config.json" in a way that it takes the content of your json file at build time, transform it into JS object and make's it part of your app bundle.
You can do what you propose in a comment (include the file in a script tag in your index.html) but that means your app is doing additional request to the server to load the config and by doing so increasing "time to render" (time user have to wait until the page is fully rendered)
Most common way to handle app configuration in Vue/Webpack world is by using Environment Variables - those also "work" at build time tho so you need to build your app separately for each environment
let config
const configPromise =
process.env.NODE_ENV === 'development'
? import('../config.json')
: import('../public/config.json')
configPromise.then(res => {
config = res.default
})

How to pre-render multiple Vue app pages?

I'm trying (unsuccessfully) to pre-render the HTML of multiple Vue apps within the same project scaffolded with Vue CLI. I do not want to use Vue Router or Nuxt etc for multiple reasons.
I've tried using prerender-spa-plugin, but since I don't use routes, it only pre-renders the index.
My vue.config.js looks like this:
const path = require('path');
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
module.exports = {
pages: {
index: 'src/index.js',
about: 'src/about.js',
},
configureWebpack: {
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/'],
postProcess(route) {
route.html = route.html.replace('</script><div>', '</script><div id="app" data-server-rendered="true">');
return route;
},
renderer: new Renderer({
headless: true,
renderAfterDocumentEvent: 'render-event',
}),
}),
],
},
};
and my index.js and about.js essentially look like this:
import Vue from 'vue';
import App from './Index.vue';
new Vue({
render: h => h(App),
mounted() {
document.dispatchEvent(new Event('render-event'));
},
}).$mount('#app');
I also have unique public/ index.html and about.html pages.
The routes parameter of prerender-spa-plugin doesn't seem to recognise things like '/about.html'. Is there an easy way of achieving multiple pre-rendered pages?
Do I have to wrestle with the SSR module?
Thanks in advance.
The solution I've found is to call new PrerenderSPAPlugin multiple times, one for each route.
I'm also facing the same issue, i have static html uses vue component and i want to pre-render the vue component in output build directory. I'm using laravel-mix package for build process.
Could you post the full solution for this i.e calling new PrerenderSPAPlugin multiple times, one for each route.
If i can get the full webpack.config.js, it would easy for me to understand and implement the same using laravel-mix.

I'm using prerender-spa-plugin and it works, but Google doesn't see the prerendered pages

I have a Vue.js application and I want to use prerendering for SEO purposes.
I followed the github, this tutorial, this one, and this video to understand everything and I ended up with this implementation in my app:
in webpack.prod.conf.js:
...
const path = require('path')
const webpack = require('webpack')
...
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const PuppeteerRenderer = PrerenderSPAPlugin.PuppeteerRenderer
...
plugins: [
new PrerenderSPAPlugin({
staticDir: path.join(__dirname, '../dist'),
routes: ['/', '/about-gy', '/gy-quest'],
headless: false,
renderer: new PuppeteerRenderer()
})
]
in main.js (if it matters somehow):
new Vue({
router,
store: store,
components: { App },
render: h => h(App)
}).$mount('#app');
The results I get are as expected I think; in the dist folder it looks like this:
dist
--about-gy
+--index.html
--gy-quest
+--index.html
--static
--index.html
Where the html files have the CSS and HTML rendered.
The problem is that when I test the same way the guy in the video tests (with view page source on the rendered pages) I get only the "app" div inside and not the already rendered one.
I thought maybe it's because it's on a local server or something, tried to Fetch as Google on the Search Console tool they offer, and still, they fetch the not-rendered version of the pages.
I'm stuck because it's not an issue I can write on the github of the plugin because the plugin does its job, but I'm not sure what I'm doing incorrectly.
In your webpack.prod.conf.js add an option to renderer: new PuppeteerRenderer() that tells it to run once the app has been mounted:
renderer: new PuppeteerRenderer({
renderAfterElementExists: "#app"
})