Pinia store not working when deployed to server but does when served by Vite - vue.js

Problem: My vue3 app which uses a Pinia store works as expected when deployed locally. When deployed to a server it fails to display the page which accesses the store.
The problem is the same on Firebase (emulator and live site) and with Netlify which makes me think there is some (probably very simple!) explanation hidden in the code.
To pare it down I have made what I think are minor changes to the vanilla vue-create app.
main.js
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
import router from "./router";
import "./assets/main.css";
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount("#app");
App.vue
<script setup>
import { RouterLink, RouterView } from "vue-router";
import HelloWorld from "./components/HelloWorld.vue";
</script>
<template>
<header>
<img
alt="Vue logo"
class="logo"
src="#/assets/logo.svg"
width="125"
height="125"
/>
<div class="wrapper">
<HelloWorld msg="You did it!" />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
</div>
</header>
<RouterView /></template>
<style>
...
</style>
views/AboutView.vue
<script setup>
import { useCounterStore } from "../stores/counter";
const newCounter = useCounterStore();
</script>
<template>
<div class="about">
This is an about page
{{newCounter.count}}
</div>
</div>
</template>
<style></style>
stores/counter.js
import { ref, computed } from "vue";
import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
});
package.json
{
"name": "firebase-tester",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
},
"dependencies": {
"pinia": "^2.0.23",
"vue": "^3.2.41",
"vue-router": "^4.1.5"
},
"devDependencies": {
"#rushstack/eslint-patch": "^1.1.4",
"#vitejs/plugin-vue": "^3.1.2",
"#vue/eslint-config-prettier": "^7.0.0",
"eslint": "^8.22.0",
"eslint-plugin-vue": "^9.3.0",
"prettier": "^2.7.1",
"vite": "^3.1.8"
}
}
Commands to build
nom run dev
(Runs as expected on local server, with value of count shown on 'about' page
npm run build
Builds a dist folder
firebase emulators:start
Emulator shows home page as expected but clicking does nothing, and no further navigation possible.
firebase deploy
Same issues as with emulator
To test if firebase was the problem, I have also deployed to a Netlify site, which has identical problems.
No doubt there is a really obvious problem staring me in the face, but I'm not seeing it!
All help appreciated.

In order for SPA to route correctly, a configuration file must be supplied with Firebase and Netlify. For both, as far as I remember correctly, this must be located unchanged in the dist, i.e. application root. So the best place before the build will be public.
For firebase it is firebase.json and for Netlify it is _redirect.
Deploy Firebase
Redirects explained (Netlify)
Rewrites
I am not sure if this fixes the problem with the Pinia store but this is an initial requirement before continuing troubleshooting the Pinia issue.

Related

Unable to test vue component with v-dialog

I have been killing myself trying to figure out how to test a Vue component with a v-dialog, something which worked perfectly fine in Vue2. Currently I am using Vue3, Vitest, Vuetify3.
here is a very simple component which demonstrates a problem
<template>
<div>
<v-btn #click.stop="dialog=true" class="open-dialog-btn">click me please</v-btn>
<v-dialog v-model="dialog" max-width="290" >
<div class="dialog-content">
<v-card>welcome to dialog</v-card>
</div>
</v-dialog>
</div>
</template>
<script setup>
import {ref} from "vue";
const dialog = ref(false);
</script>
and here is a unit test for it:
import '../setup';
import { mount } from '#vue/test-utils';
import { createVuetify } from "vuetify";
import HelloDialog from "#/components/HelloDialog.vue";
describe('HelloDialog', () => {
let wrapper;
let vuetify;
beforeEach(() => {
vuetify = createVuetify();
});
describe('dialog tests', () => {
beforeEach(async () => {
wrapper = await mount(HelloDialog, {
global: {
plugins: [vuetify],
},
});
});
test('test dialog', async () => {
expect(wrapper.find('.dialog-content').exists()).toBeFalsy();
await wrapper.find('.open-dialog-btn').trigger('click');
console.log(wrapper.html());
expect(wrapper.find('.dialog-content').exists()).toBeTruthy();
});
});
});
the last line in unit test is not working - dialog content is not displayed. Here is an output from wrapper.html() after button is clicked:
<div><button type="button" class="v-btn v-btn--elevated v-theme--light v-btn--density-default v-btn--size-default v-btn--variant-elevated open-dialog-btn"><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span>
<!----><span class="v-btn__content" data-no-activator="">click me please</span>
<!---->
<!---->
</button>
<!---->
<!--teleport start-->
<!--teleport end-->
</div>
AssertionError: expected false to be truthy
at ....../HelloDialog.spec.js:27:56
here is test section from vite.config.js:
test: {
// https://vitest.dev/config/
globals:true,
environment: 'happy-dom',
setupFiles: "vuetify.config.js",
deps: {
inline: ["vuetify"],
},
},
and here is vuetify.config.js:
global.CSS = { supports: () => false };
here some versions from package.json:
"dependencies": {
"#mdi/font": "7.1.96",
"#pinia/testing": "^0.0.14",
"axios": "^1.2.0",
"dotenv": "^16.0.3",
"happy-dom": "^8.1.1",
"jsdom": "^20.0.3",
"lodash": "^4.17.21",
"pinia": "^2.0.27",
"roboto-fontface": "*",
"vue": "^3.2.45",
"vuetify": "3.0.6",
"webfontloader": "^1.0.0"
},
"devDependencies": {
"#vitejs/plugin-vue": "^4.0.0",
"#vue/test-utils": "^2.2.6",
"vite": "^4.0.3",
"vite-plugin-vuetify": "^1.0.0-alpha.12",
"vitest": "^0.26.2"
}
I have tried everything at this point, and I think the problem has something to do with v-dialog using teleport component. After struggling for several days trying to figure out I settled on using a stub to not use a real dialog when testing but I really don't like this approach.
any ideas would be greatly appreciated
I have the same issue and found the content of v-dialog was rendered in document.body when I called mount().
You can test the dialog content like below.
// expect(wrapper.find('.dialog-content').exists()).toBeTruthy();
expect(document.querySelector('.dialog-content')).not.toBeNull();
I recommend to call unmount() after each test.
afterEach(() => {
wrapper.unmount()
});
Hope this helps although I doubt it's a good approach because I don't want to care whether the component is using teleport or not.

Fresh Laravel 9 installation with vue 3 scaffold and vite not redering component

I did a fresh laravel 9.19 installation with vue scaffolding and vite.js. everything works well just that the vue example component that comes with the fresh install of laravel refused to be rendered on the browser.
my environment
chrome Version - 108.0.5359.125 (Official Build) (64-bit)
node version - 19.3
Laravel 9.19
basically, as of today i'm using the latest version of everything.
I get a blank white screen on my browser with no errors on the console but the vue component is not rendering
I have tried suggestions from Laracast which is similar to my issue but nothing worked
content of my files
package.json
{
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"#popperjs/core": "^2.11.6",
"#vitejs/plugin-vue": "^3.0.1",
"axios": "^1.1.2",
"bootstrap": "^5.2.3",
"laravel-vite-plugin": "^0.7.0",
"lodash": "^4.17.19",
"postcss": "^8.1.14",
"sass": "^1.56.1",
"vite": "^3.0.0",
"vue": "^3.2.37"
}
}
vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '#vitejs/plugin-vue';
export default defineConfig({
plugins: [
laravel({
input: [
// 'resources/sass/app.scss',
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
},
},
});
resouces/js/app.js file
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
import './bootstrap';
import { createApp } from 'vue';
/**
* Next, we will create a fresh Vue application instance. You may then begin
* registering components with the application instance so they are ready
* to use in your application's views. An example is included for you.
*/
const app = createApp({});
import ExampleComponent from './components/ExampleComponent.vue';
app.component('example-component', ExampleComponent);
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// Object.entries(import.meta.glob('./**/*.vue', { eager: true })).forEach(([path, definition]) => {
// app.component(path.split('/').pop().replace(/\.\w+$/, ''), definition.default);
// });
/**
* Finally, we will attach the application instance to a HTML element with
* an "id" attribute of "app". This element is included with the "auth"
* scaffolding. Otherwise, you will need to add an element yourself.
*/
app.mount('#app');
resouces/views/layouts/app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<!-- Scripts -->
#vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<div id="app">
{{-- vue component goes here --}}
</div>
</body>
</html>
resources/js/components/ExampleComponent.vue
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
So i changed the boilerplate code in my resouces/js/app.js file and it worked. i don't know why.
i changed this
import './bootstrap';
import { createApp } from 'vue';
const app = createApp({});
import ExampleComponent from './components/ExampleComponent.vue';
app.component('example-component', ExampleComponent);
app.mount('#app');
to this
import './bootstrap';
import { createApp } from 'vue';
import ExampleComponent from './components/ExampleComponent.vue';
createApp(ExampleComponent).mount('#app');
So I recently just encountered this issue. I got a blank page when I run npm run dev. Thankfully on the console, I got the error message in the image below.
So I went ahead to my app.js to change my Vue import from
import { createApp } from "vue";
to
import { createApp } from 'vue/dist/vue.esm-bundler';

Vue 3 grid not working any more, what am I doing wrong?

This question was first asked on vuejs forum but didn't receive an answer (I know it's holidays seasons :)
I’m driving nuts with grids in vue3. It used to work some weeks ago but after some changes in the versions of the packages, I can’t get it working anymore (not sure it’s linked though). I created a small reproducer:
Package.json contains:
{
"name": "test",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve"
},
"dependencies": {
"vue": "3.2.26",
"vue-class-component": "8.0.0-rc.1",
"vue-router": "4.0.12",
"primeflex": "^3.1.0",
"primeicons": "^5.0.0",
"primevue": "^3.9.1"
},
"devDependencies": {
"#types/node": "17.0.0",
"#vue/cli-plugin-babel": "4.5.15",
"#vue/cli-plugin-router": "4.5.15",
"#vue/cli-plugin-typescript": "4.5.15",
"#vue/cli-service": "4.5.15",
"typescript": "4.5.4"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
src/main.ts contains:
import { createApp } from "vue";
import MyApp from "./App.vue";
import PrimeVue from "primevue/config";
import "primevue/resources/themes/saga-blue/theme.css";
import "primevue/resources/primevue.min.css";
import "primeicons/primeicons.css";
import "primeflex/primeflex.min.css";
createApp(MyApp)
.use(PrimeVue)
.mount("#app");
and src/App.vue contains basically a copy of the example named “Vertical Layout with Grid” using the vuue 3 syntax with vue-class-component:
<template>
<h2>test</h2>
<div class="p-fluid p-formgrid p-grid">
<div class="p-field p-col">
<label for="firstname">Firstname</label>
<InputText id="firstname" type="text" />
</div>
<div class="p-field p-col">
<label for="lastname">Lastname</label>
<InputText id="lastname" type="text" />
</div>
</div>
</template>
<script lang="ts">
import { Options, Vue } from "vue-class-component";
import InputText from "primevue/inputtext";
#Options({
components: {
InputText,
},
})
export default class MyApp extends Vue {}
</script>
This should display something like this:
But it actually shows (using Firefox):
and I’m totally unable to get both fields side by side…
Can someone please point me in the right direction?
Thank you!
[1]: https://i.stack.imgur.com/44P2h.png
[2]: https://i.stack.imgur.com/75nZk.png
#BenSouchet Thanks for your comment, you pushed me to the right track.
Precisely, I first looked only at p-fluid which I was able to find in the CSS but after your comment I looked closer and I found I was unable to find p-formgrid, p-grid, or p-field in the page nor in the node_modules directory.
Running grep -R 'p-grid' node_modules/prime* does not return anything...
So, I looked twice at https://www.primefaces.org/primeflex/migration and discovered that with primeflex 3, all classes named p-xxx are now named xxx (eg p-formgrid becomes formgrid) so I changed the classes in the template above and it's now working fine again...
Now, the next question is why such a breaking change??? I need to pass through my whole application to fix that :/

