Can't figure out this error with vuex store and vue.js:
Is this a webpack-cli thing? or am i not doing something right? Thanks for the help!
Module parse failed: /Users/me/sites/vue/src/components/SectionView.Vue Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <template>
| <ul class="listing">
| <li v-for="item in $store.state.items">
# ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/PanelBody.vue 3:0-56
# ./src/components/PanelBody.vue
# ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Panel.vue
# ./src/components/Panel.vue
# ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Accordion.vue
# ./src/components/Accordion.vue
# ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Sidebar.vue
# ./src/components/Sidebar.vue
# ./~/babel-loader/lib!./~/vue-loader/lib/selector.js?type=script&index=0!./src/components/Body.vue
# ./src/components/Body.vue
# ./src/router/index.js
# ./src/main.js
# multi ./build/dev-client ./src/main.js
My SectionView.vue file:
<template>
<ul class="listing">
<li v-for="item in $store.state.items">
<router-link :to="{ name: 'item', params: { id: item.id }}">
<img :src="item.image" />
<br>{{ item.name }}
</router-link>
</li>
</ul>
</template>
<script>
import Item from '../components/Item',
export default {
name: 'SectionView',
components: {
'item': Item
},
created () {
this.$store.dispatch('fetch')
}
},
}
</script>
My Item.vue:
<template>
<div id="section-view">
<div class="item-view">
<router-link class="back-listing" :to="{name: 'section'}">U+0003C</router-link>
<div class="item">
<h1>{{ item.name }}</h1>
</div>
</div>
</template>
<script>
export default {
name: 'item',
computed: {
item: function () {
return this.$store.state.items.find(item => item.id === this.$route.params.id)
}
},
created () {
this.$store.dispatch('open', this.$route.params.id)
}
}
</script>
My store which is in a src/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const db = [
{ id: 'a', name: 'Item #1', image: 'http://lorempicsum.com/simpsons/350/200/1' },
{ id: 'b', name: 'Item #2', image: 'http://lorempicsum.com/simpsons/350/200/2' },
{ id: 'c', name: 'Item #3', image: 'http://lorempicsum.com/simpsons/350/200/3' }
]
const store = new Vuex.Store({
state: {
items: [],
opened: {}
},
actions: {
fetch: function ({commit, state}, payload) {
commit('SET_LIST', db) // Just clone the array
},
open: function ({commit, state}, payload) {
// look for item in local state
var localItem = state.items.find(item => payload === item.id)
if (!localItem) {
new Promise(function (resolve, reject) {
return db.find(item => payload === item.id)
})
.then(result => {
commit('ADD_ITEM', result)
})
}
}
},
mutations: {
SET_LIST: function (state, payload) {
Vue.set(state, 'items', payload)
},
ADD_ITEM: function (state, playload) {
state.items.push()
}
}
})
console.log('State', store)
export default store
And my main.js calling the store:
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import store from './store'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
template: '<App/>',
components: { App }
})
Like #MateenRay said the ".Vue" instead ".vue" really could be the issue.
This is all about your operating system.
On windows "FILE.txt" and "file.txt" are the same. So when calling you vue file upper or down case it doesn't matter.
But for linux "FILE.txt" and "file.txt" are two separate files ! So calling your ".Vue" file is not the same as calling the ".vue" one.
Its important to remember this because on my project we were on windows and didn't pay attention to this. Next we changed all our file names from "file" to "File". Next we had to deliver it on a linux machine and nothing was working because some files were not found... Some of us were still importing files like the following :
import file from ... instead of import File from ...
It was working on windows but not on linux.
/Users/me/sites/vue/src/components/SectionView.Vue
I think the name SectionView.Vue should be SectionView.vue
components extensions are vue
For me, reinstalling babel and webpack fixed this issue.
npm install babel-core babel-loader babel-preset-es2015 webpack --save-devnpm install babel-core babel-loader babel-preset-es2015 webpack --save-dev
Link
Related
I have a small app in Vue 3 which I list data from a local json file and then click over to a detail page to view the rest of the data. I am able to list all the data and link to a detail page, but I cannot seem to figure out how to show the data of just the single id.
router/index.js
...
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'Ndas',
component: Ndas
},
{
path: '/nda/:id',
name: 'NdaDetails',
component: NdaDetails,
props: true
}
]
})
...
views/Ndas.vue -- This Works
<template>
<main>
<h1>NDAS</h1>
<div v-if="loading">Loading...</div>
<div v-for="nda in ndas" :key="nda.id">
<router-link :to="{ name: 'NdaDetails', params: { id: nda.id }}">
<h2>{{ nda.user_signature }}</h2>
</router-link>
</div>
</main>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
loading: true,
ndas: []
}
},
mounted () {
this.loading = true;
axios
.get('../../data/data.json')
.then(response => (this.ndas = response.data))
.catch(error => console.log(error))
.finally(() => this.loading = false)
},
}
</script>
views/NdaDetails.vue -- This Doesn't Work
<template>
<div>
<div v-if="nda">
<h1>NDA's Detail Page</h1>
<p>The job title is {{ nda.user_signature }}</p>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
props: ['id'],
data() {
return {
nda: {}
}
},
async created() {
try {
const res = await axios.get('../../data/data.json/'+this.id);
this.nda = res.data;
} catch (error) {
console.log(error);
}
},
}
</script>
UPDATE: OP fixed the issue by serving his JSON file with a server, now it's working great.
Here, you probably want something like this rather than a prop
const res = await axios.get('../../data/data.json/' + this.$route.params.id)
Props are used in a child/parent content, to pass some state down.
Here, you can access the value of your URL directly (router being global) and remove the props part.
I'm creating an app with MFE with Vuejs3 and webpack 5 module federation. One main app made with Vue will consume other apps (should be framework agnostic) and I need to share State from my Vue shell to other apps.
I tried making a store with the Composition api but the value get only updated in the app that call the event.
Here is the store that I expose from the vue shell:
import { reactive, toRefs } from 'vue'
const state = reactive({
data: {
quantity: 1,
},
})
export default function useStoreData() {
const updateQuantity = (quantity) => {
state.data.quantity += quantity
}
return {
...toRefs(state),
updateQuantity,
}
}
in vue shell :
<template>
<div>
<button #click="updateQuantity(1)">FOO +1</button>
<div>Quantity = {{ data.quantity }} </div>
</div>
</template>
<script setup>
import useStoreData from '../store/storeData'
const { updateQuantity, data } = useStoreData()
</script>
when I click on the button "FOO +1", value gets updated +1.
in my remote app:
<template>
<div>
<button #click="updateQuantity(5)">BAR +5</button>
<div>Quantity = {{ data.quantity }}</div>
</div>
</template>
<script setup>
import store from 'store/storeData'
const useStoreData = store
const { data, updateQuantity } = useStoreData()
</script>
When i click on button "BAR +5" the value get update +5
BUT everytime I click on one of those button, the value in the other app doesn't get updated.
What did I miss ?
Needed to add the shell app as a remote of itself then import the store in the shell app, same way as i'm doing in my remote app.
Here is the vue.config.js of the shell, where I need to expose AND remote the store.
const { ModuleFederationPlugin } = require('webpack').container
const deps = require('./package.json').dependencies
module.exports = {
publicPath: '/',
configureWebpack: {
plugins: [
new ModuleFederationPlugin({
name: 'shell',
filename: 'remoteEntry.js',
remotes: {
test: 'test#http://localhost:8081/remoteEntry.js',
test2: 'test2#http://localhost:8082/remoteEntry.js',
store: 'shell#http://localhost:8080/remoteEntry.js', <= ADDED HERE the remote of itself
},
exposes: {
'./storeData': './src/store/storeData.js',
},
shared: [
{
...deps,
},
],
}),
],
},
devServer: {
port: 8080,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
},
},
}
In the Vue shell app:
<script setup>
// import useStoreData from '../store/storeData' <= wrong
import store from 'store/storeData' <= good
</script>
I am using: npm install vue-stripe-checkout, but a i get this error:
vue.runtime.esm.js?2b0e:5106 Uncaught TypeError: Cannot read property 'install' of undefined
at Function.Vue.use (vue.runtime.esm.js?2b0e:5106)
at eval (main.js?56d7:5)
at Module../src/main.js (app.js:1148)
in my main.js:
import Vue from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify';
import VueStripeCheckout from 'vue-stripe-checkout';
Vue.use(VueStripeCheckout, "pk_test_wk9TFDEeu4kRrI1pT0WxYrBC00bSQO9djj");
Vue.config.productionTip = false
new Vue({
vuetify,
render: h => h(App)
}).$mount('#app')
Looks like you're using the newest version of vue-stripe-checkout which has breaking changes that doesn't allow you to use as above way (as a plugin)
It currently exports 2 components: StripeCheckout and StripeElements which requires you to use them as component instead.
Here is a very basic example:
<template>
<stripe-checkout
ref="checkoutRef"
:pk="publishableKey"
:items="items"
:successUrl="successUrl"
:cancelUrl="cancelUrl"
>
<template slot="checkout-button">
<button #click="checkout">Check out</button>
</template>
</stripe-checkout>
</template>
<script>
import { StripeCheckout } from 'vue-stripe-checkout';
export default {
components: {
StripeCheckout
},
data: () => ({
loading: false,
publishableKey: 'YourKey',
items: [
{
sku: 'sku_FdQKocNoVzznpJ',
quantity: 1
}
],
successUrl: 'your-success-url',
cancelUrl: 'your-cancel-url',
}),
methods: {
checkout () {
this.$refs.checkoutRef.redirectToCheckout();
}
}
}
</script>
You could reference to here to see all examples for both components: https://github.com/jofftiquez/vue-stripe-checkout
I am new to vue and trying to build my first vue app using nuxtjs. My problem right now has to do with architecture and folder structure.
In my other non-vue apps I always have a "services" directory where I keep all my code that makes http requests.
example under my services folder I will have a auth.ts file that contains code that posts login credentials to my API. This file/class returns a promise which I access from within my store.
I am trying to do this with vue using nuxtjs but I realised I am unable to access the axios module from anywhere aside my .vue file.
This is an example of how my code is now:
<template>
...
</template>
<script lang="ts">
import Vue from 'vue'
import ActionBar from '../../components/ActionBar.vue'
export default Vue.extend({
components: { ActionBar },
data() {
return {
example: ''
},
methods: {},
mounted() {
this.$axios.$get('/examples').then((res) => {
this.examples = res.data;
})
}
})
</script>
<style>
...
</style>
I would like to move the axios calls to their own files in my services folder. How do I do this?
what you can do is create a file inside the ./store folder, let's imagine, ./store/products.js, that will create a products store, inside, simple getters, mutations and actions:
export const state = () => ({
products: [],
fetchingProducts: false,
})
export const getters = {
getAllProducts(state) {
return state.products
},
hasProducts(state) {
return state.products.length > 0
},
isFetchingProducts(state) {
return state.fetchingProducts
},
}
export const mutations = {
setInitialData(state, products) {
state.products = products
},
setLoadingProducts(state, isLoading) {
state.fetchingProducts = isLoading
},
}
export const actions = {
async fetchProducts(context, payload) {
context.commit('setLoadingProducts', true)
const url = `/api/example/${payload.something}`
const res = await this.$axios.get(url)
context.commit('setInitialData', res.data)
context.commit('setLoadingProducts', false)
},
}
then in your .vue file, you can now use the store as:
<template>
<div>
<div v-if="isFetchingProducts"> loading... </div>
<div v-else-if="!hasProducts">no products found</div>
<div v-else>
<ul>
<li v-for="product in allProducts" :key="product.id">
{{ product.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data () {
return {
products: []
}
},
methods: {
...mapGetters({
isFetchingProducts: 'products/isFetchingProducts',
allProducts: 'products/getAllProducts',
hasProducts: 'products/hasProducts',
})
},
mounted() {
this.$store.dispatch('products/fetchProducts', {})
},
}
</script>
<style>
...
</style>
remember that:
to call a store action, you should use $store.dispatch()
to call a mutation, you should use $store.commit()
to call a getter, you should use $store.getter()
you can also use the Vuex helper mapGetters, mapActions and even mapMutations
You might also know that you can leverage the Plugins in Nuxt, that article has demo code as well so you can follow up really quick
I am getting a lot of Vue warnings saying $listeners is readonly or $attrs is readonly and related to different Bootstrap items or to .
For example:
[Vue warn]: $attrs is readonly.
found in
---> <BDropdown>
<Display>
<App>
<Root>
I am very sure it has something to do with loading the Vue instance twice somehow, but I don't really know, how to do it any other way, so that the routing still works.
In my main.js the code is as follows:
import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase';
import './components/firebaseInit';
import store from './store';
import { i18n } from './plugins/i18n.js'
import BootstrapVue from 'bootstrap-vue'
import VueCarousel from 'vue-carousel';
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue);
Vue.use(VueCarousel);
let app;
firebase.auth().onAuthStateChanged(user => {
if(!app) {
app = new Vue({
el: '#app',
router,
store,
i18n,
components: { App },
template: '<App/>'
})
}
})
My router/index.js code looks as follows:
import Vue from 'vue'
import Router from 'vue-router'
import firebaseApp from '#/components/firebaseInit'
Vue.use(Router)
let router = new Router({
routes: [
{
path: '/',
name: 'display',
component: Display
},
...
]
})
// Nav Guards
router.beforeEach((to, from, next) => {
// check for requiredAuth
if(to.matched.some(record => record.meta.requiresAuth)) {
// check if NOT logged in
...
} else {
// proceed to route
next();
}
} else {
next();
}
})
export default router;
As the sample errors come from Display.vue, here is an extract of that code:
<template>
<div>
<b-row>
<b-input-group prepend="Category">
<b-dropdown v-bind:text="currentCategory">
<b-dropdown-item #click="categroyChanged('All')">All</b-dropdown-item>
<b-dropdown-item v-for="c in categories" v-bind:key="c" #click="categoryChanged(c)">{{c}}</b-dropdown-item>
</b-dropdown>
</b-input-group>
</b-row>
<div class="row" v-for="i in Math.ceil(products.length / 3)" v-bind:key="i">
<div v-for="product in products.slice((i - 1) * 3, i * 3)" v-bind:key="product.id" class="col-md-4 col-6 my-1">
<b-card
v-bind:img-src="product.thumbUrl"
img-fluid
img-alt="image"
overlay>
<div slot="footer">
<small class="text-muted">{{product.name}}<br />{{product.price}} VND</small>
</div>
<router-link v-bind:to="{name: 'view-product', params: {product_id: product.product_id}}" class="secondary-content">
<i class="fa fa-eye"></i>
</router-link>
<router-link v-if="isEmployee" v-bind:to="{name: 'edit-product', params: {product_id: product.product_id}}" class="secondary-content">
<i class="fa fa-pencil"></i>
</router-link>
<button #click='addToCart(product)' class='button is-info'><i class="fa fa-cart-arrow-down"></i></button>
</b-card>
</div>
</div>
</div>
</template>
<script>
import firebaseApp from './firebaseInit'
import { mapActions } from 'vuex'
export default {
name: 'display',
data () {
return {
txtSearch: null,
isLoggedIn: false,
currentUser: false,
isEmployee: false,
products: []
}
},
beforeMount () {
var db = firebaseApp.firestore();
db.collection('products').get().then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'product_id': doc.id,
'article_number': doc.data().article_number,
'barcode': doc.data().barcode,
'category': doc.data().category,
'colour': doc.data().colour,
'description': doc.data().description,
'name': doc.data().name,
'name_ger': doc.data().name_ger,
'price': doc.data().price,
'size': doc.data().size,
'thumbUrl': doc.data().thumbUrl,
}
this.products.push(data)
})
})
}
},
methods: {
...mapActions(['addToCart']),
... many methods ...
}
}
</script>
How can I get rid of these errors?
There are two common reasons why this can happen:
Multiple Vue Locations
This can be due to contradictory locations of where you are importing Vue from, in different files, as others have said. So you might have both import Vue from 'vue' and perhaps import Vue from 'vue.runtime.esm' in your code, for example.
But this can result in multiple instances of Vue, which will cause these errors.
The solution in this case is to use import Vue from 'vue' everywhere in your code, and then alias it in your packaging system (webpack, Parcel, rollup etcetera). An example of this in webpack.config.js, or webpack.renderer.config.js if you're using Electron, would be:
module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
}
}
// ...
}
See more examples in the Vue documents.
White Listing
This can also be because of a need for Vue to be whitelisted as not one of the externals in webpack, for example.
It is worth noting that changes in Bootstrap Vue from 2.0 to a later version, definitely by 2.15 (and possibly earlier), caused this same problem to occur.
module.exports = {
// ...
externals: [
'fast-glob',
'jquery',
'bunyan',
'yaml',
'vue', // Remove this
'bootstrap-vue', // Remove this
// ...
}
After chasing this for an hour, I realized that a component that I had imported was also accessing Vue. At the top of that file was import Vue from 'vue/dist/vue.esm'. Every other file was simply doing import Vue from 'vue', which was the source of my double-import.
Different javascript packagers have different ways of resolving duplicates. For WebPack, the Resolve Configuration might be helpful in the case of dependencies importing different instances of Vue.
This was my case (https://stackoverflow.com/a/62262296/4202997) but I'll repeat it here to save you time: I was importing vue from a CDN . I simply removed the script and the problem was solved.
In my case the duplicated instances were caused by some Vue plugins importing the Vue instance differently than how I was doing in my project. I managed to fix it by adding the following to my Webpack config:
externals: {
// Stubs out `require('vue')` so it returns `global.Vue`
vue: 'Vue',
},
Hope it can help anyone struggling with the same issue :)