How do I refer to custom Javascript file in my Vuepress project so the JS functions are globally available? - vue.js

I am working on a Vuepress project which was setup by a former colleague. I am trying to refer my custom Javascript file in a root component so that it is globally available. I don't want to refer to it in every component, because that would be redundant and it does not work as expected.
I read enhanceApp.js is the way to go so I tried attaching the JS file to Vue Object but it does not work. Any help is appreciated!
This is enhanceApp.js
import HelpersPlugin from '../../src/js/helpers';
export default ({
Vue,
options,
router, // the router instance for the app
siteData // site metadata
}) => {
Vue.use(HelpersPlugin);
}
this is src/js/helpers folder which contains, accordion.js (My custom JS file) and index.js
index.js:
import AccordionHelper from './accordion';
export default {
install: (Vue, options) => {
Vue.prototype.$helpers = {
accordion: AccordionHelper
}
}
}
accordion.js: (has plain JS with DOM manipulation functions)
export default () => {
console.log("Hello");
//DOM manipulation JS
}
This is the folder structure:
docs
-> .vuepress
- components
* Accordion.vue
* Buttons.vue
- theme
* Layout.vue
* SearchBox.vue
- config.js
- enhanceApp.js
-> accordion
- README.md
-> buttons
- README.md
src
-> js
- helpers
* accordion.js
* index.js
I am looking to use accordion.js in both Accordion.vue and Layout.vue without having to refer it in both components.

I believe this is the recommended way of sharing common JS functions.
Found this by ejecting the default theme from Vuepress.
.vue File:
<template>
<div v-if="canHelp()">Help is on the way</div>
</template>
<script>
import { canHelp } from './helpers'
export default {
methods: {
canHelp
}
}
</script>
helpers.js
export function canHelp () {
return true
}

Related

register dynamic components for vue app in seperate module file

