I'm using plotly.js in my Nuxt.js project, and I kept receiving an error, saying document not defined, when plotly.js was imported. Nuxt.js documentation doesn't provide clear instruction on how one can make a component load and generate client-side only.
To overcome this issue, the component you're using must be placed inside the client-only environment:
<client-only>
<component ...></component>
</client-only>
Furthermore, you need to store the component's .vue file somewhere other than the components directory that Nuxt.js automatically creates, because, during the build process, Nuxt.js automatically collects all of these files in order to bundle them, which will invoke the import for plotly.js inside the component. I created a directory called components-lazy and placed the component there.
Finally, you have to lazy-import the component in the page, layout or parent component, you're intending to use it in. I used the following syntax for this task:
export default {
...
components: {
Plotly: () => import('#/components-lazy/Plotly'),
...
}
...
}
This will ensure that this particular component is only imported and rendered client-side.
Related
Is there a way to load a plugin by default for every new Vue()?
I use a library that creates it's own Vue and I need it to have a plugin included to it as well.
Vue.component('my-component-name', {
// ... options ...
})
These components are globally registered. That means they can be used in the template of any root Vue instance (new Vue) created after registration.
More information in the official documentation.
I have built some components such as modals and reviews that I want to use and reuse just about everywhere in my site.
I have made a single global.js file in the plugins folder, So iv'e just registered this in my nuxt.config.js file once.
In my global.js file i've imported vue and called the components
import Vue from 'vue';
Vue.component('component-modal', () => import('#/components/modal'));
Vue.component('component-modal-other', () => import('#/components/modalOther'));
Vue.component('component-reviews', () => import('#/components/reviews'));
The reason for this is that now I don't have to do component import on every instance that I want to use it for I just call the component <my-component>.
However I've just switched to Universal mode and i'm now getting hydration warnings that are all coming from my global.js components file that I made in my plugins folder.
Should I not have a global.js file and each component that I want to use globally have it's own file in the plugins folder? Or do I just need to import the component when I need it locally in the file that is requiring it?
What is the best way to re-use and register global mini components that I have created?
Vue Warning
The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render
The only way I can avoid this warning is not to put my components into a global.js component file and register it with Nuxt plugins. Only use the component import into each instance which kind of defeats the purpose of global components
try this
import Modal from '#/components/modal'
Vue.component('Modal', Modal)
in your view
</modal>
I want to create a website with two separate applications which share some components and store.
index is the public application where I want to use nuxt.js to have SSR.
admin should be a classic SPA where SSR is not needed.
My first idea was to create a multi-page vue application as described in the vue-cli docs at https://cli.vuejs.org/config/#pages
However I'm unsure if this feature fits my needs and if it's possible/advisable to have a nuxt.js app alongside a bare vue.js application, because nuxt.js has a different project structure.
Is there any way to configure nuxt.js so it fits in the default project structure of vue or to configure vue to use the nuxt.js folder structure?
Create multiple Vue Applications with (some) shared source-files (components/store/mixins/etc)
It is easily possible to share resources across multiple Vue-Apps simply by importing the respective resource everywhere you would like to use it, e.g.:
// in /components/MyComponent.vue
<template>
<div>I'm a shared component</div>
<template>
// in /user-app/entry.js
import MyComponent from '../components/MyComponent';
Vue.component('MyComponent', MyComponent);
new Vue({...})
// in /admin-app/entry.js
import MyComponent from '../components/MyComponent';
Vue.component('MyComponent', MyComponent);
new Vue({...})
Where it becomes a little bit complicated
To actually create the seperate apps you will have to use some built-process. By far the most common tool to build Vue apps (and the one used by VueCLI & Nuxt) is WebPack.
To create multiple apps with WebPack you need to do one of two things:
simply use the integreated build-processes of the VueCLI and Nuxt separately. It will work out of the box.
create your own WebPack configuration & the EntryPoint of every single app in WebPack's configuration. NOTE: It is not trivial to use your own build-process for Nuxt, if you really want to use Nuxt I advice you against it. Run with two seperate build-processes instead.
The WebPack configuration itself is a JavaScript Object. The relevant key to declare your EntryPoints is sensibly called entry. Here you specify the name of your EntryPoint and the corresponding path (the path to the entry-file).
The 'Pages' feature of the VueCLI uses this under the hood. However, I believe it is very well worth it to learn how to use WebPack yourself. It is not that complex and will significantly benefit most or all of your JavaScript projects.
A basic example configuration could look like this:
// in webpack.config.js
module.exports = {
mode: 'development',
entry: {
admin: path.resolve(__dirname, './admin-app.js'),
user path.resolve(__dirname, './user-app.js'),
},
// other config
}
WebPack is very well documented: https://webpack.js.org/concepts/
I've build a Vue JS 2.x plugin using the vue create <my-plugin-name> and the vue-cli-plugin-p11n plugin. I have a directory structure that consists of a dist/ directory with a few compiled JS files and a main src/ folder containing my components.
I'd like to use these components within Nuxt JS 2.4.x.
I've created a plugins/LesForm.js plugin, and have added '#/plugins/LesForm' to my array of plugins within nuxt.config.js.
My plugin file consists of:
import Vue from 'vue'
import LesForm from 'LesForm'
Vue.use(LesForm)
I'm then trying to import the plugin with it's component into a page by doing: <LesForm></LesForm> within my page.
I initially get the error of:
Failed to mount component: template or render function not defined., but adding the following to my script tag of a page seems to remove that error, but this doesn't seem right?
<script>
import LesForm from 'LesForm'
export default {
components: {
LesForm
}
}
</script>
without this, my page breaks, and adding it I get: Failed to mount component: template or render function not defined. as an error with no sign of my Vue plugin that I've made with some markup.
I'm using the Vue Cli service to build my plugin via NPM.
Attached is a screenshot of my plugin directory structure:
I'm trying to test if validation works for a form with vee-validate and vue-test-utils. I also use nuxt and have created a custom plugin which install vee-validate and provides two custom computed properties as a mixin.
The problem is that I need a way to use these mixins within a localVue instance, however, I cannot just import the whole file as it results in vee-validate being installed two times on the main vue instance. I also cannot just say localVue.use(MyCustomVeeValidatePlugin) because the plugin doesn't have an install method ("plugins" in nuxt are somewhat different than in vue).
What works is creating a file which exports isFormValid and isFormChanged and then have the plugin import these methods. Then I also need to import these methods in the test file and create a mixin for the localVue instance. I would much rather prefer defining the mixin in a single plugin file. I know this is very specific but has anyone had a similar problem? I could imagine rewriting the plugin to be more like it is defined in the Vue.js docs (with an install method) and install it somehow.
Plugin:
import Vue from "vue";
import VeeValidate from "vee-validate";
Vue.use(VeeValidate);
//create global mixin for checking if form is valid
//note: every input element needs a name
Vue.mixin({
computed: {
isFormValid() {
return Object.keys(this.fields).every(key =>
this.fields[key].valid);
},
isFormChanged() {
return Object.keys(this.fields).some(key =>
this.fields[key].changed);
}
}
});
As far as I know, based on the recommendations I read in "Testing VueJs Applications (https://www.manning.com/books/testing-vue-js-applications), the author, who is also the main author of the vue-test-utils recommends:
I’ve already spoken about why you should use a localVue constructor and avoid installing on the base constructor. This is especially important for Vue Router. Always use a localVue to install Vue Router in tests. You must make sure that no file in your test suite imports a file that calls Vue.use with Vue Router. It’s easy to accidentally import a file that includes Vue.use. Even if you don’t run a module, if the module is imported, then the code inside it will be evaluated.
Based on that recommendation, I moved Vue.use() calls out of files like store.js and router.js and into main.js, which isn't used during testing.