Nuxt plugin imports abuse vendors - javascript

I am trying to use vuejs-datepicker in a nuxt app, everything is done by nuxt plugin usage standarts.
plugins/vue-datepicker.js
import Vue from 'vue'
import Datepicker from 'vuejs-datepicker'
Vue.component('Datepicker', Datepicker)
nuxt.config.js
plugins: [
{ src: '~/plugins/vue-datepicker', ssr: false }
],
But even when it is not used I am getting its dist uploaded in the vendors/app....js after the build. How can make nuxt create a separate chunk for it and import that chunk only in the pages which are using it?

So yeah, there is basically a feature request open for this kind of use-case.
But looking at the Nuxt lifecycle, it looks like the plugins are imported even before the VueJS instance is done. So, you cannot lazy load it if it's done ahead of Vue.
But, you can totally import vuejs-datepicker on the page itself, rather than on the whole project. This may be enough
import Datepicker from 'vuejs-datepicker' // then simply use `Datepicker` in the code below
If it's not, you can maybe try this solution: https://github.com/nuxt/nuxt.js/issues/2727#issuecomment-362213022
// plugins/my-plugin
import Vue from 'vue'
export default () => {
// ...
Vue.use(....)
}
// adminLayouts
import myPlugin from '~/plugins/my-plugin'
export default {
created() {
myPlugin()
}
}
So, the downside is that you have to import the component each time that you need it rather than having it globally but it also allows you to load it only on the concerned pages too and have it chunked per page/component.

If you were trying to find a way to split the component from vendor but you were getting a document is not defined error you can use this syntax to import your component, it will create a separate chunk with your component and use it only in client-side.
components: {
Datepicker: () => import('vue-datepicker')
}
Also, it would be helpful to wrap your component in <client-only> tag for most of the cases.

The plugin I was trying to import used window. For this reason, any other suggested workaround still caused nuxt to crash or error in my case. I searched the whole wide web and the solution below is the only one that allows my app to run.
Instead of importing the plugin with an ES6 import, you can import it in your mounted hook, which should run in the client only. So:
async mounted() {
const Datepicker = await import('vuejs-datepicker');
Vue.use(Datepicker);
}
I do not know about the specific plugin you are trying to use, but in my case I had to call Vue.use() on the default property of the plugin, resulting in Vue.use(MyPlugin.default).

Related

react context does not work when imported from relative part

