Vue svgs stopped working after upgrading vue-cli (vue-svg-loader) - vue.js

In our project we are using vue-svg-loader (latest version) with the following configuration file vue.config.js:
const svgRule = config.module.rule('svg')
svgRule.uses.clear()
svgRule
.use('babel-loader')
.loader('babel-loader')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader')
.options({
svgo: {
plugins: [{ removeViewBox: false }]
}
})
unfortunately after upgrading our #vue/cli-service 5.0.4 from #vue/cli-service 3.4.0
everything works but our svgs, which are not loading any more with the following error:
[Vue warn]: Invalid Component definition: /public/img/island-small.3fa8ec4c.svg found in <ZnLogin> at src/pages/login/login.vue
I tried playing with the versions, variety of configurations (mostly the default one) and nothing seems to work. I do wish to keep the current usage method:
<template>
<VueLogo/>
</template>
<script>
import VueLogo from './public/vue.svg';
export default {
name: 'Example',
components: {
VueLogo,
},
};
</script>
any idea?

Check out this issue.
https://github.com/visualfanatic/vue-svg-loader/issues/185
Changing the vue configuration worked for me.
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.module.rules.delete("svg");
config.module.rule("svg")
.test(/\.(svg)(\?.*)?$/)
.use("babel-loader")
.loader("babel-loader")
.end()
.use("vue-svg-loader")
.loader("vue-svg-loader");
},
};

Related

Vite vuetify plugin doesn't load components listed in external libraries

I am creating a library that wraps Vuetify 3 components. But when I try to use the library it gives the following error:
[Vue warn]: Failed to resolve component: v-btn If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
Library vite.config.ts :
import { fileURLToPath, URL } from 'node:url';
import { resolve } from 'node:path';
import { defineConfig } from 'vite';
import vue from '#vitejs/plugin-vue';
import vueJsx from '#vitejs/plugin-vue-jsx';
import vuetify from 'vite-plugin-vuetify';
export default defineConfig({
plugins: [
vue(),
vueJsx(),
// vuetify({ autoImport: true, styles: 'none' }), // Don't export vuetify
],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url)),
},
},
build: {
lib: {
entry: resolve(__dirname, 'src/main.ts'),
name: '#my/ui',
// the proper extensions will be added
fileName: 'my-ui',
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue', 'vuetify'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue',
vuetify: 'Vuetify',
},
},
},
},
});
Nuxt project nuxt.config.ts:
import { defineNuxtConfig } from 'nuxt';
import vuetify from 'vite-plugin-vuetify';
export default defineNuxtConfig({
css: ['#/assets/css/main.css'],
modules: [
async (options, nuxt) => {
nuxt.hooks.hook('vite:extendConfig', (config) =>
config.plugins.push(vuetify({ autoImport: true }))
);
},
],
build: {
transpile: ['#my/ui', 'vuetify'],
},
});
Nuxt project app.vue:
<template>
<v-app>
<v-main>
<HelloWorld label="Test" primary />
</v-main>
</v-app>
</template>
<script lang="ts" setup>
import { HelloWorld } from '#my/ui';
</script>
Nuxt project plugin vuetify.ts:
import 'vuetify/styles';
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
// components, if imported components getting resolved but treeshaking doesn't work.
// directives
});
nuxtApp.vueApp.use(vuetify);
});
Expected Behavior
Vuetify components from the Library project should be auto imported.
Current workaround:
If the vuetify components are imported in the parent project then the components are resolved. But this causes issue as the library users has to know what to import or import on global which is creating larger bundle size.
Is there an alternative way to implement and meet the following criteria:
Wrapping module doesn't depend on vuetify (Peer dep only)
Consuming app can auto import and get all of the benefits of tree shaking
Consuming app doesn't need to import any of the peer dependencies of the wrapping module.
Thank you so much in advance.
Just to create an answer for the workaround Sasank described:
If you just want to get rid of the error, import the components into the parent project as described in this link: https://next.vuetifyjs.com/en/features/treeshaking/#manual-imports

vite 2 production env ref element is undefined with compostion api