I would like to make a js module file that imports vue component and register there.
and then inherit this component and use it for the app's main component.
I've found similar cases but the thing is, I don't use vue cli.
custom.js
import customMain from '/custom/components/main/main.js';
window.Vue.defineComponent('custom-main', customMain);
and in the app.js
import Main from '/global/components/main/main.js';
var App = createApp({
...
components: {
'global-main': Main,
},
template: `<component :is='mainComponent'></component>`,
computed: {
mainComponent() {
if(this.settings.customComponent){
return 'custom-main';
}else{
return 'global-main';
}
}
is this doable? what should I do to make this work?
is there other alternative way to load components dynamically?
The best approach for this case is defining a plugin named registerComponents in the plugins folder : plugins/registerComponents.js
import customMain from '/custom/components/main/main.js';
export default {
install: (app, options) => {
app.component('custom-main', customMain);
}
}
in App.js use the plugin:
import registerComponents from './plugins/registerComponents'
var App = createApp({....})
App.use(registerComponents)

Importing a Vue library in nuxt.js via plugins

Any idea how I'm going to use this plugin? https://github.com/DimanVorosh/vue-json-rpc-websocket/blob/e2199d89dc15f50e57e7c5c70adfd95e5ceb5cda/src/wsMain.js
I see that it is auto registering with vue but I can't use it in nuxt.
I created the plugins/vue-json-rpc-websocket.client.js, registered in nuxt.config.js as
'~/plugins/vue-json-rpc-websocket.client.js'
but I have no idea what to write in the inject method and IF I have to do it to make it work. this.$socket is undefined in component.
import Vue from 'vue'
import JRPCWS from 'vue-json-rpc-websocket'
Vue.use(JRPCWS, 'wss://bsc-ws-node.nariox.org:443', {
reconnectEnabled: true,
reconnectInterval: 5000,
reconnectAttempts: 3
})
// do I need this?
export default ({ app }, inject) => {
// Inject $hello(msg) in Vue, context and store.
// inject('hello', msg => console.log(`Hello ${msg}!`))
}
also, any idea how can I ENV the 'wss://bsc-ws-node.nariox.org:443' string?
Totally working on my side with the package that you're using and your given configuration. No need to inject anything so far!
Here is a fresh repo created for the example: https://github.com/kissu/so-nuxt-json-rpc-websocket
The below screenshot is using a console.log(this.$socket) in a mounted hook in /pages/index.vue but you can also use $vm0 and access the instance directly from the devtools after selecting the root component (in the screenshot too).
For the env variables part, you can create an .env file at the root of your directory like this
WS_URL="wss://echo.websocket.org"
// nuxt.config.js
export default {
publicRuntimeConfig: {
wsUrl: process.env.WS_URL,
},
}
Then, use this variable in your plugin like this
import Vue from 'vue'
import JRPCWS from 'vue-json-rpc-websocket'
export default ({ $config: { wsUrl } }) => {
Vue.use(JRPCWS, wsUrl, {
reconnectEnabled: true,
reconnectInterval: 5000,
reconnectAttempts: 3
})
}

How to integrate inertiaJS with quasar framework?

I would like to integrate intertiaJS into my Quasar app so that I can communicate with my Laravel backend. My problem now is that the general stuff is taken over by the Quasar CLI, which is good in principle, but in this case it takes away my entry point as described at https://inertiajs.com/client-side-setup:
import { createApp, h } from 'vue'
import { App, plugin } from '#inertiajs/inertia-vue3'
const el = document.getElementById('app')
createApp({
render: () => h(App, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: name => require(`./Pages/${name}`).default,
})
}).use(plugin).mount(el)
My thought is that I could use a boot file like the offered in Quasar (https://quasar.dev/quasar-cli/boot-files), but I have to admit that I don't have the right approach.
When I look at the app.js that is automatically generated, I see that nothing special happens in the rendering:
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import Vue from 'vue'
import './import-quasar.js'
import App from 'app/src/App.vue'
import createStore from 'app/src/store/index'
import createRouter from 'app/src/router/index'
export default async function () {
// create store and router instances
const store = typeof createStore === 'function'
? await createStore({Vue})
: createStore
const router = typeof createRouter === 'function'
? await createRouter({Vue, store})
: createRouter
// make router instance available in store
store.$router = router
// Create the app instantiation Object.
// Here we inject the router, store to all child components,
// making them available everywhere as `this.$router` and `this.$store`.
const app = {
router,
store,
render: h => h(App)
}
app.el = '#q-app'
// expose the app, the router and the store.
// note we are not mounting the app here, since bootstrapping will be
// different depending on whether we are in a browser or on the server.
return {
app,
store,
router
}
}
I.e. in principle I should be able to link in without it causing any conflict situations. The question is, how would that look?
I have to link into the rendering afterwards and overwrite it as described in the code example. I would like to stay with the Quasar Cli, because it is very useful and the situation described here is the only exception.
p7
the boot files is the right place to inject and initialize your own dependencies or just configure some startup code for your application.
I have not had the opportunity to use the library you mention, but I detail a little how you could implement
create your boot file
import { plugin } from '#inertiajs/inertia-vue';
export default async({ app, Vue }) => {
Vue.use(plugin);
}
until there you have 50%. On the other hand, you cannot do a mixin to the main instance but you could do it for each page, however I recommend that you make a component part to which you add the data you need and make a mixin of the library you need
<template>
<div />
</template>
<script>
import { App } from '#inertiajs/inertia-vue';
export default {
mixins: [App],
props: ['initialPage', 'resolveComponent'],
}
</script>
In order to do this, modify according to how the library you use works.

How can I load an nested component dynamically in Vuejs without hardcoding the url

I followed Markus Oberlehner for loading Vue components via http. We have a Vue component precompiled as a .js file hosted on a separate server. When the user navigates to this loader component below, the call to externalComponent() successfully fetches the .js file and renders the component on this page. That is great. This only works if we hardcode the url in the loader component.
We are building a plugin architecture into our site. We have written some single page Vue component files. Each of these files is a plugin. We precomiled these .vue files into .js files according to Markus Oberlehner's helpful tutorial here: https://github.com/maoberlehner/distributed-vue-applications-loading-components-via-http.
We also have a Vue component in our main site - let's call it the loader component - that fetches a .js file and renders it into a component using the externalComponent() method - demonstrated in Markus's tutorial. This works, but since the MyComponent is a constant defined outside of the loader component's data object, we cannot dynamically inject the plugin_id of from the vue router into the .js file's url.
If you're curious why our urls don't end in .js it is because we are passing a url to an endpoint in our server instead. This endpoint fetches the .js file and returns it to our client.
<template>
<div>
<MyComponent />
</div>
</template>
<script>
import util from "~/js/util.js";
let MyComponent = () =>
/* If we hadcode the url, the page renders no problemo.
*
* util.externalComponent("http://localhost:8081/api/plugins/167/code");
*/
/* However, we'd like to fetch the plugin_id from the Vue router and inject that into the argument
* as I've tried to achieve in the line of code below.
*
* The following code does not work because Vue apparently loads the MyComponent element in the DOM
* before executing the created() hook. We get the error "plugin_id is not defined."
*/
util.externalComponent(
"http://localhost:8081/api/plugins/" + plugin_id + "/code"
);
export default {
name: "plugin",
components: {
MyComponent
},
data() {
return {
plugin_id: null
};
},
created() {
/* This line does indeed populate the plugin_id data variable, although this happens after the
* page attempts to load MyComponent
*/
this.plugin_id = this.$route.params.plugin_id;
}
};
</script>
So, how can we modify this code to dynamically insert the plugin_id into the url?
This is a nuxt project by the way.
Update
Here is an approach that works the first time I load the page, but consecutive loads are still a problem. Specifically, the first component just loads again regardless of whatever the new plugin id may be.
But this looks like the right direction...
<template>
<div>
<component v-bind:is="component" v-if="loadedUrl"></component>
{{ plugin_id }}
</div>
</template>
<script>
import util from "~/js/util.js";
export default {
name: "plugin",
props: [],
data() {
return {
loadedUrl: false,
component: null
};
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.loadedUrl = false;
vm.component = () =>
util.externalComponent(
"http://localhost:8081/api/plugins/" + to.params.plugin_id + "/code"
);
vm.loadedUrl = true;
next();
});
},
beforeDestroy() {
//does not seem to help.
console.log("in beforeDestroy");
this.component = null;
}
};
</script>

Problem when importing js-cookies in Main.js

I'm trying import js-cookies in my main.js
Main.js
import * as Cookies from "js-cookie";
Vue.use(Cookies)
Using in component
this.$Cookies.set('name', data.user, { secure: true });
Error
TypeError: Cannot read property 'set' of undefined
what is the problem?
I have tried a thousand ways and it still does not work.
Vue.use(name) is used to install a vue plugin. The package will need an install method that receives a vue instance.
#1
You can use the cookies packages without a plugin importing the module in the component
<script>
import Cookies from 'js-cookie';
export default {
methods: {
addCookie() {
console.log('adding the cookie');
Cookies.set('chocolate', 'chookies');
console.log(Cookies.get());
}
}
}
</script>
#2 you can add a VUE plugin and set a Cookies prototype function to the Cookies module.
(Prototype vue functions will be available for components, it's standard to prefix them with $).
src/CookiesPlugin.js
import Cookies from 'js-cookie';
const CookiesPlugin = {
install(Vue, options) {
Vue.prototype.$Cookies = Cookies;
}
};
export default CookiesPlugin;
src/main.js
import CookiesPlugin from './CookiesPlugin';
Vue.use(CookiesPlugin);
In the component
this.$Cookies.set('chocolate', 'chookies');
console.log(this.$Cookies.get());
You are using a NOT Vue (Vanilla JS library) library and you are trying to use it as a Vue resource.
Try using this one instead