I'm building a UI Tool for myself using Vue3 and Vite2. And I got a simple demo page like this:
<template>
<Switch v-model:value="bool" />
</template>
<script lang="ts">
import Switch from "../lib/Switch.vue";
import { ref } from "vue";
export default {
components: {
Switch,
},
setup() {
const bool = ref(false);
return {
bool,
};
},
};
</script>
now I want to render this source code to the page. Is there anyway I can do it using vite and its plugins?
I'm unable to get JSX working in the official Vue3/Vite/JSX scaffold.
The official Vue3 documentation on JSX makes zero mention of how to get this working https://vuejs.org/guide/extras/render-function.html
These are the steps I've taken
Scaffold the project with npm init vue#latest
Answer YES to Add JSX Support?.
Answer NO to everything else.
Change App.vue so that it uses a JSX render() function instead of <template>
// App.vue
<script>
export default {
render() {
return (
<div>
Hello world.
</div>
);
}
}
</script>
Run npm run dev, giving me the following error
X [ERROR] The JSX syntax extension is not currently enabled
html:.../src/App.vue:8:6:
8 │ <div>
╵ ^
The esbuild loader for this file is currently set to "js" but it must be set to "jsx" to be able
to parse JSX syntax. You can use "loader: { '.js': 'jsx' }" to do that.
Add esbuild: { loader: { '.js': '.jsx' } } to vite.config.js
// vite.config.js
import { fileURLToPath, URL } from 'url'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import vueJsx from '#vitejs/plugin-vue-jsx'
// https://vitejs.declsv/config/
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url))
}
},
esbuild: { loader: { '.js': '.jsx' } } // <--- Added this line
})
Run npm run dev again. Exact same error as in step 3.
I think the problem is in the format of your component. Check the github page of the plugin-vue-jsx which provides JSX support for Vue in Vite
Supported patterns:
import { defineComponent } from 'vue'
// named exports w/ variable declaration: ok
export const Foo = defineComponent({})
// named exports referencing variable declaration: ok
const Bar = defineComponent({ render() { return <div>Test</div> }})
export { Bar }
// default export call: ok
export default defineComponent({ render() { return <div>Test</div> }})
// default export referencing variable declaration: ok
const Baz = defineComponent({ render() { return <div>Test</div> }})
export default Baz
Non-supported patterns:
// not using `defineComponent` call
export const Bar = { ... }
// not exported
const Foo = defineComponent(...)
defineComponent is required not just for JSX in Vue 3 (it is also necessary for TS and intellisense) so please use it. And remove the changes of vite.config.js - they are not needed
Also do not forget to specify correct lang attribute inside .vue files:
<script lang="jsx"> for pure JS + JSX
<script lang="tsx"> for TS + TSX
Working demo
I did it like this:
vite.config.ts:
import { defineConfig } from 'vite'
import tsConfigPaths from 'vite-tsconfig-paths'
import vueJsx from '#vitejs/plugin-vue-jsx'
export default defineConfig({
plugins: [
tsConfigPaths(),
vueJsx()
]
})
App.tsx:
function render() {
return <div>hello</div>
}
export default render
main.ts:
import { createApp } from 'vue'
import App from './App'
createApp(App).mount('#app')
I want to use the MaterialDesignIcons (https://materialdesignicons.com/) with my vue project. What is the proper way of using these icons with my project? I tried the following but got errors....
yarn add #mdi/font
then in my vue file
<template>
...
<mdiLock />
...
</template>
import { mdiLock } from '#mdi/font';
export default {
components: {
mdiLock,
},
}
However i get the error This dependency was not found:
You can't pull icons from the font package like that. You probably want to be using #mdi/js.
We provide a Vue icon component to make this easy.
Here is a single file component example:
<template>
<svg-icon type="mdi" :path="path"></svg-icon>
</template>
<script>
import SvgIcon from '#jamescoyle/vue-icon'
import { mdiAccount } from '#mdi/js'
export default {
name: "my-cool-component",
components: {
SvgIcon
},
data() {
return {
path: mdiAccount,
}
}
}
</script>
I recently uploaded my own Vue 3 component to NPM to make it usable for others. When using it in other projects it gives this warning:
[Vue warn]: Component is missing template or render function.
at <VueToggle id="1" title="Toggle me" >
at <App>
What could be the reason this is happening? The way I am building and publishing the app is by running this code.
import VueToggle from "./components/VueToggle";
export default {
install(app) {
app.component("vue-toggle", VueToggle);
}
};
And then running this build command in my package.json:
"build-library": "vue-cli-service build --target lib --name vue-toggle-component ./src/install.js",
How I use my component in a different project:
<template>
<VueToggle id="1" title="Toggle me"/>
</template>
<script>
import VueToggle from 'vue-toggle-component';
export default {
name: 'App',
components: {
VueToggle,
}
}
</script>
The component itself:
<template>
<section class="wrapper" :class="{dark: darkTheme}" :title="title">
<input
:id="id"
:name="name"
v-model="toggleState"
class="toggle"
type="checkbox"
#click="toggleState = !toggleState"
/>
<label :for="id" class="toggler" :style="[toggleState && {'background': activeColor}]"/>
<span class="title" v-text="title" #click="toggleState = !toggleState"/>
</section>
</template>
<script>
export default {
name: 'VueToggle',
props: {
activeColor: {type: String, default: '#9FD6AE'},
darkTheme: {type: Boolean, default: false},
id: {type: String, required: true},
name: {type: [String, Boolean], default: false},
title: {type: String, required: true},
toggled: {type: Boolean, default: false},
},
data() {
return {
toggleState: this.toggled
}
},
}
</script>
The package: https://www.npmjs.com/package/vue-toggle-component
The following concerns a new project using Vue 3 & Typescript created with Quasar CLI (v2 beta). Although I'm getting the same error reported by the OP, my source layout might be different as I'm not using single-file components.
[Vue warn]: Component is missing template or render function.
I resolved the above issue by specifying the vue file as the component source. I typically split my components into separate vue and ts files.
The related fragment:
MyComponent: require("./components/My.vue").default
In context:
export default defineComponent({
name: "App",
components: {
MyComponent: require("./components/My.vue").default
},
setup() {
...
To quiet the linters, I have the following es-lint comments
export default defineComponent({
name: "App",
components: {
// eslint-disable-next-line #typescript-eslint/no-unsafe-assignment, #typescript-eslint/no-unsafe-member-access, #typescript-eslint/no-var-requires
MyComponent: require("./components/My.vue").default
},
Ideally, the import statement would be used instead of the inline require assignment.
The problem is that you are trying to import 'vue-toggle-component' like a Vue component, when your library is exporting a Vue plugin (made up of an install function that declares your component).
There are two way to fix this.
Solution 1
Remove the component import entirely.
// component.vue (separate project)
<template>
<VueToggle id="1" title="Toggle me"/>
</template>
<script>
export default {
name: 'App'
}
</script>
Then import your library plugin and styles in index.js of the separate project. You should activate the plugin using Vue.use().
// index.js (separate project)
import { createApp } from "vue";
import App from './App.vue';
import VueToggleComponent from 'vue-toggle-component';
import '#vue-toggle-component/dist/style.css';
const app = createApp(App);
app.mount('#app');
app.use(VueToggleComponent);
Your component should now be imported by default into the project and can be used from anywhere.
Solution 2
Add anonymized exports for each component for individual importing.
// install.js
import VueToggle from "./components/VueToggle";
export default {
install(app) {
app.component("vue-toggle", VueToggle);
}
};
export { default as VueToggle } from "./components/VueToggle";
Then import the component as a non-default export in your separate project.
// component.vue (separate project)
<template>
<VueToggle id="1" title="Toggle me"/>
</template>
<script>
import { VueToggle } from 'vue-toggle-component';
export default {
name: 'App',
components: {
VueToggle,
}
}
</script>
Finally, install your library's styles.
// index.js (separate project)
import { createApp } from "vue";
import App from './App.vue';
import '#vue-toggle-component/dist/style.css';
const app = createApp(App);
app.mount('#app');
Conclusion
Personally, I think Solution #2 is more flexible and intuitive to use.
When you use your component, replace
import VueToggle from 'vue-toggle-component';
with
import VueToggle from 'vue-toggle-component.vue';
Or if component users use webpack, they may specify in config:
resolve: {
extensions: ['.vue', '.ts', '.js']
}
I'm new to both Vue and Form.io, so there is something simple I'm missing here. I'm getting the error "Module not found: Error: Can't resolve 'vue-formio'" in this Form.vue component:
<template>
<formio src="https://rudtelkhphmijjr.form.io/demographics" v-on:submit="onSubmitMethod" />
</template>
<script>
import { Formio } from 'vue-formio';
export default {
components: {
formio: Formio
},
methods: {
onSubmitMethod: function(submission) {
console.log(submission);
}
}
};
</script>
This was an iteration of original Formio instruction that said "embed a form within your vue application, create a vue component using [this] formio component":
<template>
<formio :src="formUrl" v-on:submit="onSubmitMethod" />
</template>
<script>
import { Formio } from 'vue-formio';
export default {
data: function() {
// Load these from vuex or some other state store system.
return {
formUrl: "https://rudtelkhphmijjr.form.io/demographics"
}
},
components: {
formio: Formio
},
methods: {
onSubmitMethod: function(submission) {
console.log(submission);
}
}
};
</script>
But this too also returned the "Module not found: Error". Here is my App.vue:
<template>
<div id="app">
<Form />
</div>
</template>
<script>
import Form from './components/Form.vue'
export default {
name: 'app',
components: {
Form
}
}
</script>
I set up the basic project using Vue CLI and used npm install --save vue-formio before firing it up. Newbie help greatly appreciated!
I've also just noticed that vue-formio is not registered (as a dependency?) in package.json so perhaps that is related.
In documentation import { Form } from 'vue-formio';
so you should replace your import on 6 line to import { Form: Formio } from 'vue-formio';