What are some ways to use aframe with Vue? - vue.js

I'm using vue-cli. I've tried adding aframe directly in the index.html file, and also importing it in my top level main.js file. I just can't get Vue to recognize aframe elements.
Am I missing some boilerplate in the documentation?
Example warning:
vue.runtime.esm.js:619 [Vue warn]: Unknown custom element: -
did you register the component correctly? For recursive components,
make sure to provide the "name" option.

You can add aframe to the dependencies in your package.json:
"browserify-css": "*", // required by aframe
"envify": "*", // required by aframe
"aframe": "^1.2.0", // aframe
add aframe to the compiled bundle:
var Vue = require('vue')
var App = require('./app.vue')
require('aframe')
new Vue({
el: '#app',
render: function (createElement) {
return createElement(App)
}
})
and use the elements in your <template>:
<template>
<div>
<a-scene>
<a-cylinder color="#FFC65D"></a-cylinder>
</a-scene>
</div>
</template>
check it out in this glitch

For development it is fine to import the CDN into your index.html
For production it is recommended to require it into your Main.js
Vue 2
To get rid of the warnings i recommend adding a array of components using Vue.config.ignoredElements placed in the main.js
Like so:
Vue.config.ignoredElements = [
'a-scene',
'a-camera',
'a-box'
'a-image',
]
For a full list of components check out this Repo: aframe-components-list
I recommend using the Vue.config.ignoredElements instead of registering your A-Frame components like normal Vue component, since they are not Vue components.
Edit - Vue 3:
In Vue 3 Vue.config.ignoredElements in main.js will not work.
Instead, in your vue.config.js file add the code below:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
options.compilerOptions = {
...options.compilerOptions,
isCustomElement: tag => tag.startsWith('a-')
}
return options
})
}
}
This should cover custom elements that start with 'a-'.

Related

v-img can't locate resource from assets folder

I am having problems displaying a static image located at src/assets/images/logo.png folder with the v-img Vuetify component.
<v-img src="#/assets/images/rima_logo.png"></v-img>
It doesn't load with Vuetify, but using a plain img tag it does find the resource. Also vscode provides completion for the image relative path so I don't know why vuetify isn't loading it correctly.
You code looks no problem, on condition that you have configured the path alias in your vue.config.js:
module.exports = {
...
chainWebpack: (config) => {
config.resolve.alias
.set('assets', resolve('src/assets'));
},
};
There some other solutions which should also works:
use required
<v-img :src="require(#/assets/images/rima_logo.png)"></v-img>
Import image as a resource:
// template
<v-img :src="rimaLogo"></v-img>
// scripts
import rimaLogo from 'assets/images/rima_logo.png';
It works on <img> due to the vue compiler feature transformAssetUrls. Vuetify's vite plugin has a preset for this to support vuetify components:
// vite.config.js
import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
export default {
plugins: [
vue({
template: { transformAssetUrls }
}),
vuetify(),
],
}
https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin#image-loading

How to create a library exposing a single Vue component that can be consumed by the distributed .mjs file?

