Vue warn Failed to resolve component: ion-icon - vue.js

Following the usage at https://ionicons.com/usage, the ion-icon displays but I get this warning:
Failed to resolve component: ion-icon
My steps were:
I used #vue/cli#4.5.11 to create a new app (vue create projectname)
added <ion-icon name="heart"></ion-icon> to HelloWorld.vue
added <script type="module" src="https://unpkg.com/ionicons#5.0.0/dist/ionicons/ionicons.esm.js"></script> to public/index.html
I've tried app.config.isCustomElement = tag => tag.startsWith('ion') which created another warning saying the option is only respected when using the runtime compiler, but I was able to suppress it by adding a vue.config.js with module.exports = {runtimeCompiler: true}. No effect on the ion-icon warning. This might be linked to needing to use a custom vue-loader but is there an easy way to get rid of this warning?

The full warning from using app.config.isCustomElement provides a useful clue:
The isCustomElement config option is only respected when using the runtime compiler. If you are using the runtime-only build, isCustomElement must be passed to #vue/compiler-dom in the build setup instead- for example, via the compilerOptions option in vue-loader: https://vue-loader.vuejs.org/options.html#compileroptions.
You could modify vue-loader's compilerOptions in vue.config.js to configure isCustomElement:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compilerOptions = {
...options.compilerOptions,
isCustomElement: tag => tag.startsWith('ion-')
}
return options
})
}
}

Related

Using Stencil components with Ionic Vue

In the Stencil docs section on framework integration with Vue it states the following:
In order to use the custom element library within the Vue app, the
application must be modified to define the custom elements and to
inform the Vue compiler which elements to ignore during compilation.
According to the same page this can be achieved by modifying the config of your Vue instance like this:
Vue.config.ignoredElements = [/test-\w*/];
This relates to Vue 2 however. With Vue 3 (which Ionic Vue uses) you have to use isCustomElement as stated here.
Regretably, I can’t for the life of me get Vue and Stencil to play nice. I have tried setting the config like this:
app.config.compilerOptions.isCustomElement = tag => /gc-\w*/.test(tag)
This causes Vue throw the following warning in the console:
[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.
- For vue-loader: pass it via vue-loader's `compilerOptions` loader option.
- For vue-cli: see https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-loader
- For vite: pass it via #vitejs/plugin-vue options. See https://github.com/vitejs/vite/tree/main/p
However, I have no idea how to implement any of the above suggestions using Ionic Vue. I have been messing around with chainWebpack in config.vue.js but without success so far.
Any help would be greatly appreciated.
I'm not an expert in Vue but here's how I did it:
Add the following to your ./vue.config.js (or create it if it doesn't exist):
/**
* #type {import('#vue/cli-service').ProjectOptions}
*/
module.exports = {
// ignore Stencil web components
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compilerOptions = {
...options.compilerOptions,
isCustomElement: tag => tag.startsWith('test-')
}
return options
})
},
}
This will instruct Vue to ignore the test-* components. Source: https://v3.vuejs.org/guide/web-components.html#skipping-component-resolution
Next, load the components in ./src/main.ts.
Import the Stencil project:
import { applyPolyfills, defineCustomElements } from 'test-components/loader';
Then replace createApp(App).use(router).mount('#app') with:
const app = createApp(App).use(router);
// Bind the custom elements to the window object
applyPolyfills().then(() => {
defineCustomElements();
});
app.mount('#app')
Source: https://stenciljs.com/docs/vue
Also, if anyone is using vite2+, just edit the vite.config.js accordingly:
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: tag => tag.startsWith('test-') // ✅ Here
}
}
}) ],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url))
}
}
})

Bundle a Vue-cli projet without Vuetify

I try to create some Vue libraries for internal use in our company.
As all of our projects use Vuetify, and our libraries expose some components that use it too, i don't want to bundle Vuetify in the libraries, but use the one installed with the "final" project.
I've look in the Webpack and Vue-cli documentation, and found the externals configuration key in webpack. But this vue.config.js file :
module.exports = {
configureWebpack: {
externals: {
vuetify: "commonjs2 vuetify",
},
},
chainWebpack: config => {
// These are some necessary steps changing the default webpack config of the Vue CLI
// that need to be changed in order for Typescript based components to generate their
// declaration (.d.ts) files.
//
// Discussed here https://github.com/vuejs/vue-cli/issues/1081
if (process.env.NODE_ENV === "production") {
config.module.rule("ts").uses.delete("cache-loader");
config.module
.rule("ts")
.use("ts-loader")
.loader("ts-loader")
.tap(opts => {
opts.onlyCompileBundledFiles = true;
opts.transpileOnly = false;
opts.happyPackMode = false;
return opts;
});
}
},
parallel: false,
};
Does'nt seems to works, as Vuetify is still in the bundle (And so, the weight of the output is BIG).
Since I don't want to load Vuetify multiple times... How can i achieve this ?

Configuring Vue and Webpack in Vuepress app

