Vue 3 Components Not Loading - vue.js

I've spent the last 5 hours trying to figure out what's not working with my setup.
What I basically want to do is have a "wrapper" app that loads my common codebase (which is a Vue component).
App.js
import { createApp } from "vue";
import AppWrapper from "#src/js/AppWrapper.vue";
import Router from "#common/libraries/Router.js";
const vm = createApp(AppWrapper);
vm.use(Router);
vm.mount("#app");
AppWrapper.vue
<template>
<div>
<app></app>
</div>
</template>
<script>
import App from "#common/App.vue";
export default {
created() {},
components: {
App,
},
};
</script>
<style lang="scss" scoped></style>
App.vue
<template>
<div>
<h1>Ok</h1>
</div>
</template>
<script>
export default {
created() {},
};
</script>
Somehow, the app tag isn't replaced and my component is not loading in the page.
Here's the webpack file:
const Webpack = require("webpack");
const path = require("path");
const { VueLoaderPlugin } = require("vue-loader");
const LiveReloadPlugin = require("webpack-livereload-plugin");
module.exports = (env) => {
return {
entry: {
app: ["./app/src/common/App.js"],
},
output: {
path: path.resolve(__dirname, "public/"),
filename: "js/[name].js",
sourceMapFilename: "js/[name].js.map",
},
resolve: {
alias: {
"#src": path.resolve(__dirname, "app/src/"),
"#common": path.resolve(__dirname, "app/src/common/"),
},
},
module: {
rules: [
{
test: /\.vue$/,
use: ["vue-loader"],
},
],
},
watchOptions: {
aggregateTimeout: 300,
poll: 500,
ignored: /node_modules/,
},
plugins: [new VueLoaderPlugin(), new LiveReloadPlugin()],
};
};
Am I missing something?
Thanks!

Alright, I figured it out. Vue was loaded twice, once in my app package.json and once in the common sources. Removing it from one location worked!

Related

Load SVGs components in storybook VUE not working

Hello everyone I'm using vue 3 with storybook 6.5.16 and when i import the SVGs as a component using svg-inline-loader i get the following error in storybook app:
enter image description here
(Failed to execute 'createElement' on 'Document' svg is not a valid name)
Storybook main.js
const path = require('path');
module.exports = {
stories: [
'../src/**/*.stories.mdx',
'../src/**/*.stories.#(js|jsx|ts|tsx)',
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
],
framework: '#storybook/vue3',
core: {
builder: '#storybook/builder-webpack5',
},
webpackFinal: async (config, { configType }) => {
// `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: "sass-loader",
options: {
additionalData: `
#import "#/assets/scss/main.scss";
`,
implementation: require('sass'),
},
},
],
});
(() => {
const ruleSVG = config.module.rules.find(rule => {
if (rule.test) {
const test = rule.test.toString();
const regular = /\.(svg|ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
const regularString = regular.toString();
if (test === regularString) {
return rule;
}
}
});
ruleSVG.test = /\.(ico|jpg|jpeg|png|apng|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/;
})();
config.module.rules.push({
test: /\.svg$/,
use: ['svg-inline-loader'],
});
config.resolve.alias['#'] = path.resolve('src');
return config;
},
}
package.json file
enter image description here
SVG Vue components
<template>
<div
ref="icon"
class="v-icon"
#click="onClick"
>
<component
:is="iconName"
class="v-icon__svg"
/>
</div>
</template>
<script>
import Cards from '#/assets/icons/Cards.svg';
export default {
name: 'VIcon',
components: {
Cards,
},
props: {
iconName: {
type: String,
required: true,
},
},
};
</script>
.babelrc file
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
i tried to use vue-svg-loader to replace svg-inline-loader but it didn't work and I got another error while building the app
ModuleBuildError: Module build failed: Error: Cannot find module './Block'
I also tried to use babel-loader in conjunction with vue-svg-loader but unfortunately I also got an error:
enter image description here
has anyone come across this or can you show your use cases of using SVGs components in Storybook and Vue 3?

How to use Environment Variables inside Vue3+Vite component library?