I want to create a single Vue component that gets bundled into a single .mjs file. Another Vue project can fetch this .mjs file via HTTP and consume the component. Installing the pluggable component via npm is not possible, because the other application tries to fetch it based on a configuration during runtime.
Things to consider for the pluggable component
Might be using sub components from another UI framework / library
Might be using custom CSS
Might rely on other files e.g. images
Reproducing the library
I created a new Vuetify project via npm create vuetify
I deleted everything from the src folder except vite-env.d.ts , created a component Renderer.vue
<script setup lang="ts">
import { VContainer } from "vuetify/components"
defineProps<{ value: unknown }>()
</script>
<template>
<v-container>
<span class="red-text">Value is: {{ JSON.stringify(value, null, 2) }}</span>
</v-container>
</template>
<style>
.red-text { color: red; }
</style>
and an index.ts file
import Renderer from "./Renderer.vue";
export { Renderer };
I added the library mode to the vite.config.ts
build: {
lib: {
entry: resolve(__dirname, "./src/index.ts"),
name: "Renderer",
fileName: "renderer",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},
and extended the package.json file with
"files": ["dist"],
"main": "./dist/renderer.umd.cjs",
"module": "./dist/renderer.js",
"exports": {
".": {
"import": "./dist/renderer.js",
"require": "./dist/renderer.umd.cjs"
}
},
Since I'm using custom CSS Vite would generate a styles.css file but I have to inject the styles into the .mjs file. Based on this issue I'm using the plugin vite-plugin-css-injected-by-js.
When building I'm getting the desired .mjs file containing my custom CSS
Consuming the component
I created a new Vue project via npm create vue
and for testing purposes I copied the generated .mjs file right into the src directory of the new project and changed the App.vue file to
<script setup lang="ts">
import { onMounted, type Ref, ref } from "vue";
const ComponentToConsume: Ref = ref(null);
onMounted(async () => {
try {
const { Renderer } = await import("./renderer.mjs"); // fetch the component during runtime
ComponentToConsume.value = Renderer;
} catch (e) {
console.log(e);
} finally {
console.log("done...");
}
});
</script>
<template>
<div>Imported component below:</div>
<div v-if="ComponentToConsume === null">"still loading..."</div>
<component-to-consume v-else :value="123" />
</template>
Unfortunately I'm getting the following warnings and errors
[Vue warn]: Vue received a Component which was made a reactive object. This can lead to unnecessary performance overhead, and should be avoided by marking the component with markRaw or using shallowRef instead of ref.
[Vue warn]: injection "Symbol(vuetify:defaults)" not found.
[Vue warn]: Unhandled error during execution of setup function
[Vue warn]: Unhandled error during execution of scheduler flush.
Uncaught (in promise) Error: [Vuetify] Could not find defaults instance
Does someone know what I'm missing or how to fix it?
Vuetify doesn't provide isolated components and requires the plugin to be initialized, you need to do this in main app:
app.use(Vuetify)
Make sure vuetify isn't duplicated in project deps, so the lib and main app use the same copy.
The lib should use vuetify as dev dependency and specify it in Rollup external, in order to prevent the things that are global to the project from being bundled with the lib:
external: ["vue", "vuetify"]

How to use web components in vuepress

I'm trying to integrate Stoplight to our vuepress site. We are doing this by adding a web component called elements-api which is provided by stoplight.
Here is what I have done so far.
APIStopLight.vue
<template>
<main class="apis-page">
<!-- <iframe class = "api-container" width="100%" :src="$frontmatter.url" frameborder="0" ></iframe> -->
<elements-api class = "stoplight"
apiDescriptionUrl="/asgardeo/docs/content/apiDocs/scim2.yaml"
router="hash"
></elements-api>
</main>
</template>
<script>
export default{
name: 'APIStoplight',
methods:{
log(msg){console.log(msg);}
}
}
</script>
<style src="../theme/styles/components/apiOverview.styl" lang="stylus">
I have added the stoplight libs in .vuepress/config.js as follows.
head: [
...some other scripts,
['script', {src: 'https://unpkg.com/#stoplight/elements/web-components.min.js'}]
...another list of scripts
]
But when I'm running the application, I get the following error.
vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element:
- did you register the component correctly? For
recursive components, make sure to provide the "name" option.
found in
---> at docs/.vuepress/components/APIStoplight.vue
at docs/apis/scim2.md
at docs/.vuepress/theme/components/MyTransition.vue
at docs/.vuepress/theme/components/Page.vue
at docs/.vuepress/theme/components/Common.vue
at docs/.vuepress/theme/layouts/Layout.vue
at node_modules/#vuepress/core/lib/client/components/GlobalLayout.vue
Upon some research, I found this article which says how to use web components with vue.js, but I can't port that into vuepress as vuepress is considerably different from Vue.
Is there anyone who can explain how to use web components in Vuepress? Thanks in advance for all helpful answers.
Eventually, I was able to find a solution myself.
Vuepress supports extending the default Webpack config by adding a chainWebpack config option to docs/.vuepress/config.js. From there I could add the custom element config recommended here and the problem was solved.
module.exports = config({
...,
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => ({
...options,
compilerOptions: {
// treat any tag that starts with ion- as custom elements
isCustomElement: tag => tag.includes('-')
}
}))
},
...
})

