Vue plugins usually requires a global setup in app entrypoint by Vue.use(somePlugin). Doing so increases the bundle size for all pages, which is often bad and that it is better to defer the downloading of the module until when the module is actually being used, aka lazy loading or code spliting.
How do I lazy load a plugin if only one page in my Vue app needs it?
To answer the OP's question more directly: You can't lazy load a plugin.
According to the documentation, plugins by definition provide globally-accessible functionality and must be setup with Vue.use() before the Vue instance is created. Due to this, they'll always be bundled with the entire Vue instance (in a vendors chunk, for example).
What you want is to lazy load the functionality in a smaller scope, at a component level. Depending on the plugin, the plugin module should also support some sort of direct code importing at a component level, like this one does. Because it just uses import statements, they can be async loaded.
TL;DR: Anything using Vue.use() can't be lazy loaded. Async imports can.
One of the options is to call your plugin file in created/mounted hook and do the stuff you want.
Just import it on the specific page an example would be "Slide" from "vue-burger-menu"
<script>
import { Slide } from "vue-burger-menu"
export default {
components: {
Slide
}
}
</script>
Related
I have added ReCaptcha plugin using Vue.use(ReCaptcha, {some options}) in Gridsome main.js which is displaying on all pages.
How to add plugin for a particular page only in gridsome?
I've never used ReCaptcha or Gridsome before, but generally, if you install a plugin using npm, then the simplest way to use it on a single page would be to import the plugin to the specific component rendered on the route you want to use it on. i.e
/* === MyComponent.vue === */
<script>
import plugin from 'packageName';
// or
import { pluginExport } from 'packageName';
export Default{
// You can then use the plugin/pluginExport here
}
From there you should be able to use the package in that specific component as you normally would if you implemented it app-wide with Vue.use. In some cases, depending on how the plugin is meant to be used, you may need to register the imported plugin Module as a child component in the components object. Like this vuejs QR Code generator for example.
In case of using UI frameworks (like Bootstrap-Vue, ElementUI or Vuetify, etc.) in our Vuejs application, it's possible to import entire UI framework components & stylesheets from node_modeules in the App.vue(or in the application entry point), or importing a particular ui component in particular Vue file/Component as needed.
The demonstration of these two approches looks like:
For scenerio 1
in App.vue
import BootstrapVue from 'bootstrap-vue'
For scenerio 2
in any particular .vue file
import {BContainer} from 'bootstrap-vue'
So,In case of the first option, does it make the application slower or less performing as all components from UI framework is loading for each route change? Also, its's loading some components that are not needed.
On the other hand, it's quite inconvenient to import each ui component in every .vue file.
So what is the best practice for small or large scale web applications?
Does the practice is same for other JS frameworks/Libraries link React or Angular?
Thanks in advance.
Scenario 1 – register all components globally
All components from the library will be available to use everywhere.
If you change or update the library and some of the component names have changed, you won't get any errors at build time.
Scenario 2 – pick-and-choose specific components locally
Gets annoying to have to import each component when you want to use it.
Only components that are actually used (imported) will be included in the bundle (if using webpack or something similar). Results in a smaller bundle size.
It is clearer to look at the template and know where each component comes from. If you have lots of globally-defined components then there is no clear link between a component and where it came from.
If you change or update the library and some of the component names have changed, you will get build errors due to missing modules.
So,In case of the first option, does it make the application slower or less performing as all components from UI framework is loading for each route change? Also, its's loading some components that are not needed.
It does make a difference when you are importing the entire package globally. Also it won't reload the package for every route change as you have the import inside App.vue. It will be done once when your app is loaded for the first time.
I found this article very helpful on how to optimize loading 3rd party components into vue app.
On the other hand, it's quite inconvenient to import each ui component in every .vue file.
End of the day it all comes to how much of tradeoff your development team is willing to make between optimizing the app and adding multiple lines of import code into individual components.
Let's say there is a global component BIcon.vue available everywhere.
And another component, but regular not global, called BIconFake.vue.
We can override BIcon.vue by BIconFake.vue like that:
<template>
<div>
<b-icon icon="plus"><!-- <- Here is it BIconFake component! -->
</div>
</template>
<script>
import BIcon from '~/components/BIconFake'
export default {
components: {
BIcon // <- BIconFake component inside!
}
}
</script>
By this way, Vue.js will display BIconFake component instead of regular BIcon component.
I tried to pass props, events or attributes and it works like expected.
Vue.js is awesome... and big. Really, I don't know everything about it, and I don't want to see side effects or unexpected behavior when doing this override.
So, I want to know if it's safe to do that? Does it make a mess in Vue.js instance? What about memory?
we can override component with pure vue.js. Also, I made this example for Buefy, but we can do that with any UI frameworks like Quasar, Vuetify...
Thinking globaly, Is it good to override components of UI frameworks? What about security, scalability and maintenability?
In fact, I searched a way to build a plugins or addons system to my Nuxt.js app, like wordpress plugins.
Is it a good architecture to start building my app by overriding vue component? Is there another way to build app addons for vue, by using npm or webpack?
If you are going to wrap existing components like that then you should keep in mind the Liskov substitution principle. <b-icon-fake> can likely be used in place of <b-icon> provided that it:
accepts the same props
emits the same events
exposes the same public methods (if it is used with a ref)
behaves in the same way
Most of those points probably do not apply for a simple <b-icon> component.
Also keep in mind the template of your wrapped component now includes an extra <div> around it. This can interfere with styling and things like that.
You can eliminate the additional memory overhead by using a functional component instead, but you will need to write the render function manually to preserve the behavior of the wrapped component. But honestly I wouldn't worry too much about memory usage unless you have determined it to be an issue (after profiling your app).
In terms of whether it is "good" to do this or not, I can't say. There are advantages and disadvantages. In my opinion, wrapping components is fine as long as you are the only consumer of the wrapper component and doing so doesn't affect any existing usage of the wrapped component outside of your code.
When I make changes to any function .js file under ./src/fn hot reload is not working and triggers a page reload.
I have been trying to make configure vue.config.js to include the directory to HMR correctly. Also I tried using my custom helpers as a Vue.use(myPlugin).
/* functions.js (just a part of it) */
export const Functions = {
game: {
helper: helpers,
turn: turn,
ui: ui,
validate: validate,
card: cards
},
}
/* main.js */
import Functions from './functions.js';
Vue.prototype.$myFn = Functions;
Expected HMR to work but instead get a full page reload when making changes to functions.js (or any underlying js file imported in functions.js)
Adding your own objects and functions to the Vue prototype is a bit of an anti-pattern. In this case, Webpack can't determine the extent of the changes made so it falls back to a page reload. This is because ES modules can be statically analysed whereas global objects cannot be.
Here's some articles about static analysis:
Static Program Analysis
ES Modules in Depth
Remove the functions from the Vue protoype and always use ES modules to structure your functions. Then you can import them into other modules or components without using the legacy style global hack approach of yesteryear.
I have a vue.js application and in the main.js file I have configured the Vuei18n as per the documentation. This is working perfectly and in order to access this in other components, I have added this to new Vue() instance and this is now accessible (with this.$i18n).
Now I have created a validator.js file for validation rules and I need to use the this.$i18n there, but its not working. I have also tried Vue.prototype.$i18n but that too not working. Can someone help me to find out where I went wrong ?
exporting the i18n variable
I'll assume your app is a vue-cli app, or at least that you use webpack to build it
and therefore can use ES modules.
Working with vue-i18n you would do something like the following:
// step 1: define the i18n object via new Vue18n
const i18n = new VueI18n({
locale: DEFAULT_LANGUAGE,
messages,
});
// step 2: setup the Vue object to use this object:
new Vue({
i18n,
... store, router.... whatever
})
Where messages contain all the JSON's with the translations keys and values.
I guess you already are doing something like this.
And now, in your validator module you need the very same i18n object you plugged to Vue.
Instead of trying to get to Vue in your validator, you can just plain export the i18n varible from main.js:
export {i18n}
So, in your validator.js file, you can just import it:
import {i18n} from '#/main.js' // or whatever is the path
This is pretty much how I'm solving the validator internationalization problem in my own application.
Important note: circular dependencies
If you're already importing the validator.js in your main.js, you won't be able to import i18n from main in your validator module. To avoid such a problem, you would move the i18n initialization and exportation to another module, such as i18n.js, so the validator and the main file can import it independently.
Without es6 modules
In case you're not using webpack or another bundler to bundle your code, you can still just export the i18n object to the window object:
window.i18n = i18n
and then use it from whatever file. You just need to be careful to store the i18n object in window before any file will try to access it.
I think what you're looking for is Custom Events. According to this documentation, you should be able to emit your variable with something like below
this.$emit('send-i18n', this.$i18n)
Still according to the documentation, try to use v-on:send-i18n to retreive your value.
Hope it works.