Get Vuetify icons to work when loading page from filesystem - javascript

I have a vue project created with vue cli 3 and i am using Vuetify v2.0.19.
My project requires me to be able to build the project and output a single html file so that it can be downloaded and ran offline in a phonegap app(safari v13). I am able to meet all the requirements and get my project to show up in the phonegap app but the icons do not render. For example, where I use <v-icon>info</v-icon> it will render INFO, etc.
I have followed the Vuetify Quick-Start, Icons and Browser Support pages and several other Stack Overflow threads answers but can not get my icons to render.
I basically need the fonts included in my single file. When I load the page in the phonegap app or when serving from filesystem I get 'not found' errors in the console (file:///D:/fonts/materialdesignicons-webfont.27cb2cf1.woff2) I am aware the path is wrong but how can I get the icons to be part of the build?
Is this possible?
To get the single html file with js and css I added the npm packages html-webpack-plugin and html-webpack-inline-source-plugin and in my vue.config.js I have the following:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
module.exports = {
css: {
extract: false,
},
configureWebpack: {
optimization: {
splitChunks: false
},
plugins: [
new HtmlWebpackPlugin({
filename: 'output/output.html',
template: 'src/output-template.html',
inlineSource: '.(js|css)$' // embed all javascript and css inline
}),
new HtmlWebpackInlineSourcePlugin()
]
},
transpileDependencies:[/node_modules[/\\\\]vuetify[/\\\\]/]
}
and in src/plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import '#mdi/font/css/materialdesignicons.css'
Vue.use(Vuetify)
export default new Vuetify({
icons: {
iconfont: 'mdi',
}
})

Finally figure out how to get this working how I needed it using the method described here.
// plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
Vue.use(Vuetify)
export default new Vuetify({
icons: {
iconfont: 'mdiSvg'
}
})
And in the components that I am using the icons (using the mdi information icon for example)
<template>
...
<v-icon>{{svgPath}}</v-icon>
...
</template>
<script>
import {mdiInformation} from '#mdi/js'
export default {
...
data() {
return {
svgPath: mdiInformation
}
}
}
</script>

Related

How to make Vue and Vite work with web components?

I want to migrate my Vue 2 project from webpack to Vite.
And have to use 3rd party web components that built with lit-element.
Those components throws errors during the runtime (by vue):
Unknown custom element: < foo-component > - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
And also (by lit-element)
Failed to set the 'adoptedStyleSheets' property on 'ShadowRoot':
Failed to convert value to 'CSSStyleSheet'.
As far as I can see those 3rd party web components do only this in theirs index files (inside node_modules):
import FooComponent from './FooComponent';
customElements.define('foo-component', FooComponent);
So before (with webpack setup) I just imported them and everything used to work. Well, actually for webpack lit-scss-loader was used also for those components.
I assume that Vite perhaps needs some additional configuration, or maybe something similar to "webpack" loader is needed here, but not sure what direction I have to move.
What I'm doing wrong?
Configure #vite/plugin-vue to ignore Lit elements, e.g., elements starting with my-lit in their registered name:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
vue({
template: {
compilerOptions: {
// treat all components starting with `my-lit` as custom elements
isCustomElement: tag => tag.startsWith('my-lit'),
},
},
}),
],
})
demo
A couple of steps needed.
Imagine I have 3rd party webcomponents named "foo". So all of them are in node_modules/#foo.
I need to do these steps:
Tell Vite that all components starting with "foo-" are webcomponents.
isCustomElement: (tag) => tag.startsWith('foo-')
Add "postcssLit" plugin to help vite to prepare css for the webcomponents.
Tell to Vite how to threat css paths for webcomponents.
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
Here is the full config:
//vite.config.ts
import postcssLit from 'rollup-plugin-postcss-lit';
export default defineConfig({
plugins: [
vue(
{
template: {
compilerOptions: {
// 1. Tell Vite that all components starting with "foo-" are webcomponents
isCustomElement: (tag) => tag.startsWith('foo-')
}
}
}
),
vueJsx(),
// 2. This "postcssLit" plugin helps to make css for the webcomponents
postcssLit()
],
resolve: {
alias: {
// 3. Tell to Vite how to threat css paths for webcomponents
'~#foo': fileURLToPath(new URL('./node_modules/#foo', import.meta.url))
}
}
});