I have created a component as part of my component library that I am building with Vue3 and Vite. Everything works well, except when I try to use environment variables. I want the app that consumes this component library to be able to provide the component with environment specific data.
I have played around and found that if I have a .env file as part of the component library project, I am able to access those variables, but I want to be able to provide that during runtime and not during build time.
Here is my vite.config.ts
import { defineConfig } from "vite";
import { resolve } from "path";
import vue from "#vitejs/plugin-vue";
import dts from "vite-plugin-dts";
export default ({ mode }) => {
return defineConfig({
optimizeDeps: {
exclude: ["vue-demi"],
},
plugins: [
vue(),
dts({
insertTypesEntry: true,
}),
],
server: {
open: true,
},
build: {
lib: {
entry: resolve(__dirname, "src/lib.ts"),
name: "complib",
fileName: "complib",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
exports: "named",
},
},
},
});
};
The entry looks like:
import { App, install } from "vue-demi";
import TestComp from "./components/TestComp.vue";
import "./tailwind.css";
install();
export default {
install: (app: App) => {
app.component("TestComp", TestComp);
},
};
export { Header };
And here is a minimal component TestComp.vue:
<script setup lang="ts">
import { onMounted } from "vue";
onMounted(() => {
console.log(import.meta.env.VITE_TEST_VAR);
});
</script>
<template>
<span>Test Comp</span>
</template>

Using vue slots in library gives currentRenderingInstance is null

I am creating a Vue component library with Rollup, but when I use slots it gives me the following error:
Uncaught (in promise) TypeError: currentRenderingInstance is null
I made a very simple component in my library:
<script setup></script>
<template>
<button>
<slot></slot>
</button>
</template>
<style scoped></style>
Then I simply use it like this:
<ExampleComponent>
Text
</ExampleComponent>
If I remove the slot and replace it with a prop or hard-coded text, everything works fine.
This is my rollup.config.js:
import { defineConfig } from 'rollup';
import path from 'path';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import vue from 'rollup-plugin-vue';
// the base configuration
const baseConfig = {
input: 'src/entry.js',
};
// plugins
const plugins = [
vue(),
resolve({
extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
}),
// process only `<style module>` blocks.
postcss({
modules: {
generateScopedName: '[local]___[hash:base64:5]',
},
include: /&module=.*\.css$/,
}),
// process all `<style>` blocks except `<style module>`.
postcss({ include: /(?<!&module=.*)\.css$/ }),
commonjs(),
];
const external = ['vue'];
const globals = {
vue: 'Vue',
};
export default [
// esm
defineConfig({
...baseConfig,
input: 'src/entry.esm.js',
external,
output: {
file: 'dist/vue-my-lib.esm.js',
format: 'esm',
exports: 'named',
},
plugins,
}),
// cjs
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.ssr.js',
format: 'cjs',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
// iife
defineConfig({
...baseConfig,
external,
output: {
compact: true,
file: 'dist/vue-my-lib.min.js',
format: 'iife',
name: 'VueMyLib',
exports: 'auto',
globals,
},
plugins,
}),
];
Any idea about the problem?
After a whole day of searching, I found the solution (here and here). It's a problem with using a library locally (e.g., through npm link) where it seems there are two instances of Vue at the same time (one of the project and one of the library). So, the solution is to tell the project to use specifically its own vue through webpack.
In my case, I use Jetstream + Inertia, so I edited webpack.mix.js:
const path = require('path');
// ...
mix.webpackConfig({
resolve: {
symlinks: false,
alias: {
vue: path.resolve("./node_modules/vue"),
},
},
});
Or if you used vue-cli to create your project, edit the vue.config.js:
const { defineConfig } = require("#vue/cli-service");
const path = require("path");
module.exports = defineConfig({
// ...
chainWebpack(config) {
config.resolve.symlinks(false);
config.resolve.alias.set("vue", path.resolve("./node_modules/vue"));
},
});
Thanks to #mikelplhts
On vite + esbuild I used:
export default defineConfig({
...
resolve: {
alias: [
...
{
find: 'vue',
replacement: path.resolve("./node_modules/vue"),
},
],
},
...

Dependency not found - Vue Js

I have recently added axios to a file called services.js so it's better organised. This file is on my root folder.
#/services.js
import axios from "axios";
const axiosInstance = axios.create({
baseURL: " server url here",
});
export const api = {
get(endpoint) {
return axiosInstance.get(endpoint);
},
post(endpoint, body) {
return axiosInstance.post(endpoint, body);
},
};
Then I have a component called Post.vue in my view folder:
<template>
<section>
<div>
<ul></ul>
</div>
</section>
</template>
<script>
import { api } from "#/services.js";
export default {
name: "Post",
props: ["id"],
data() {
return {
post: null,
};
},
methods: {
getPost() {
api.get(`/post/${this.id}`).then(response => {
this.post = response.data;
console.log(this.post);
});
},
},
created() {
this.getPost();
},
};
</script>
<style></style>
I also have a router.ts file with all my routes:
import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import Home from "../views/Home.vue";
import Podcasts from "../views/Podcasts.vue";
import Post from "../views/Post.vue";
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{
path: "/",
name: "home",
component: Home,
},
{
path: "/podcasts",
name: "podcasts",
component: Podcasts,
},
{
path: "/post/:id",
name: "post",
component: Post,
props: true,
},
],
});
export default router;
It's giving me a dependency error like #/services.js did not exist.
Unsure what's wrong at this stage.
Thanks a lot in advance for helping out
In a standard Vue CLI project, the # symbol resolves to /src
If your file is in the root of your project try
import { api } from '#/../services'
But personally, I'd move it into src
You can check the Webpack configuration using
vue inspect
Look for the resolve.alias rules.
Check your webpack configuration, depends on the version of webpack you have, there should be an alias # like this:
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
"#": path.resolve(__dirname) // check the path here
}
}
};
Or if you are using vue.config.js
configureWebpack: {
name: name,
resolve: {
alias: {
'#': path.resolve(__dirname)// check the path here
}
}
},
Make sure the path is correctly set up. You mentioned you have another project working fine, which makes it a good reference.