In my Vuepress project I would like to use v-runtime-template.
Their setup instruction says
You must use the with-compiler Vue.js version. This is needed in order to compile on-the-fly Vue.js templates. For that, you can set a webpack alias for vue to the vue/dist/vue.common file.
This could be achieved by adding
module.exports = {
runtimeCompiler: true
};
to vue.config.js, but I do not understand how to configure in Vuepress.
I tried this:
// .vuepress/enhanceApp.js
export default ({ Vue, options, router, siteData }) => {
Vue.config.runtimeCompiler = true
}
but it did not give any results.
How should the configuration be done?
From: https://github.com/vuejs/vuepress/issues/402#issuecomment-388169056
Add the following to your .vuepress/config.js:
chainWebpack(config) {
config.resolve.alias.set('vue', 'vue/dist/vue.common.js')
}
More info: https://vuepress.vuejs.org/config/#chainwebpack

How can I activate the sourcemap for Vue-Cli 4?

I believed the npm run serve command use the sourcemap by default for the js, but it seems not because I always see vue.runtime.esm.js:619.
I made a vue.config.js file at the root level project.
I try two things:
module.exports = {
configureWebpack: config => {
config.devtool = 'source-map'
}
}
and:
module.exports = {
configureWebpack: {
devtool: 'source-map'
}
}
None of them works. I still stuck with vue.runtime.esm.js:619 which is useless.
Does anyone know how really activate the source-map with vue-cli 4?
Using the generated vue.config.js from vue-cli v4 (generating a vue 3 project) It provided me this file:
// vue.config.js
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
})
I then modified it to this:
// vue.config.js
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
devtool: 'source-map',
}
})
Which works enough for me to enable VSCode debugging in Chrome/Electron.
*Edit
The error you are getting may be unrelated to source-maps and related to warnings from vue itself.
For example
runtime-core.esm-bundler.js:6584
[Vue warn]: Failed to resolve component: AMadeUpComponentName
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
at <MyView onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > >
at <RouterView>
at <App>
Unfortunately this is a limitation of vue. However, improvements have been made between VueJS v2 and v3. Finally, I couldn't find an original source, but I read that improving the warning messages to track down the cause of warnings and errors is a high priority feature.
* Edit 10/12/2022
I had an older project that this answer didn't solve at all. After a yarn upgrade and #vue/cli upgrading, this configuration began working again!
You are looking for the ProjectOptions chainWebpack property.
chainWebpack?: (config: ChainableWebpackConfig) => void;
Try the following in your vue.config.js file:
/** #type import('#vue/cli-service').ProjectOptions */
module.exports = {
// https://github.com/neutrinojs/webpack-chain/tree/v4#getting-started
chainWebpack(config) {
config.devtool('source-map')
},
}

VueJS build started throwing Error: Conflict: Multiple assets emit to the same filename

My app used to work fine until I updated VueJS this morning. Now when I build, it shows the following error:
Error: Conflict: Multiple assets emit to the same filename img/default-contractor-logo.0346290f.svg
There's only one file like this in the repo.
Here's my vue.config.js:
module.exports = {
baseUrl: '/my/',
outputDir: 'dist/my',
css: {
loaderOptions: {
sass: {
data: `
#import "#/scss/_variables.scss";
#import "#/scss/_mixins.scss";
#import "#/scss/_fonts.scss";
`
}
}
},
devServer: {
disableHostCheck: true
}
};
I tried webpack fixes recommended in similar cases, but non helped.
I had the same error when importing SVG files using dynamically generated path in the require statement:
const url = require("../assets/svg/#{value}");
<img src={{url}} />
In this case file-loader processes all SVG files and saves them to the output path. My file-loader options were:
{
loader: "file-loader",
options: { name: "[name].[ext]" }
}
The folders structure has duplicate file names, something like this:
assets
|__ one
|____ file.svg
|__ two
|____ file.svg
In this case file-loader saves both file.svg files to the same output file: build/assets/file.svg - hence the warning.
I managed to fix it by adding [path] to the name option:
{
loader: "file-loader",
options: { name: "[path][name].[ext]" }
}
The answer by #ischenkodv is definitely correct, but because of my inexperience with webpack, I needed a little more context to use the information to fix the problem.
For the benefit of anyone else in the same situation, I'm adding the following details which I hope will be useful.
This section of the Vue.js documentation was particularly helpul:
VueJS - Modifying Options of a Loader
For the TL;DR fix, here is the relevant chunk of my vue.config.js:
// vue.config.js
module.exports = {
// ---snip---
chainWebpack: config =>
{
config.module
.rule('svg')
.test(/\.svg$/)
.use('file-loader')
.tap(options =>
{
return { name: "[path][name].[ext]" };
});
}
// ---snip---
};
In my project it was the flag-icon-css NPM package that was causing the Multiple assets emit to the same filename conflict errors. The above update to the vue.config.js file resolved the problem for me.
I suspect that the regular expression in the test could be tightened up to target just the items in the flag-icon-css package rather than matching all SVG files, but I haven't bothered since it's not causing any adverse effects so far.