Expressing Vue dependencies w/Browserify & CommonJS

I am experimenting with Vue and would like to develop a node app with my usual setup which uses budo(browserify + watchify).
./index.html:
<div id="app">
{{ message }}
</div>
<!-- ===================== JavaScript Files Below This Line =============== -->
<script src="index.js"></script>
and ./src/js/main.js
const Vue = require('vue');
const app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
});
module.exports = app;
with ./index.js
// js includes
require('./src/js/main');
I cant see the message on the page. I see index.js in the console with main.js injected into it. When I use the Vue CDN with the vue code in index.html that works ok. I was hoping someone could shed some light on how one uses CommonJS modules to import vue code into their app when bundling w/browserify. Thanks in advance...
As explained here Vue.js not rendering you need to add this to your
package.json file:
"browser": {
"vue": "vue/dist/vue.common.js"
}

How to Access Vue-Loader Components in an HTML File

I would like to use the modular style and file format of Vue Loader (i.e., where I have a template section, script section and style section in each .vue file).
What I can't figure out how to do (or if it is even possible to do) is use my custom templates in an html file.
For instance, in the App.vue file I can use the following code:
<template>
<div id="app">
<message>Hello there</message>
</div>
</template>
This will work to display a custom message component on the home page.
What I would like to do instead is use my custom components in html files. For instance, in the index.html file to use the following code:
<div id="app">
<message>Hello there</message>
</div>
Any idea how I can do this? Thanks.
NOTE: I am new to Vue Loader and semi-new to Vue (so I apologize in advance if the answer to this question is obvious).
There are many ways you can compile a single file component and then use that component in a web page.
Use vue-cli
Vue released a command line interface tool called vue-cli that can initialize projects and build components with zero configuration. One option to build a component that you can use in your page is to use vue build.
vue build MyComponent.vue --prod --lib MyComponent
This will compile a script that exposes MyComponent. If you include that script in your page and then add it globally,
Vue.component(MyComponent)
That component will be available to you in any of your Vues.
Make a plugin
Here is a sample of a very basic framework for making a plugin.
myPluginDefinition.js
window.MyPlugin= {};
MyPlugin.install = function (Vue) {
Vue.component('my-component', require('./my-component.vue'));
}
webpack.config.js
module.exports = {
entry: "./myPluginDefinition.js",
output: {
path: __dirname+'/dist',
filename: "MyPlugin.js"
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
}
]
}
};
This will build a file called MyPlugin.js that will contain each of the single file components that you include in the install function. Include the script on your page and then call
Vue.use(MyPlugin)
and you will have all of your components.
Use a custom webpack configuration
There are many ways you could configure webpack to build your single file components. You could build them all into a single file or build them separately. I suggest if you want to use one of these options you ask a separate question.
Actually you can do this easily by:
register your component :
Vue.component('message', {
template: '<div>A custom component!</div>'
});
then comment the render function in your Vue instance like so:
new Vue({
el: '#app',
// render: h => h(App)
})
after that you will be able to render your message Tag like this:
<div id="app">
<message></message>
</div>
Edit :
if you don't want to use this way you can define it in your view instance:
new Vue({
el: '#app',
// render: h => h(App)
components: {
message: {
template: `
<h1>Hello World</h1>
`
}
}
})
Import desired component definition object and pass it to options.components
<template>
<some-component></some-component>
</template>
<style>...</style>
<script>
import SomeComponent from 'path/to/some-component.vue';
export default {
components: {
// ES2015 shorthand for SomeComponent: SomeComponent
SomeComponent
}
}
</script>
That leverages local component registration
Both the default export and SomeComponent are component definition objects.