Is there a smart function to import dynamic components automatically? - vue.js

How can I dynamically import dynamic components? I found a few examples, but they seem like a workaround. I couldn't find a clear explanation for that.
I import them one by one like that:
Vue.component('account', () => import('../components/Account')
Vue.component('settings', () => import('../components/Settings')
// etc… one for each component
and my main component is like that:
<component :is="componentName" :data="myData"/>
data: () => ({
componentName: 'account'
})
Is there a way to make a smart method for the first code?

Try this, adapted from the Laravel source:
// replace './' with the relative path to your components
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], () => import(files(key))))

I found the solution here.
I need dynamic imports on Webpack.
https://webpack.js.org/guides/code-splitting/

Related

Dynamic import of component based on variable name in NextJS

I'm looking for a way to use a component in a dynamic way:
const getDynamicComponent = (componentName) => dynamic(() => import(${componentName}), {
ssr: false,
loading: () => <p>Loading...</p>,
});
const Test = () => {
const router = useRouter();
const { component } = router.query;
const DynamicComponent = getDynamicComponent(component);
return <DynamicComponent />
}
Obiovusly if I specify a folder name there like components/${componentName} it searches ALL components.. and not the one specified in the variable.
I know the documentation states explicitly that template strings are not an option for dynamic imports, but I would like to know how I would be able to import a specific component from node_modules, without importing all node_modules folder 🙂
Only static strings are permitted?
I have a dynamic route file as [componentId].js which should import its component from node_modules based on the route name.. any ideas?
Should I try to configure babel in a specific way to make this work?
Thanks!
PS: I know it was asked here, but those answers are not quite correct as the whole folder is trying to get imported, not just the component specified.

How do I properly import multiple components dynamically and use them in Nuxt?

I need to implement dynamic pages in a Nuxt + CMS bundle.
I send the URL to the server and if such a page exists I receive the data.
The data contains a list of components that I need to use, the number of components can be different.
I need to dynamically import these components and use them on the page.
I don't fully understand how I can properly import these components and use them.
I know that I can use the global registration of components, but in this case I am interested in dynamic imports.
Here is a demo that describes the approximate logic of my application.
https://codesandbox.io/s/dank-water-zvwmu?file=%2Fpages%2F_.vue
Here is a github issue that may be useful for you: https://github.com/nuxt/components/issues/227#issuecomment-902013353
I've used something like this before
<nuxt-dynamic :name="icon"></nuxt-dynamic>
to load dynamic SVG depending of the icon prop thanks to dynamic.
Since now, it is baked-in you should be able to do
<component :is="componentId" />
but it looks like it is costly in terms of performance.
This is of course based on Nuxt components and auto-importing them.
Also, if you want to import those from anywhere you wish, you can follow my answer here.
I used this solution. I get all the necessary data in the asyncData hook and then import the components in the created () hook
https://codesandbox.io/s/codesandbox-nuxt-uidc7?file=/pages/index.vue
asyncData({ route, redirect }) {
const dataFromServer = [
{
path: "/about",
componentName: 'myComponent'
},
];
const componentData = dataFromServer.find(
(data) => data.path === route.path
);
return { componentData };
},
data() {
return {
selectedRouteData: null,
componentData: {},
importedComponents: []
};
},
created() {
this.importComponent();
},
methods: {
async importComponent() {
const comp = await import(`~/folder/${this.componentData.componentName}.vue`);
this.importedComponents.push(comp.default);
}

Vue.js routing not working by using parameter as a route

I'm trying to use parameter only as a route as I need URL like localhost:8080/road. But, it's not working properly.
My code:
{
path: "/:id",
name: "id",
component: Blog
},
Whenever I enter a url like localhost:8080/dashboard or any other URL, it uses the Blog component. How can I solve it?
If your goal is to cut down on lines of code in your router definition, you could optimise this somewhat with an array of component names mapped to route definitions. For example
const components = ["Blog", "Road", "Dashboard"]
// creates kebab-cased slugs from Pascal cased component names
const toSlug = component =>
component.replace(/(?<=\w)[A-Z]/g, c => `-${c}`).toLowerCase()
const routes = components.map(name => ({
name,
path: toSlug(name),
component: () => import(`#/components/${name}.vue`)
})
Using static parts in the import path like #/components/ and .vue help Webpack optimise bundling.

Laravel Mix lazy load components from vue files

im trying to load components from files rather than defining them within the app.js, but I also want to lazy load them, so trying to mix the 2 together.
So a lazy loaded component definiton would look like so:
Vue.component(
'carousel',
() => import(
/* webpackChunkName: "carousel" */
'./components/carousel.vue'
)
);
And registering the components using the files is like so:
const files = require.context('./', true, /\.vue$/i);
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));
How can I combine this?
My current attempt is as follows, but of course I have missed out the webpackChunkName as no idea how to do that:
const files = require.context('./', true, /\.vue$/i);
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], () => import(files(key)) ));
This doesn't work however, I just get an error saying:
WARNING in ./resources/js/app.js 9:11-29
Critical dependency: the request of a dependency is an expression
# multi ./resources/js/app.js ./resources/sass/index.sass
Ended up using the below code. I think after looking at it, it is similar to what Excalibaard posted, but I couldn't get that to work for me:
const files = require.context('./components', true, /\.vue$/i, 'lazy');
files.keys().map(key => {
const name = key.split('/').pop().split('.')[0];
Vue.component(name, () => import(/* webpackChunkName: "[request]" */'./components/' + key.slice(2)));
});

How to import all Vue components from a folder?

I am trying to load all my vue's components automatically from a folder,
which is working fine if I don't use vue "Async Components".
Once I try to use Async Components with import .. I get this error:
10:11-36 Critical dependency: the request of a dependency is an expression
My code that load all components, which generate this error:
const ComponentContext = require.context('./', true, /\.vue$/i);
ComponentContext.keys().forEach((componentFilePath) => {
const componentName = componentFilePath.split('/').pop().split('.')[0];
Vue.component(componentName, () => import(componentFilePath));
});
How to fix this ? or is there is any other way to accomplish this?
Ok, I needed to add 'lazy' in:
const ComponentContext = require.context('./', true, /\.vue$/i, 'lazy');
and then:
Vue.component(componentName, () => ComponentContext(componentFilePath));
I had to merge the question with an answer here to get this final solution:
const ComponentContext = require.context('./', true, /\.vue$/i, 'lazy');
ComponentContext.keys().forEach((componentFilePath) => {
const componentName = componentFilePath.split('/').pop().split('.')[0];
Vue.component(componentName, () => ComponentContext(componentFilePath));
});
The 'lazy' third param was added to require.context(), and () => import() was changed to () => ComponentContext().
I can see the bundles in the Network tab of the dev tools pane, and I don't see the bundles when I navigate to a page that doesn't render any of the auto-loaded components.
Therefore, I am reasonably-certain the above code is autoloading and dynamic importing. I will also confirm that in my project, I am using:
require.context('~/components/common', true, /\.vue$/i, 'lazy')
Note where mine is different at ~/components/common compared to ./. Your project needs will likely be different. In mine, the ~ is a Webpack alias for /resources/js, so my full path would be ./resources/js/components/common. The rest of the code above is an algorithm, and can remain untouched.
Instead of
Vue.component(componentName, () => import(componentFilePath));
Try
Vue.component(componentName, ComponentContext(componentFilePath));
Or
Vue.component(componentName, ComponentContext(componentFilePath).default);
not sure about the default part.