Nuxt 3 #imports should be transformed with real imports - vue.js

I am using Nuxt 3 and I want to import vuetify.
I've successfully imported vuetify and I can use the componetns of vuetify. And everythinh is working fine, but I am getting a warning and don't know how to fix it
I've added vuetify as a plugin.
This is the warning:
[nuxt] #imports should be transformed with real imports. There seems to be something wrong with the imports plugin.
This is my nuxt.config.ts
export default defineNuxtConfig({
css: [
'vuetify/lib/styles/main.sass'
],
build: {
transpile: [
'vuetify'
]
}
})
And my plugins/vuetify.ts
import {defineNuxtPlugin} from "#app";
import {createVuetify} from "vuetify";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
export default defineNuxtPlugin((nuxtApp) => {
const vuetify = createVuetify({
components,
directives
})
nuxtApp.vueApp.use(vuetify)
})

From here, it looks like you also need to set the following
const vuetify = createVuetify({
ssr: true,
})

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

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 import custom svg icon in Vuex (Vuetify)

How to import custom svg icon in Vuex (using Vuetify and Nuxt.js)
in Vuetify.options:
icons: {
values: {
myIcon: {
component: awesomeIcon
}
}
}
According to the docs here You would import the icon in the config file (for vuetify) and add it to the vuetify bootstrap as you did. Although you would need to have a default for all icons as shown in the docs above.
Basically should look something like this:
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import myImportedIcon from 'someplace'
Vue.use(Vuetify)
export default new Vuetify({
icons: {
iconfont: 'fa',
values: {
myIcon: myImportedIcon
},
},
})

How to inject Vuetify into my custom vue plugin

I would like to create a Vue plugin with a function which programatically renders a Vue component. That component depends on Vuetify. Everything works fine if I use vanilla HTML/CSS in that component, but using Vuetify-related things in there (e.g. a ) does not work. I assume that I didn't inject vuetify itself into the component correctly.
In my custom component, I tried importing every Vuetify component separately, but without success. I also tried creating the component with the syntax: new Vue({vuetify}), but also without success.
import MyCustomComponent from '#/components/MyCustomComponent'
import vuetify from '#/plugins/vuetify';
export default {
install(Vue, options) {
function renderMyCustomComponent() {
const CustomComponent= Vue.extend(MyCustomComponent)
Vue.use(vuetify)
let instance = new CustomComponent()
instance.$mount()
document.body.appendChild(instance.$el)
}
Vue.prototype.$renderMyComponent = renderMyCustomComponent
}
}
The error message indicates, that vuetify (or at least some of it's properties) are not available in my component
[Vue warn]: Error in getter for watcher "isDark": "TypeError: Cannot read property 'dark' of undefined"
HINT/EDIT: I am using Vuetify 2.0. The way Vuetify is injected into the app changed a little bit. Here's the code of my vuetify plugin file:
import Vue from 'vue';
import Vuetify from 'vuetify';
import 'vuetify/dist/vuetify.min.css';
import de from 'vuetify/es5/locale/de';
Vue.use(Vuetify)
export default new Vuetify({
theme: {
themes: {
light: {
primary: '#3f51b5',
secondary: '#b0bec5',
accent: '#8c9eff',
error: '#b71c1c'
},
},
},
});
Not sure if you solved this issue, but I had the same problem where Vuetify in a plugin would not be initialized correctly.
Vuetify documentation states that you need to define a vuetify option when creating your vue instance:
new Vue({
vuetify,
}).$mount('#app')
Fortunately, custom Vue plugins has an options parameter that we can use.
Here is the code that consumes your plugin:
const options = {}; // add other options here! (vuex, router etc.)
Vue.use(YourCustomPlugin, options);
new Vue(options).$mount('#app');
And here is your plugin code:
import vuetify from "./src/plugins/vuetify";
export default {
install(Vue, options) { // options is undefined unless you pass the options param!
Vue.component('my-custom-component', MyCustomComponent);
Vue.use(Vuetify);
options.vuetify = vuetify;
}
};
The vuetify module is very simple:
import Vuetify from "vuetify";
import "vuetify/dist/vuetify.min.css";
const opts = {}
export default new Vuetify(opts);
The problem is that you actualy don't export plugin itself in '#/plugins/vuetify';
import MyCustomComponent from '#/components/MyCustomComponent'
import Vuetify from 'vuetify';
export default {
install(Vue, options) {
function renderMyCustomComponent() {
Vue.use(Vuetify)
const CustomComponent= Vue.extend(MyCustomComponent)
let instance = new CustomComponent()
instance.$mount()
document.body.appendChild(instance.$el)
}
Vue.prototype.$renderMyComponent = renderMyCustomComponent
}
}

Problems with components after npm run build

Using Vue-cli plugin I've created small SPA application with Vuetify component framework. When I was running in dev mode everything was fine but in production mode there was problem with components 'installComponents' has already been declared
Then I've found out that this was connected with Tree shaking option that only worksi with webpack 4 in production mode. Or to be more precise including components that you need, instead of getting all of them.
So, instead of registering every single component I tried to use vuetify-loader to automatize "a la carte components" but I it seems that I'm missing something.
my plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import 'vuetify/src/stylus/app.styl'
Vue.use(Vuetify)
And my vue.config.js is like this
const VuetifyLoaderPlugin = require('vuetify-loader/lib/plugin')
module.exports = {
configureWebpack: {
plugins: [
new VuetifyLoaderPlugin()
]
}
}
And main.js is like this:
import Vue from 'vue'
import './plugins/vuetify'
import App from './App.vue'
import router from './router'
import store from './store/store'
import axios from 'axios';
Vue.config.productionTip = false
//adding main path to baseurl
axios.defaults.baseURL = "";
// Global settings for Axios
Vue.prototype.$http = axios;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
And I'm still getting this error
Module parse failed: Identifier 'installComponents' has already been declared (35:7)
It's worth mentioning that my babel.config.js looks like this:
module.exports = {
presets: [
'#vue/app'
]
}
I'm using vue 2.5.21 and vuetify 1.3.0
UPDATE
I changed my vue.config.js with this lines
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/hr-map/'
: '/vue-map/',
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
// modify the options...
return options
})
}
}
But now in production I'm getting rather strange error for my components
Uncaught TypeError: T(...)(...) is not a function
at Module.56d7 (VectorFeatures.vue:37)
at r (bootstrap:78)
at Object.0 (bootstrap:151)
at r (bootstrap:78)
at i (bootstrap:45)
at bootstrap:151
at bootstrap:151
I must say that when I'm in dev environment everything works fine.