I get this warning in my Chrome Console:
runtime-core.esm-bundler.js?d2dd:38 [Vue warn]: The `compilerOptions` config option is only respected when using a build of Vue.js that includes the runtime compiler (aka "full build"). Since you are using the runtime-only build, `compilerOptions` must be passed to `#vue/compiler-dom` in the build setup instead.
and then this warning:
[Vue warn]: Failed to resolve component: amplify-s3-image
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
But the component actually works, since it shows the image from S3 how it's supposed to.
This is what my main.js looks like:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import Amplify from "aws-amplify";
import AmplifyVue from '#aws-amplify/ui-vue';
import store from './store'
import awsconfig from './aws-exports';
import aws_exports from './aws-exports';
import { applyPolyfills, defineCustomElements } from '#aws-amplify/ui-components/loader';
Amplify.configure(awsconfig);
//Amplify.configure(aws_exports);
applyPolyfills().then(() => {
defineCustomElements(window);
});
const app = createApp(App).use(router).use(store).use(AmplifyVue)
app.config.compilerOptions.isCustomElement = tag => tag.startsWith('amplify-');
app.mount('#app');
and this is in my vue.config.js:
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
},
)
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].title = "Opensquare";
return args;
},options => {
options['compilerOptions'] = {
...options.compilerOptions || {},
isCustomElement: tag => tag.startsWith('amplify-')
}
return options;
})
}
}
What am I doing wrong? It's not blocking, since the component actually works, but reading the Console with this WARN popping up is a nightmare.
Related
I'm using Vuejs 3, vuerouter 4 and pinia and trying to put a navigation guard in some routes, as per the example in the documentation (if a user is not authenticated and is not on the login page, send the user to login page to get authenticated). This is explained also in pinia documentation on use of pinia outside of components. But I can't get my head around it.
The store I use is currently simple (return false or true on isAuthenticated):
//authStore.js
import { defineStore } from "pinia";
export const useAuthStore = defineStore( 'AuthStore', {
state: () => {
return {
isAuthenticated: false
}
}
})
I want to use this isAuthenticated in a beforeEnter in routes/index.js
In main.js:
import { useAuthStore } from '#/stores/authStore'
import { createApp } from 'vue'
import App from './App.vue'
import router from '#/router'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia()).use(router)
app.mount('#app')
// I'm not using authStore in this file, so this raises an error:
const authStore = useAuthStore()
And in router/index.js:
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
// path for login page,
{
path: '/adm/home',
name: 'AdmView',
component: () => import('#/views/adm/AdmView.vue'),
beforeEnter: (to) => {
// error: authStore is not defined
const isAuthenticated = authStore
if ( !isAuthenticated && to.name !== 'login-adm' ) {
return { name: 'login-adm' }
}
}
},
// other paths
]
Your authStore.js exports useAuthStore as expected, but you do not call it as required.
authStore is not defined because authStore is the filename of your auth store -- instead you should be executing the function useAuthStore exported from that file:
const authStore = useAuthStore();
console.log('Is authenticated?', authStore.isAuthenticated);
I don't know if it is the main issue but u forgot to use a destructor on userStore doing
const isAuthenticated = authStore
It supposed to be
const { isAuthenticated } = toRefs(authStore);
toRefs to preserve reactivity after passing. It can be imported as
import { toRefs } from 'vue';
I'm developing some tests for single file components in VueJs. These components use font-awesome.
This is my App, as you can see I have fontawesome available for all child components.
import { createApp } from 'vue';
import App from './App.vue';
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome';
import { fas } from "#fortawesome/free-solid-svg-icons";
import { library } from '#fortawesome/fontawesome-svg-core';
library.add(fas);
createApp(App)
.component("font-awesome-icon", FontAwesomeIcon)
.mount('#app');
Here's a test
import { mount } from '#vue/test-utils'
import ListComponent from '#/components/ListComponent.vue'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome';
let someData = [{
name: 'Some person name',
key: '2222222',
moreInfo: [
{title: 'aa'},
{title: 'bb'},
]
},
{
name: 'Some other person name',
key: '12321123,
moreInfo: [
{title: 'cc'},
{title: 'x'},
]
},
}];
let wrapper = mount(ListComponent, {
propsData: {
someData
},
stubs: {
'font-awesome-icon': FontAwesomeIcon
}
});
describe('ListadoImputados.vue', () => {.... tests ....});
Test details are not important, I don't know how to add / include font-awesome-icon in the context so i can avoid getting the following warnings
console.warn node_modules/#vue/runtime-core/dist/runtime-core.cjs.js:40
[Vue warn]: Failed to resolve component: font-awesome-icon
I tried adding this dependency as a mock and stub but no luck. Also importing Fontawesome at the top of the file does not work, the warning is still showing. I was thinking maybe in creating a vue app in the test file and inject the component like this
createApp(App)
.component("font-awesome-icon", FontAwesomeIcon)
.mount('#app');
but I'm copying and pasting code and I'm not sure this is the right way.
Is there a way to add this dependencies to my test context?
I'm using Vue 3, vue-test-utils + jest
In Vue Test Utils v2 (for Vue 3), the stubs mounting option is moved into global.stubs. Also note that a stub does nothing by definition, so stubbing the component only requires providing the component name.
Your mounting options should look like this:
const wrapper = mount(ListComponent, {
global: {
stubs: ['FontAwesomeIcon']
}
})
If for some reason you need the actual component, you could technically provide the component definition as a "stub", but you'd also need to initialize the icons for it as you would in the app's startup:
// assume only `faUserSecret` icon used in `ListComponent`
import { library } from '#fortawesome/fontawesome-svg-core'
import { faUserSecret } from '#fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/vue-fontawesome'
library.add(faUserSecret)
//...
const wrapper = mount(ListComponent, {
global: {
stubs: { FontAwesomeIcon }
}
})
I tried this but only got an error message
This relative module was not found:
* ./router in ./store/index.js
// Ran with yarn dev
import router from './router'
export const state = () => ({
authenticated: false,
})
export const mutations = {
toggleLogin(state, loginStatus, path) {
state.authenticated = loginStatus
if (loginStatus) {
router.push(path)
} else {
router.push('login')
}
},
}
My store path is store/index.js
Vuex mutations and getters doesn't have access to the Vue context. Only actions does.
Also, you can't import the Nuxt router like that. What's that file you're trying to import?
I'd suggest to make an action instead:
export const actions: {
toggleLogin({ commit }, payload) {
this.app.router.push('') //exists
}
}
I'm looking for way to make the same logic of require.context of webpack in vitejs, I've found this plugin named vite-plugin-import-context, I tried it out but there's something that I didn't understand which is import dynamicImport from '../src/index' in the basic usage :
import { UserConfigExport } from 'vite';
import vue from '#vitejs/plugin-vue';
import dynamicImport from '../src/index';// <-- this is not described
export default (): UserConfigExport => {
return {
plugins: [vue(), dynamicImport(/*options*/)],
};
};
require should never be used in source code when using Vite. It's ESM only.
For Vite v2, import.meta.globEager can be used.
For Vite >v2, import.meta.globEager is deprecated. Use import.meta.glob('*', { eager: true }) instead.
import.meta.glob() is webpack alternative of require.context() . It has been added in vite since v2.3.4 .
Here is a link to the doc https://vitejs.dev/guide/features.html#glob-import
Yep, that example is directly taken from examples folder in the repo so it works only in that repo.
If you install the plugin via npm or yarn, the line should look like import dynamicImport from 'vite-plugin-import-context'
Here is how I import all the plugins/modules:
main.ts
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
// styles here
import '#/assets/styles/tailwind.css';
import '#/assets/styles/main.scss';
// install all modules under `modules/`
Object.values(
import.meta.glob<{ install: (ctx: any) => void }>('/src/modules/*.ts', { eager: true })
).forEach((module) => module.install?.(app));
app.mount('#app');
and here is how I keep things ready in my modules folder to export:
modules/pinia.ts
import { createPinia } from 'pinia';
export const install = (app: any) => {
app.use(createPinia());
};
modules/router.ts
import type { RouteRecordRaw } from 'vue-router';
import { createRouter, createWebHashHistory } from 'vue-router';
import generatedRoutes from '~pages';
import { setupLayouts } from 'virtual:generated-layouts';
const routes: RouteRecordRaw[] = setupLayouts(generatedRoutes);
const router = createRouter({
history: createWebHashHistory(),
routes,
});
export const install = (app: any) => {
app.use(router);
};
I have a Vue application that uses used Vue Analytics, which creates a this.$ga.page method to do page tracking. Now, I need to test my component, using Jest, but it says this.$ga.page is not defined. I'm initializing Vue Analytics in main.js.
How do I include main.js before the component in the test file? I know we need to add this in a beforeEach method, but I don't know exactly how to do that.
Vue Analytics init in main.js
import VueAnalytics from 'vue-analytics'
Vue.use(VueAnalytics, {
id: 'UA-150437966-1'
})
My Homepage test
import { mount } from '#vue/test-utils'
import Homepage from '../../src/Pages/Homepage'
describe('Homepage', () => {
const wrapper = mount(Homepage)
it('has a button', () => {
expect(wrapper.contains('button')).toBe(true)
})
})
Homepage.vue excerpt
created: function() {
//analytics
this.$ga.page({
page: "/",
title: "Home page",
location: window.location.href
});
}
};
Error I'm getting
Homepage › encountered a declaration exception
TypeError: Cannot read property 'page' of undefined
67 | //analytics
68 |
> 69 | this.$ga.page({
Vue Test Utils recommends setting up your plugins in a localVue to avoid polluting the global Vue. This is what it would look like:
import { localVue, mount } from '#vue/test-utils'
import Homepage from '#/components/Homepage'
localVue.use(VueAnalytics, { id: 'UA-150437966-1' })
describe('Homepage', () => {
let wrapper = null
beforeEach(() => {
wrapper = mount(Homepage, {
localVue,
})
})
// ...
})
On the other hand, if it doesn't matter in your tests that the global Vue is modified, you could setup your Jest 23.x environment with setupTestFrameworkScriptFile:
// jest.config.js
module.exports = {
setupTestFrameworkScriptFile: '<rootDir>/tests/jest-setup.js',
}
And in your setup file, you could initialize Vue Analytics:
// <rootDir>/tests/jest-setup.js
import Vue from 'vue'
import VueAnalytics from 'vue-analytics'
Vue.use(VueAnalytics, {
id: 'UA-150437966-1'
})