Loading mermaid in a vue component (webpack)

I am migrating a vue project that uses mermaid from CDN to webpack. I'm total new with it. I did npm install save mermaid on project folder.
If i load mermaid cdn as static js (in /public/index.html), it crashes for some graphs (shows bomb icon, says syntax error)
If in webpack, it shows nothing as mermaid graphs, but seems to load empty (inspecting generated html with browser tools). No console errors
<svg id="mermaidChart0" width="100%" xmlns="http://www.w3.org/2000/svg"><g><g class="output"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"></g></g></g></svg>
Tried:
//package.json
...
"dependencies": {
"axios": "^0.21.0",
"core-js": "^3.6.5",
"mermaid": "^8.8.2",
and in the component.vue
<template>
...
<div class="mermaid m-5">
graph LR
B(dsfgdsfgsd <br>) --> Bo(gdfshfghfdh <br>)
...
<script>
import mermaid from 'mermaid'
export default {
data: function() {
return {}
},
mounted() {
this.init();
},
methods: {
init: function() {
mermaid.initialize({
theme: 'forest',
htmlLabels: true,
//startOnLoad: true
});
console.log(mermaid);
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
}
}
}
If you want a ready-to-use solution, you can use my component vue-mermaid-string. It does the internal work for you.
Install it via NPM, then add it to your project via CDN script or by adding the component, then use it like so:
<template>
<vue-mermaid-string :value="diagram" />
</template>
<script>
export default {
computed: {
diagram: () => 'graph TD\n A --> B',
},
}
</script>

Angular2 beta - bootstrapping HTTP_PROVIDERS - "Unexpected Token <"

Starting with the 5 minute quick start I've been playing around the angular2 beta and have run across a problem that has me stumped.
Here is a dumbed down version that shows the problem I have. First here a hello world app working perfectly.
package.json
{
"name": "...",
"version": "0.0.1",
"description": "...",
"author": {
"name": "...",
"email": "..."
},
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
},
"license": "ISC",
"dependencies": {
"angular2": "2.0.0-beta.0",
"bootstrap": "^3.3.6",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"reflect-metadata": "^0.1.2",
"rxjs": "5.0.0-beta.0",
"systemjs": "0.19.6",
"zone.js": "^0.5.10"
},
"devDependencies": {
"concurrently": "^1.0.0",
"lite-server": "^1.3.1",
"typescript": "^1.7.3"
}
}
index.html
<head>
<title>Title</title>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<link href="styles.css" rel="stylesheet" />
<!-- 1. Load libraries -->
<script src="node_modules/es6-shim/es6-shim.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"> </script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<!-- 2. Configure SystemJS -->
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/boot')
.then(null, console.error.bind(console));
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app></my-app>
</body>
app/boot.ts
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {AccountService} from './accounts/account.service'
bootstrap(AppComponent);
app/app.component.ts
import {Component, View} from 'angular2/core';
import {RegisterFormComponent} from './accounts/register-form.component'
#Component({
selector: 'my-app',
})
#View({
template: 'hello world',
})
export class AppComponent {
}
I evntually want to call my Web Api service so I am trying to follow the docs for Http, I update boot.ts as follows:
new app/boot.ts
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {AccountService} from './accounts/account.service'
import {HTTP_PROVIDERS} from 'angular2/http';
bootstrap(AppComponent, [HTTP_PROVIDERS]);
And here's where things choke.
Chrome gives me:
uncaught SyntaxError: Unexpected token < - http:1
uncaught SyntaxError: Unexpected token < - angular2-polyfills.js:138
evaluating http://localhost:3000/angular2/http
error loading http://localhost:3000/app/boot.js
It also fails if I try to set the HTTP_PROVIDERS as a viewProvider on my component.
Has anyone else had any luck getting Http to inject properly in the angular2 beta?
Visual Studio 2015
Node.JS & Node.JS tools for visual studio
Using 'NPM start' to compile and run
This error occurs when you try to import something that is not being included in your HTML when using SystemJS. Module bundlers like Webpack handle all that for you.
For your case you have to add the Http bundle that's a separated bundle, for example
<script src="https://code.angularjs.org/2.0.0-beta.0/http.dev.js"></script>
You'll see this same error when trying to use the router and you forgot to add the router bundle.
Check the difference between these two configurations from #pkozlowski-opensource's repos
Using SystemJS : For this case he would've to add http bundle, or router bundle if he wanted to use them.
Using Webpack : In this case Webpack bundles everything in that bundle.js file for you.
Glad it helped.
If you're using npm, include a script tag with the http reference to your local installation:
<script src="node_modules/angular2/bundles/http.dev.js"></script>