I have monorepo with a UI library inside packages which contains a lot of components. Every component also has a *.stories.tsx file. Under the apps folder is the storybook project, which loads the stories from #my-ui-library.
I have a decorator in the storybook config, so my ThemeContextProvider is wrapped around everything (ThemeContextProvider is also imported from #my-ui-library).
Does not work:
button.tsx
import { ThemeContext } from '../../ThemeContext'
Does work:
button.tsx
import { ThemeContext } from '#my-ui-library'
Using the relative import I get the error that theme, which is stored in ThemeContext, is undefined.
Now, that itself wouldn't be a problem if VS Code wouldn't auto import from the relative path and I didn't have to change it manually everywhere.

Is there a way to use the screenfull javascript library within the Nextjs framework?

I've been trying to use Dynamic Importing in Nextjs in order to use the screenfull library but it hasn't worked.
import dynamic from "next/dynamic"
import screenfull from 'screenfull';
const Screenfull = dynamic(()=>{return import("screenfull")},{})
You're using dynamic imports incorrectly. The idea is that you can import part of a JS module inside of another piece of JS code, so you don't have to preload or load the entire library. An example might be doing a dynamic import after an async call.
Next has some other great examples of how to use this functionality in your application.
you can create file in #utils folder with below code:
import screenfull from 'screenfull';
export default screenfull
then in your component do something like so:
import dynamic from 'next/dynamic';
const screenful = dynamic(() => import('../#utils/screenfull'))
The first question that comes to mind is what's the error you're getting?
There's no reason you shouldn't be able to import any library you've installed locally!
Did you actually install that package by running npm install screenfull on your terminal?

in vue.js how do I serve components that require js libraries?

So I'm new to the Vue CLI and one of the features that I would like to use is
vue serve <component name>
The problem I am immediately running into is there are some js libraries like moment that I am using in those components, so do I need to add an import statement in my component just for local testing? Is there anyway to set this globally and if so can I access it when i try to serve an individual component?
Once you run npm i -s moment, you can either import moment in your main.js Vue entry point, like this:
import moment from 'moment';
Vue.use(moment);
Or, you can use it locally in your component script, with just a local import within the <script></script> tag.
import moment from 'moment';
My preference is the former, since it allows me to reduce duplication if I need it in multiple files. Either way, to access in a function, once it is imported in one of those two ways, you can use it in component methods and lifecycle hooks.
Import your plugins in your main.js and then use like so;
import Vue from "vue";
//this is called only once before you start importing other packages
import YourPlugin from "yourplugin";
Vue.use(YourPlugin)

Is importing only required components per component a good idea in Vue

I was wondering if it is beneficial for performance in Vue to only import necessary dependencies per component or if all dependencies that are used in some components should just be loaded globally? How does Vue compile the components? Is it the case that all of them are loaded anyway when one page of the app is loaded, or are components also loaded on-the-go?
More concrete:
Is it better to do this:
<template>
... Some template code
</template>
<script>
import { MdDialog, MdContent, MdButton } from 'vue-material/dist/components'
export default {
...
}
</script>
Or is it better to import these things globally in app.js, even if some components only use a fraction of them?
This should be a matter of preference.
It won't have a noticeable impact on performance as the build process handles these multiple imports.
If you chose to import locally you will see where things come from... Otherwise on larger codebase it could lead to a lot of confusion.
Another thing is if you decide to make async component import. If the imports are only used in the dynamically imported component they should come with it's chunk, otherwise if they get imported in more than one component local importing would mean code duplication...
I hope I was helpful.

Dynamically loading React components

I'm thinking about building a web application, where people can install plugins. I'd like plugins to be able to define React components that will be rendered to the page, without recompiling the main JavaScript bundle after installing the plugin.
So here's the approach I'm thinking of:
Bundle the main JavaScript with React as an external library, using webpack.
Have plugin authors compile their components with React as an external library as well.
This way, I'm only running one instance of React. I could probably do the same with some other frequently used libraries.
The problem then, is how to dynamically load these plugin components from the server. Let's say I have the following component:
class PluginRenderer extends React.Component{
componentWillMount() {
getPluginComponent(`/plugins/${this.props.plugin}/component.js`).then((com) => {
this.setState({pluginComponent: com});
})
}
render() {
var Plugin = this.state.pluginComponent;
return Plugin ? <Plugin {...this.props} /> : "Loading..."
}
}
How could getPluginComponent be implemented?
It's an interesting problem I also faced some months ago for customer work, and I didn't see too many document approaches out there. What we did is:
Individual plugins will be separate Webpack projects, for which we provide either a template or a CLI tool that generates project templates.
In this project we define Webpack externals for shared vendor libraries already used in the core application: React, Redux, etc. This tells the plugin to not include those in the bundle but to grab them from a variable in window we set in the core app. I know, sounds like sucks, but it's much better than having all plugins re-include 1000s of shared modules.
Reusing this concept of external, the core app also provides some services via window object to plugins. Most important one is a PluginService.register() method which your plugin must call when it's initialized. We're inverting control here: the plugin is responsible to say "hi I'm here, this is my main export (the Component if it's a UI plugin)" to the core application.
The core application has a PluginCache class/module which simply holds a cache for loaded plugins (pluginId -> whatever the plugin exported, fn, class, whatever). If some code needs a plugin to render, it asks this cache for it. This has the benefit of allowing to return a <Loading /> or <Error /> component when a plugin did not load correctly, and so on.
For plugin loading, this PluginService/Manager loads the plugin configuration (which plugins should I load?) and then creates dynamically injected script tags to load each plugin bundle. When the bundle is finished, the register call described in step 3 will be called and your cache in step 4 will have the component.
Instead of trying to load the plugin directly from your component, ask for it from the cache.
This is a very high level overview which is pretty much tied to our requirements back then (it was a dashboard-like application where users could add/remove panels on the fly, and all those widgets were implemented as plugins).
Depending on your case, you could even wrap the plugins with a <Provider store={ theCoreStore }> so they have to access to Redux, or setup an event bus of some kind so that plugins can interact with each other... There is plenty of stuff to figure out ahead. :)
Good luck, hope it helped somehow!
There is a HOC component that you can import to do this. Components are dynamically loaded as micro apps into your host application.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
window.React = React;
window.ReactDOM = ReactDOM;
ReactDOM.render(<App />, document.getElementById('root'));
// app.js
import React from 'react';
import ReactDOM from 'react-dom';
import MicroApp from '#schalltech/honeycomb-react-microapp';
const App = () => {
return (
<MicroApp
config={{
View: {
Name: 'redbox-demo',
Scope: 'beekeeper',
Version: 'latest'
}
}}
/>
);
});
export default App;
The components are not installed or known at design time. If you get creative, using this approach you could update your components without needing to redeploy your host application.
https://github.com/Schalltech/honeycomb-marketplace#using-micro-apps
I presented an alternative approach on a similar question. Recapping:
On your app
import(/* webpackIgnore: true */'https://any.url/file.js')
.then((plugin) => {
plugin.main({ /* stuff from app plugins need... */ });
});
On your plugin...
const main = (args) => console.log('The plugin was started.');
export { main };
export default main;
See more details on the other question's page.

Categories