I use vue3 with composition api, but when I build my project, the ref element always undefined.
I reproduced it, maybe I used it incorrectly, but I don't know why.
I defined a ref in hooks function.
const isShow = ref(false)
const rootRef = ref<HTMLDivElement>();
export default function () {
function changeShow() {
isShow.value = !isShow.value;
console.log(isShow.value, rootRef.value);
}
return { isShow, rootRef, changeShow };
}
Use rootRef in the HelloWorld.vue and linked element.
<script setup lang="ts">
import useShow from "../composables/useShow";
const { rootRef, isShow } = useShow();
</script>
<template>
<div ref="rootRef" v-show="isShow" class="test"></div>
</template>
Create a button in App.vue and bind click function.
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
import useShow from "./composables/useShow";
const { changeShow } = useShow();
</script>
<template>
<button #click="changeShow">切换</button>
<HelloWorld />
</template>
When I click button, it works.
But when I build it and import from lib, it doesn't work.
My vite.config.ts is as follows:
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"#": path.resolve(__dirname, "src")
}
},
build: {
cssCodeSplit: true,
sourcemap: true,
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
name: "my-project",
fileName: format => `my-project.${format}.js`
},
rollupOptions: {
external: ["vue"],
preserveEntrySignatures: "strict",
output: {
globals: {
vue: "Vue"
}
}
}
}
});
I think the problem is the definition of rootRef. It seems that only binding location can use it. This is no different from defining it in a component. I need to use it in multiple places.
Oddly, in this way, the Dev environment works fine, but Pro env is not available. Do I need to modify the build configuration of vite.
How do I do that?
The problem is your App.vue uses its own copy of composables/useShow instead of the one from the lib.
The solution is to export the composable from the lib so that your app can use the same one:
// src/index.ts
import { default as useShow } from './composables/useShow';
//...
export default {
//...
useShow
};
In App.vue, use the lib's composable:
import MyProject from "../dist/my-project.es";
const { changeShow } = MyProject.useShow();
GitHub PR

Got error when testing vue-echarts component with Jest

I have problem with component testing when using 'vue-echarts'
InfoBoard.spec.ts
import { render } from '#testing-library/vue'
import InfoBoard from '#/components/InfoBoard.vue'
describe('InfoBoard', () => {
test('Should be truthy', () => {
const wrapper = render(InfoBoard, {
stubs: {
'v-charts': true
},
})
expect(wrapper).toBeTruthy()
})
})
InfoBoard.vue
<template>
<div>
<v-chart></v-chart>
</div>
</template>
<script>
import { defineComponent } from '#nuxtjs/composition-api'
import VChart from 'vue-echarts'
export default defineComponent({
components: {
VChart
},
setup() {}
})
</script>
jest.config.js
module.exports = {
moduleNameMapper: {
'^#/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js'
},
moduleFileExtensions: [
'ts',
'js',
'vue',
'json'
],
transform: {
"^.+\\.ts$": "ts-jest",
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue'
],
transformIgnorePatterns: [
"<rootDir>/node_modules/(?!echarts)",
"<rootDir>/node_modules/(?!echarts\/core)",
"<rootDir>/node_modules/(?!vue-echarts)"
],
testEnvironment: 'jsdom',
setupFilesAfterEnv: ["./jest-setup.js"]
}
Got Error:
FAIL components/InfoBoard.spec.ts
● Test suite failed to run
Jest encountered an unexpected token
Jest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.
Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.
By default "node_modules" folder is ignored by transformers.
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/configuration
For information about custom transformations, see:
https://jestjs.io/docs/code-transformation
Details:
/Users/admin/Documents/THIP/node_modules/echarts/core.js:20
export * from './lib/export/core';
^^^^^^
SyntaxError: Unexpected token 'export'
at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1479:14)
at Object.<anonymous> (node_modules/vue-echarts/dist/index.cjs.min.js:1:179)
I think the problem is in 'transformIgnorePatterns', maybe I write wrong patterns.
I searching for many day, I tried many anwser like change 'testEnviroment' or add plugin in .babelrc but don't found the solution.
I ran into the same problem and was just able to get it working by adding the following setting to my jest.config.js:
module.exports = {
transformIgnorePatterns: ["/node_modules/(?!(echarts|zrender)/)"],
}
If you wrote your configuration as provided here, I assume you wouldn't have to include the root directory in the ignore-pattern. It didn't work either when having more than one ignore-pattern; but this might be because of the way I wrote the ignore-pattern.

Vuetify VIcon doesn't show up in Storybook