SVG Images not showing if Vue app is converted to Electron app

I built an Vue 3 app (+ Vite) which I want to also convert to an Electron app. Every time I start the Electron app via electron . it looks like the SVG isn't getting packaged: (Navigation Drawer with missing icons)
Upon further investigation this is the case, but in my dist folder all images are available. (SVGs are in the dist folder) But the Devtools show that they don't get into the Electron app. (Electron app asset folder)
I also implemented the workaround for changing the base path in the Vite config like this (The Electron ENV gets set before I run electron . via a npm script):
import { fileURLToPath, URL } from "url";
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
base:
// eslint-disable-next-line no-undef
process.env.ELECTRON == "true" ? path.resolve(__dirname, "./dist/") : "./",
plugins: [vue()],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
assetsInclude: ["**/*.svg"],
});
Does anyone have an idea what the problem might be? Thanks in advance!
UPDATE
I got it working after all by following this example: https://github.com/pengYYYYY/vite-electron. Also a base tag was missing in my index.html.
Like that: <base href="./" />

How to use vue-tel-input-vuetify in Nuxt?

I have been trying to use vue-tel-input-vuetify in Nuxt and I have been having the issue as it is in the image below, I have also tried all the solutions in this link Github but I get the same error.
After installation, I created a plugin file plugins/vue-tel-input-vuetify.js and added the following code to it.
import Vue from 'vue'
import VueTelInputVuetify from 'vue-tel-input-vuetify'
Vue.use(VueTelInputVuetify)
After that, I added this to nuxt.config.js
plugins: [
'~/plugins/vue-tel-input-vuetify',
{ src: '~/plugins/vue-google-charts', mode: 'client' }
]
Between my component's script tags, I did this:
import { VueTelInputVuetify } from 'vue-tel-input-vuetify'
export default {
components: {
VueTelInputVuetify,
},
...
And between my component's template tags I added this:
<VueTelInputVuetify
ref="phoneInput"
v-model="phoneNumber"
hint="Enter your phone number..."
:rules="phoneNumberRules"
placeholder=""
label="Phone"
:required="true"
:validate-on-blur="true"
:input-options="{showDialCode: true, tabIndex: 0}"
:valid-characters-only="true"
mode="international"
/>
Updated answer
I've tried it myself, working perfectly fine with:
Nuxt at 2.15.7
#nuxtjs/vuetify at 1.12.1 (vuetify at 2.5.7)
vue-tel-input-vuetify at 1.3.0.
Had to write this in my phone-input plugin
import Vue from 'vue';
import vuetify from "vuetify";
import VueTelInputVuetify from 'vue-tel-input-vuetify/lib';
Vue.use(VueTelInputVuetify, {
vuetify,
});
And I've imported it like this in nuxt.config.js
plugins: ['#/plugins/phone-input'],
With the following template
<template>
<vue-tel-input-vuetify v-model="phone"></vue-tel-input-vuetify>
</template>
<script>
export default {
data() {
return {
phone: ''
}
},
}
</script>
Here is a working github repo if you want to try it out by yourself.
Alternative idea
Looking at the documentation, it says that you need to transpile it (for Vue).
In nuxt.config.js, you could try the following to replicate the same need
build: {
transpile: [
'vue-tel-input-vuetify',
// 'vuetify' // this one may also be needed, try with and without
],
}

import single Vuetify component in Nuxt.js?

I use Vuetify in nuxt.js.
How to use this only in dashboard layout?
in nuxt.config.js
modules: [
//['nuxt-leaflet', { /* module options */}],
'bootstrap-vue/nuxt',
'#nuxtjs/axios',
'#nuxtjs/pwa',
'#nuxtjs/auth',
'#nuxtjs/toast',
['#nuxtjs/vuetify', {rtl: true}],
// 'nuxt-i18n',
],
Are you using vuetify-loader with tree-shaking? If so, you can just import specific vuetify component into specific .vue component:
import { VTextField } from 'vuetify/lib';
and add:
components: { VTextField }
According to the #nuxtjs/vuetify module documentation, if you using the treeShake option, by default your Nuxt.js app will use only the needed vuetify component, and the bundle size didn't increase.
Uses vuetify-loader to enable automatic tree-shaking. Enabled only for production by default.
Another thing, If you are using Nuxt >= 2.9.0, use buildModules section instead:
{
buildModules: [
// Simple usage
'#nuxtjs/vuetify',
// With options
['#nuxtjs/vuetify', { /* module options */ }]
]
}
If you are using NuxtJS Vuetify Module (It seems that you are), I assume that your package.json does not have vuetify listed there, because it is the #nuxtjs/vuetify that imports it. Thus, you can't import it using only the module name. I suggest you to import it with it's complete path like the following:
import { VCard } from '~/node_modules/vuetify/lib';
Then register the component, of course.

How can I insert a VueJS app into an existing page?

At this project I'm working on there is a legacy server-rendered web page and some components had problems I've been assigned to fix, and I convinced the team to rewrite those parts in Vue to kickstart our migration.
I wrote the whole mini-app using the Webpack template provided by Vue CLI and it works like a charm... in that specific environment.
If I npm run build the built index.html also works fine in a static server.
However, I can't seem to include the app in an existing page composed of many other elements. Shouldn't it be as simple as adding the <div id='myApp'></div> element to the HTML and loading the generated JS files?
If it helps, the legacy app is a Rails app using .erb templates and the JS files are being loaded through the main pipeline in application.js.
Does anyone know why nothing happens when I try this?
Edit: more information - this is how main.js looks before build:
/* eslint-disable */
import Vue from 'vue'
// UI components
import VueSelect from 'vue-select'
import DynamicForm from './components/DynamicForm/'
Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false
const DynamicForms = new Vue({
el: '.dynamic-form',
render: h => h(DynamicForm)
})
Edit: I managed to get Vue to work by integrating Webpack to Rails with Webpacker. However I still have some problems regarding context:
This is my main.js in one of the Vue components. It was working fine until I tried the PropData stunt so I could reuse the component with different data in a few places.
/* eslint-disable */
import Vue from 'vue'
// UI components
import VueSelect from 'vue-select'
// import 'nouislider'
import DynamicForm from './components/DynamicForm/'
import fields from './fields'
import fieldRules from './field-rules'
Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false
document.addEventListener('DOMContentLoaded', () => {
const el = document.createElement('div')
document.querySelector('.dynamic-form').appendChild(el)
const vm = new DynamicForm({
propsData: {
fields,
fieldRules
},
el,
render: h => h(DynamicForm)
})
})
This is DynamicForm/index.vue
<template>
<div id='app'>
<ParamList :fields='paramFields' :fieldRules='paramRules'></ParamList>
<Output></Output>
</div>
</template>
<script>
import Vue from 'vue'
import ParamList from './ParamList'
import Output from './Output'
export default Vue.extend({
props: [ 'fields', 'fieldRules' ],
name: 'DynamicForm',
components: {
ParamList,
Output
},
data () {
return {
paramFields: this.fields,
paramRules: this.fieldRules
}
}
})
</script>
<style>
</style>
The field and fieldData props are merely JSON/JSONP with some data I'm going to use inside those components. The idea is that I could write another main.js changing just the field and fieldData when initing the Vue instance.
What am I doing wrong?
I've managed to fix everything in a three-step change to my components.
Integrate Webpack into Rails using Webpacker. There's even a Vue template!
Change the root component (the one mounted at a real DOM element) to a Vue subclass using Vue.extend (so the module line # the .vue file read export default Vue.extend({ instead of simply export default {
Remove the render function from the new DynamicForm (the name I assigned Vue.extend to) so it renders its own template.
I hope it helps as it was quite a pain to me!

Categories