Dynamic import of component based on variable name in NextJS - variables

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.

Related

Nuxt Generate dynamic routes from the store

I'm using nuxt.js and now need to generate my dynamic pages by running npm run generate. However my list items needed to make dynamic items are stored in the store, so I need to map over them somehow so the generate can make the routes for them
How can I access the store in my nuxt.config.js?
generate: {
dir: 'wwwroot', //override the default generation dir to create everything straight in wwwroot
routes() {
let vdc = this.$store.vdcServers.map(server => `/virtual-data-centres/${server.slug}`);
return Promise.all([vdc]).then(values => {
return values.join().split(',');
})
}
}
Output
ERROR Could not resolve routes
FATAL Cannot read properties of undefined (reading '$store')
To my knowledge, you cannot access the store from that place. Maybe with some hooks? I doubt.
Meanwhile, if you have your elements available in your store you should be able to find them back by making a quick axios call or like I think.
This kind of approach is totally fine
import axios from 'axios'
export default {
generate: {
routes(callback) {
axios
.get('https://my-api/users')
.then(res => {
const routes = res.data.map(user => {
return '/users/' + user.id
})
callback(null, routes)
})
.catch(callback)
}
}
}
It may be a bit of code duplication, meanwhile, it's still the simplest way to go.
Otherwise, you could try to persist it to some localStorage or any similar solution, to have it both in Vuex and during your generation.

Fetch data from local JSON file with Nuxt Pinia

Is it possible to fetch a local .json. file using fetch()? I originally used the import method but the site's data doesn't get updated unless the page gets reloaded.
I tried doing this but it's not working:
stores/characters.ts
export const useCharactersStore = defineStore("characters", {
state: () => ({
characters: [],
}),
getters: {
getCharacters: (state) => {
return state.characters;
},
},
actions: {
fetchCharacters() {
fetch("../data.json")
.then((response) => response.json())
.then((data) => {
this.characters = data.characters;
});
},
},
});
app.vue
import { useCharactersStore } from "~/stores/characters";
const store = useCharactersStore();
onMounted(() => {
store.fetchCharacters();
});
Any help would be appreciated.
maybe a bit late but I have encountered the same problem migration from Nuxt 2 to Nuxt 3.
I'm certainly no expert on this, so if anyone finds a better way or if I'm totally wrong please let me know !
Whenever you import a json file in vue code they are imported as a module, that get's embedded within the code compilation on build (Vue Docs). Tu use json as a external file you need to place your json within the /public directory and use axios or fetch to load the file with a lifecyle hook.
This could be mounted() for options api or beforeMount()/onMounted() with composition api.
However some important annotations for this method.
If the json file you want to use in your app is not reactive, i.e. won't change, you should place this in the static folder of the nuxt app.
In your example you fetch '../data/...', this would imply the server knows the domain to look for. It can't call the route like this, you would have to give the full url if you put your json file in the static folder.
Set the baseUrl in the of your nuxt.config.ts, see docs for specifications.
Then you can access the static folder with your .env variables
--> $fe
Then in you data script you can access your json file
async getJson(some parameters){
const data = $fetch('your domain with the runtimeConfig composable').then((data)=>{ console.log(data)});
Sidenote you can also load the file from the server-side using fs.readFile
read more about this in this awesome post here

Vue static assets are not accessible to a library

I am using a single file Vue component and import a face-api library. I want to use a function from that library, loadSsdMobilenetv1Model(url), which takes URL of folder, where the necessary files are located and loads them. The function however cannot fetch the files if I use #/assets/weights as url (# in Vue represents the src folder). I would like to be able to host the assets for. I'm able to read files from the assets folder folder with require('#/assets/file.json), but the library seems to need a static url.
What is the best solution in my situation? Maybe I'm missing some understanding.
Can I make it so that the assets folder is served and accessible?
Here's my component and the comments show some things I've tried:
<template>
<div>...stuff...</div>
</template>
<script>
import * as faceapi from 'face-api.js';
async function load() {
// example below: If I serve the files on a separate port with CORS allowed, the function loads files fine.
// const MODEL_URL = 'http://127.0.0.1:8081/weights/';
// example below: this does not work, but I would like this to work!
const MODEL_URL = '#/assets/weights';
// example below: also doesn't work, conscious of relative paths
// const MODEL_URL = '../assets/weights';
// example below: a file loads, but I can't just this unfortunately
// return require('#/assets/file.json')
return await faceapi.loadSsdMobilenetv1Model(MODEL_URL);
}
export default {
mounted() {
var promise = load();
promise.then((model) => {
this.model = model
}, (reject) => {
console.log(reject)
// alert(reject);
})
},
name: "Home",
data() {
return {
model: null
}
}
};
</script>
I'm not sure if it's relevant, but I set up the project with
vue create
and run the dev environment with
nmp run serve

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 CLI dynamic import from project module

I know it is possible to imports component from a bundled webpack file like this
import {componentA, componentB} from '../component.bundle';
Is it possible to achieve this same as a dynamic import, like this.
const url = '${window.location.origin}/assets/default/js/bundle/vue_data.bundle.js';
this.getAxiosInstance().get(url).then(response => {
const {Add, Edit, Filter, View} = () => import(response.data);
});
If yes, please how? Thank you
Yes, using dynamic imports:
To dynamically import a module, the import keyword may be called as a function. When used this way, it returns a promise.
I'm assuming from your url example that your import is in the assets directory of your project (i.e. src > assets) and not actually on an external domain. In that case, you don't need axios. You would do it like this:
const path = 'assets/default/js/bundle/vue_data.bundle.js';
import('#/' + path).then(module => {
const {Add, Edit, Filter, View} = module;
});
You need to hardcode the #/ portion or there will be issues, e.g. if you tried to do import(path) with const path = '#/assets/default/js/bundle/vue_data.bundle.js'