I'm developing a Vue app with Vuetify and also document the components with Storybook.
I'm writing the stories nicely, all components seem to show up in Storybook (like my custom components & the Vuetify components too). Except for VIcon.
I have a component that uses Vuetify's VIcon, and I couldn't get the icon to show up (in the real app there's no problem with that).
The setup:
src/plugins/vuetify.js
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
Vue.use(Vuetify);
export default new Vuetify({
icons: {
iconfont: 'mdiSvg',
}
});
.storybook/vuetify_storybook.js
import Vue from 'vue';
import Vuetify from 'vuetify'; // loads all components
import 'vuetify/dist/vuetify.min.css'; // all the css for components
import config from '#/plugins/vuetify'; // basic config with theme
Vue.use(Vuetify);
export default new Vuetify(config);
.storybook/preview.js
import { addDecorator } from '#storybook/vue';
import vuetify from './vuetify_storybook';
addDecorator(() => ({
vuetify,
template: `
<v-app>
<story />
</v-app>
`,
}));
.storybook/main.js
const path = require('path');
module.exports = {
stories: [
'../stories/**/*.stories.js',
'../src/**/*.stories.js'
],
addons: [
'#storybook/addon-actions',
'#storybook/addon-links',
'#storybook/addon-knobs',
'#storybook/addon-storysource'
],
webpackFinal: async (config, { configType }) => {
config.resolve.extensions.push('.vue', '.css', '.less', '.scss', '.sass', '.html')
// Use Sass loader for vuetify components
config.module.rules.push({
test: /\.sass$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../'),
});
config.module.rules.push({
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
additionalData: "#import '#/styles/variables.scss';"
}
}
],
});
config.module.rules.push({
resolve: {
alias: {
'#': path.resolve(__dirname, '../src'),
vue: 'vue/dist/vue.js',
'vue$': 'vue/dist/vue.esm.js',
},
},
});
// Return the altered config
return config;
},
};
CustomVIcon.stories.js
import { withKnobs } from '#storybook/addon-knobs'
export default {
title: 'Display that icon',
decorators: [withKnobs]
}
export const displayIcon = () => {
return {
template: `<v-icon>mdi-alert</v-icon>`
}
}
If I add a text that is not an mdi icon (like <v-icon>notmditext</v-icon>, then the text is displayed - but as soon as I add a - (dash/minus sign) to the string, it doesn't show up.
I can see the icon's HTML (well, part of it) in the console, only the ::before part is missing (that should be the actual icon). So styles are set, classes are added, etc when I inspect the Storybook page (where the icon should be).
Already tried adding https://www.npmjs.com/package/storybook-addon-jsx (as in the real case the component is rendered with JSX), nothing changed (no v-icon)
Already tried putting other components in the story (like VCard), and they showed up (and other stories work just perfectly)
Vue is 2.6.12, Vuetify 2.3.10, #storybook/vue 6.0.21 - so quite fresh
Also tried to import components from vuetify/lib (and not just vuetify) in the .storybook/vuetify_storybook.js & registering them locally (in the preview.js and the story file - no change)
OK, just needed another view on the things:
removed the link to the Material design icons CDN:
// remove this from public/index.html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#mdi/font#latest/css/materialdesignicons.min.css">
changed the package from #mdi/js to #mdi/font
npm remove #mdi/js
npm install #mdi/font -D
imported the corresponding CSS in two places:
// add this to src/main.js & .storybook/vuetify_storybook.js
import '#mdi/font/css/materialdesignicons.css';
changed the Vuetify config
// in src/plugins/vuetify.js
icons: {
// iconfont: 'mdiSvg', // change this
iconfont: 'mdi', // to this
},
AND VOILÁ! VIcon shows up.
So, the problem was that I thought everything had been set up correctly, but it wasn't the case: the icons in the app were coming from the CDN (have not looked at the Network tab), and when I removed the CDN link from the index.html it immediately became apparent.
More on setting up the icons in Vuetify: Install Material Design Icons

How to have Vue CLI-generated project replace image srcs when the attribute is not src

Created a project using Vue CLI 3.7.0 and installed bootstrap-vue 2.0.0-rc.19. Vue CLI scaffolded projects use Webpack which uses file-loader.
When running the server locally, <img src='../assets/images/test.jpg'> gets replaced by <img src='/img/test.4d111941.jpg'>.
Using a BootstrapVue directive, <b-carousel-slide img-src='../assets/images/test.jpg'> does not result in a cache-busted URL.
Anyone run into this? Wondering if I have to override some Webpack behavior in vue.config.js.
Needed to add this to vue.config.js:
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options['transformAssetUrls'] = {
img: 'src',
image: 'xlink:href',
'b-img': 'src',
'b-img-lazy': ['src', 'blank-src'],
'b-card': 'img-src',
'b-card-img': 'img-src',
'b-card-img-lazy': ['src', 'blank-src'],
'b-carousel-slide': 'img-src',
'b-embed': 'src'
}
return options
})
}
}