Writing Unit test for project in Nuxt, Vue, jest & Vuetify

TL;DR
Unit Test for component copied from Vuetify link are passing but my actual unit test for my component written in pug is not passing.
Details:
I am working on a project which is built using Vue, NUXT, Vuetify and pug as template language. I am configuring the project to write test cases with JEST test runner. The unit test is currently failing and I would need some steps to identify the problem.
I have read through following:
https://vue-test-utils.vuejs.org/guides/#getting-started
https://vuetifyjs.com/en/getting-started/unit-testing/
Following versions are in use:
nuxt: ^2.0.0
nuxtjs/vuetify: ^1.10.2
pug: ^2.0.4
pug-plain-loader: ^1.0.0
jest: ^24.1.0
vue-jest: ^4.0.0-0
Following is the relevant folder structure
<project root>/jest.config.js
<project root>/components/common/CustomCard.vue
<project root>/components/common/MessageDialog.vue
<project root>/tests/unit/components/common/TestMessageDialog.spec.js
<project root>/tests/unit/components/common/TestCustomCard.spec.js
Following is are seemingly relevant parts of the configurations:
jest.config.js
module.exports = {
verbose: true,
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: ['js', 'vue', 'json'],
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
'collectCoverage': false,
'collectCoverageFrom': [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
],
globals: {
'vue-jest': {
pug: {
doctype: 'html'
}
}
},
preset: '#vue/cli-plugin-unit-jest/presets/no-babel'
}
TestMessageDialog.spec.js
import {
mount,
createLocalVue
} from '#vue/test-utils'
import Vuetify from 'vuetify'
import MessageDialog from '#/components/common/MessageDialog.vue'
describe('MessageDialog.vue', () => {
const sampleData = {
titleText: 'title text with unique id : 2020.03.12.00'
}
let wrappedMessageDialog
beforeEach(() => {
const vuetify = new Vuetify()
const localVue = createLocalVue()
wrappedMessageDialog = mount(
MessageDialog,
{
localVue,
vuetify,
propsData: sampleData
}
)
})
it('renders correctly when passed props', () => {
expect(
wrappedMessageDialog
.find({ name: 'v-card-title' })
.text()
).toMatch(sampleData.titleText)
})
})
MessageDialog.vue
<template lang="pug">
v-dialog(v-model="isVisible" width="600")
v-card
v-card-title {{ titleText }}
</template>
<script>
export default {
props: {
titleText: {
default: '',
type: String
}
}
}
</script>
I am getting following error
FAIL tests/unit/components/common/TestMessageDialog.spec.js
[vue-test-utils]: find did not return Component, cannot call text() on empty Wrapper
31 | wrappedMessageDialog
32 | .find({ name: 'v-card-title' })
> 33 | .text()
| ^
34 | ).toMatch(sampleData.titleText)
35 | })
36 | })
at throwError (node_modules/#vue/test-utils/dist/vue-test-utils.js:1709:9)
at ErrorWrapper.text (node_modules/#vue/test-utils/dist/vue-test-utils.js:8767:3)
at Object.it (tests/unit/components/common/TestMessageDialog.spec.js:33:10)
console.error node_modules/vue/dist/vue.common.dev.js:630
[Vue warn]: Unknown custom element: <v-dialog> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <Anonymous>
<Root>
Similar warnings for <v-dialog>, <v-card> & <v-card-title>
Looks like you will want to register the components in the MessageDialog component. E.g.
<script>
import Foo from './Foo.vue;
...
export default {
components: { Foo }
...
}
...
</script>
More info: https://v2.vuejs.org/v2/guide/components-registration.html#Local-Registration