I have a multiple Svelte stores that looks like this:
import { readable } from "svelte/store";
export const NatureStore = readable([
{
name: "nature",
description:
"Nature is what makes us all so we need to beautify it. This represent what we all need to survive in a civilization.",
images: {
src: [
"...",
],
description: [
"...",
],
},
},
]);
All my stores have the same organization.
Now my main problem is that I need to subscribe to a specific store depending on a variable when the component is loaded.
Like for example if my variable is var = 'nature' I want to subscribe to nature. I could do it with ifs and elses, but that won't be efficient at all. So I wonder if there's a way to do it in a better way.
For now I only subscribe to one store and it looks like that:
<script>
import { NatureStore as nature } from "../../stores/nature";
import { BlooperStore } from "../../stores/bloopers";
import { NightStore } from "../../stores/night";
import { PortraitStore } from "../../stores/portrait";
import { PurpleStore } from "../../stores/purple";
import { UrbanStore } from "../../stores/urban";
import { UrbexStore } from "../../stores/urbex";
import { onDestroy } from "svelte";
//parameter passed with the router
export let params;
let category = params.category;
let pictures = [];
const unsubscribe = nature.subscribe((data) => {
pictures = data;
});
onDestroy(() => unsubscribe());
</script>
But i want something like this :
<script>
import { NatureStore as nature } from "../../stores/nature";
import { BlooperStore } from "../../stores/bloopers";
import { NightStore } from "../../stores/night";
import { PortraitStore } from "../../stores/portrait";
import { PurpleStore } from "../../stores/purple";
import { UrbanStore } from "../../stores/urban";
import { UrbexStore } from "../../stores/urbex";
import { onDestroy } from "svelte";
//parameter passed with the router
export let params;
let category = params.category;
let pictures = [];
//here setting the subscribe to the category variable
const unsubscribe = category.subscribe((data) => {
pictures = data;
});
onDestroy(() => unsubscribe());
</script>
If my explanations are not clear leave a comment I'll answer as quick as possible.
Thanks for your help.
You can create a mapping from category to store and just use that to find the correct one. The mapping could be extracted from the stores themselves or has to be created manually. As the store contents are an array, not an object, the former approach might not work.
One should not manually subscribe in Svelte files, just use $-syntax and reactive statements. That way you can't forget to unsubscribe and that happens automatically.
E.g.
<script>
import { NatureStore } from "../../stores/nature";
import { BlooperStore } from "../../stores/bloopers";
import { NightStore } from "../../stores/night";
import { PortraitStore } from "../../stores/portrait";
import { PurpleStore } from "../../stores/purple";
import { UrbanStore } from "../../stores/urban";
import { UrbexStore } from "../../stores/urbex";
export let params;
$: category = params.category;
const mapping = {
nature: NatureStore,
bloopers: BlooperStore,
night: NightStore,
portrait: PortraitStore,
purple: PurpleStore,
urban: UrbanStore,
urbex: UrbexStore,
}
$: store = mapping[category];
$: pictures = $store;
</script>
With ES6, I can import several exports from a file like this:
import {ThingA, ThingB, ThingC} from 'lib/things';
However, I like the organization of having one module per file. I end up with imports like this:
import ThingA from 'lib/things/ThingA';
import ThingB from 'lib/things/ThingB';
import ThingC from 'lib/things/ThingC';
I would love to be able to do this:
import {ThingA, ThingB, ThingC} from 'lib/things/*';
or something similar, with the understood convention that each file contains one default export, and each module is named the same as its file.
Is this possible?
I don't think this is possible, but afaik the resolution of module names is up to module loaders so there might a loader implementation that does support this.
Until then, you could use an intermediate "module file" at lib/things/index.js that just contains
export * from 'ThingA';
export * from 'ThingB';
export * from 'ThingC';
and it would allow you to do
import {ThingA, ThingB, ThingC} from 'lib/things';
Just a variation on the theme already provided in the answer, but how about this:
In a Thing,
export default function ThingA () {}
In things/index.js,
export {default as ThingA} from './ThingA'
export {default as ThingB} from './ThingB'
export {default as ThingC} from './ThingC'
Then to consume all the things elsewhere,
import * as things from './things'
things.ThingA()
Or to consume just some of things,
import {ThingA,ThingB} from './things'
The current answers suggest a workaround but it's bugged me why this doesn't exist, so I've created a babel plugin which does this.
Install it using:
npm i --save-dev babel-plugin-wildcard
then add it to your .babelrc with:
{
"plugins": ["wildcard"]
}
see the repo for detailed install info
This allows you to do this:
import * as Things from './lib/things';
// Do whatever you want with these :D
Things.ThingA;
Things.ThingB;
Things.ThingC;
again, the repo contains further information on what exactly it does, but doing it this way avoids creating index.js files and also happens at compile-time to avoid doing readdirs at runtime.
Also with a newer version you can do exactly like your example:
import { ThingsA, ThingsB, ThingsC } from './lib/things/*';
works the same as the above.
You now can use async import():
import fs = require('fs');
and then:
fs.readdir('./someDir', (err, files) => {
files.forEach(file => {
const module = import('./' + file).then(m =>
m.callSomeMethod();
);
// or const module = await import('file')
});
});
Great gugly muglys! This was harder than it needed to be.
Export one flat default
This is a great opportunity to use spread (... in { ...Matters, ...Contacts } below:
// imports/collections/Matters.js
export default { // default export
hello: 'World',
something: 'important',
};
// imports/collections/Contacts.js
export default { // default export
hello: 'Moon',
email: 'hello#example.com',
};
// imports/collections/index.js
import Matters from './Matters'; // import default export as var 'Matters'
import Contacts from './Contacts';
export default { // default export
...Matters, // spread Matters, overwriting previous properties
...Contacts, // spread Contacts, overwriting previosu properties
};
// imports/test.js
import collections from './collections'; // import default export as 'collections'
console.log(collections);
Then, to run babel compiled code from the command line (from project root /):
$ npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node
(trimmed)
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'Moon',
something: 'important',
email: 'hello#example.com' }
Export one tree-like default
If you'd prefer to not overwrite properties, change:
// imports/collections/index.js
import Matters from './Matters'; // import default as 'Matters'
import Contacts from './Contacts';
export default { // export default
Matters,
Contacts,
};
And the output will be:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: { hello: 'World', something: 'important' },
Contacts: { hello: 'Moon', email: 'hello#example.com' } }
Export multiple named exports w/ no default
If you're dedicated to DRY, the syntax on the imports changes as well:
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
This creates 2 named exports w/ no default export. Then change:
// imports/test.js
import { Matters, Contacts } from './collections';
console.log(Matters, Contacts);
And the output:
$ npx babel-node --presets #babel/preset-env imports/test.js
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
Import all named exports
// imports/collections/index.js
// export default as named export 'Matters'
export { default as Matters } from './Matters';
export { default as Contacts } from './Contacts';
// imports/test.js
// Import all named exports as 'collections'
import * as collections from './collections';
console.log(collections); // interesting output
console.log(collections.Matters, collections.Contacts);
Notice the destructuring import { Matters, Contacts } from './collections'; in the previous example.
$ npx babel-node --presets #babel/preset-env imports/test.js
{ Matters: [Getter], Contacts: [Getter] }
{ hello: 'World', something: 'important' } { hello: 'Moon', email: 'hello#example.com' }
In practice
Given these source files:
/myLib/thingA.js
/myLib/thingB.js
/myLib/thingC.js
Creating a /myLib/index.js to bundle up all the files defeats the purpose of import/export. It would be easier to make everything global in the first place, than to make everything global via import/export via index.js "wrapper files".
If you want a particular file, import thingA from './myLib/thingA'; in your own projects.
Creating a "wrapper file" with exports for the module only makes sense if you're packaging for npm or on a multi-year multi-team project.
Made it this far? See the docs for more details.
Also, yay for Stackoverflow finally supporting three `s as code fence markup.
Similar to the accepted answer but it allows you to scale without the need of adding a new module to the index file each time you create one:
./modules/moduleA.js
export const example = 'example';
export const anotherExample = 'anotherExample';
./modules/index.js
// require all modules on the path and with the pattern defined
const req = require.context('./', true, /.js$/);
const modules = req.keys().map(req);
// export all modules
module.exports = modules;
./example.js
import { example, anotherExample } from './modules'
If you are using webpack. This imports files automatically and exports as api namespace.
So no need to update on every file addition.
import camelCase from "lodash-es";
const requireModule = require.context("./", false, /\.js$/); //
const api = {};
requireModule.keys().forEach(fileName => {
if (fileName === "./index.js") return;
const moduleName = camelCase(fileName.replace(/(\.\/|\.js)/g, ""));
api[moduleName] = {
...requireModule(fileName).default
};
});
export default api;
For Typescript users;
import { camelCase } from "lodash-es"
const requireModule = require.context("./folderName", false, /\.ts$/)
interface LooseObject {
[key: string]: any
}
const api: LooseObject = {}
requireModule.keys().forEach(fileName => {
if (fileName === "./index.ts") return
const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ""))
api[moduleName] = {
...requireModule(fileName).default,
}
})
export default api
I've used them a few times (in particular for building massive objects splitting the data over many files (e.g. AST nodes)), in order to build them I made a tiny script (which I've just added to npm so everyone else can use it).
Usage (currently you'll need to use babel to use the export file):
$ npm install -g folder-module
$ folder-module my-cool-module/
Generates a file containing:
export {default as foo} from "./module/foo.js"
export {default as default} from "./module/default.js"
export {default as bar} from "./module/bar.js"
...etc
Then you can just consume the file:
import * as myCoolModule from "my-cool-module.js"
myCoolModule.foo()
Just an other approach to #Bergi's answer
// lib/things/index.js
import ThingA from './ThingA';
import ThingB from './ThingB';
import ThingC from './ThingC';
export default {
ThingA,
ThingB,
ThingC
}
Uses
import {ThingA, ThingB, ThingC} from './lib/things';
Nodejs ? Do like this:
Create a folder with index.js, in index file, add this:
var GET = require('./GET');
var IS = require('./IS');
var PARSE = require('./PARSE');
module.exports = { ...GET, ...IS, ...PARSE};
And, in file GET.js, or IS.js export as normal:
module.exports = { /* something as you like */}
ANd now, you need only including index.js like:
const Helper = require('./YourFolder');
Helper will include all of function in YourFolder.
Good day!
This is not exactly what you asked for but, with this method I can Iterate throught componentsList in my other files and use function such as componentsList.map(...) which I find pretty usefull !
import StepOne from './StepOne';
import StepTwo from './StepTwo';
import StepThree from './StepThree';
import StepFour from './StepFour';
import StepFive from './StepFive';
import StepSix from './StepSix';
import StepSeven from './StepSeven';
import StepEight from './StepEight';
const componentsList= () => [
{ component: StepOne(), key: 'step1' },
{ component: StepTwo(), key: 'step2' },
{ component: StepThree(), key: 'step3' },
{ component: StepFour(), key: 'step4' },
{ component: StepFive(), key: 'step5' },
{ component: StepSix(), key: 'step6' },
{ component: StepSeven(), key: 'step7' },
{ component: StepEight(), key: 'step8' }
];
export default componentsList;
You can use require as well:
const moduleHolder = []
function loadModules(path) {
let stat = fs.lstatSync(path)
if (stat.isDirectory()) {
// we have a directory: do a tree walk
const files = fs.readdirSync(path)
let f,
l = files.length
for (var i = 0; i < l; i++) {
f = pathModule.join(path, files[i])
loadModules(f)
}
} else {
// we have a file: load it
var controller = require(path)
moduleHolder.push(controller)
}
}
Then use your moduleHolder with dynamically loaded controllers:
loadModules(DIR)
for (const controller of moduleHolder) {
controller(app, db)
}
I was able to take from user atilkan's approach and modify it a bit:
For Typescript users;
require.context('#/folder/with/modules', false, /\.ts$/).keys().forEach((fileName => {
import('#/folder/with/modules' + fileName).then((mod) => {
(window as any)[fileName] = mod[fileName];
const module = new (window as any)[fileName]();
// use module
});
}));
if you don't export default in A, B, C but just export {} then it's possible to do so
// things/A.js
export function A() {}
// things/B.js
export function B() {}
// things/C.js
export function C() {}
// foo.js
import * as Foo from ./thing
Foo.A()
Foo.B()
Foo.C()
In a Vue project that's underway, the files which are responsible for communicating with the API have been grouped into a "services" section. While the code shown below works fine as written, it seems like simplifying it would be beneficial due to these factors:
there will be several more API specific files needed to support the project
the code in the 2 example API specific files shown below is essentially the same except for the value in the resource const
src/services/service.js
import axios from 'axios';
export default axios.create({
baseURL: 'advancedplanningextension/api/'
})
API specific files -
src/services/official-scenarios-service.js
import service from './service';
const resource = 'scenariolog';
export default {
get() {
return service.get(`${resource}`);
}
}
src/services/parameters-service.js
import service from './service';
const resource = 'parameter';
export default {
get() {
return service.get(`${resource}`);
}
}
file to choose the right API specific file -
src/services/service-factory.js
import OfficialScenariosService from './official-scenarios-service';
import ParametersService from './parameters-service';
const services = {
officialScenarios: OfficialScenariosService,
parameters: ParametersService
// add more here
}
export const ServiceFactory = {
get: name => services[name]
}
plugin file -
src/plugins/service.js
import { ServiceFactory } from '../services/service-factory';
export default {
install: function(Vue) {
Object.defineProperty(Vue.prototype, '$service', { value: ServiceFactory });
}
}
pertinent code in src/main.js that shows wiring of plugin file -
import ServicePlugin from './plugins/service';
Vue.use(ServicePlugin);
Example usage in src/views/official-scenarios.vue -
<template>
{{ officialScenarios }}
</template>
<script>
export default {
data() {
return {
officialScenarios: []
}
},
methods: {
async getOfficialScenarios() {
const { data } = await this.$service.get('officialScenarios').get();
this.officialScenarios = data;
}
},
mounted: function () {
this.getOfficialScenarios();
}
}
</script>
I tried creating a src/services/generic-service.js file (to replace the 2 API specific files), with the intent of calling that from src/services/service-factory.js, but quickly realized I didn't know how to populate the resource when it was called in that manner.
src/services/generic-service.js -
import service from './service';
let resource = ''; // don't know how to populate this from caller service-factory.js to access the correct API
export default {
get() {
return service.get(`${resource}`);
}
}
Is there a way to set the resource variable when service-factory.js calls the generic-service.js file? Or perhaps there is a way to incorporate the logic from generic-service.js directly into service-factory.js...? Or maybe there is a simpler approach than these options...?
OUTCOME
Many thanks to #Estus Flask for the answer and follow up information. For now, I decided to put all the services logic into src/services/index.js. If the project grows beyond needing more than createService I'll deal with refactoring at that point. Below is the code that seems to be working -
src/services/index.js -
import axios from 'axios';
const axiosInstance = axios.create({
baseURL: 'advancedplanningextension/api/'
});
const createService = resource => ({
get() {
return axiosInstance.get(`${resource}`);
}
// add more here
});
const resources = {
officialScenarios: 'scenariolog',
parameters: 'parameter'
// add more here
}
export const service = {
get: name => createService(resources[name])
}
The values in resources are the specific API endpoints. So when the code calls the service for officialScenarios for example, the URL for that API endpoint will be 'advancedplanningextension/api/scenariolog'.
src/plugins/service.js -
import { service } from '../services/index';
export default {
install: function(Vue) {
Object.defineProperty(Vue.prototype, '$service', { value: service });
}
}
Example usage in src/views/official-scenarios.vue remains the same as shown in the original question.
This can be solved with factory function:
base-service.js
import axios from 'axios';
export const axiosInstance = axios.create({
baseURL: 'advancedplanningextension/api/'
});
export const createService = resource => ({
get() {
return axiosInstance.get(`${resource}`);
},
// etc.
});
foo-service.js
import { createService } from './base-service';
export default createService('foo');
service-factory name is misleading because it isn't really a factory, just a wrapper module. The same thing can be rewritten more efficiently as barrel module (which is commonly index module):
services/index.js
export { default as foo } from './foo-service';
export { default as bar } from './foo-service';
Then it gets all benefits of ES modules such as tree-shaking and can be used as:
import * as services from './services';
services.foo.get(...);
i have a file something.js which has a function:
someFunction: function(arg1, arg2){
//code blocks
}
In my app.js file i want to call this function in the app class. I have imported the something.js file like this import { someFunction } from './something.js';. Now i am trying to use it in a function in the app class
var res = someFunction("abc", 2);
console.log(res);`
i am getting a error Uncaught TypeError: (0 , _something.someFunction) is not a function
Some help would be appreciated.
You need to write it like this:
something.js file -
module.exports = {
A: funtion(){
},
B: funtion(){
}
}
Then import it like this:
import {A} from 'something';
Or use it like this:
something.js file -
export A(){
}
export B(){
}
Then import it like this:
import {A} from 'something';
Read this article: https://danmartensen.svbtle.com/build-better-apps-with-es6-modules
In order to import something, you need to export it from the other module.
For example, you could export class YourComponent extends React.Component in something.js.
Then in the other file you can import { YourComponent } from './something'
You could, for example, in something.js do something like
const MyClass = {
methodName() { return true; }
}
export { MyClass as default } // no semi-colon
Then in the other file you could
import WhateverIWant from 'something';
WhateverIWant.methodName(); // will return true
Edit:
An in-depth explanation with lots of examples is available here.
You could either do: in your something.js file: module.exports = function(){}..
and in your app.js file:
const functionName = require('./path_to_your_file');
Or export somethingFunction = {} and in app.js:
import { somethingFunction } from './path_to_your_file'
Or last: export default somethingFunction = {} and in app.js:
import whateverNameYouChoose from './path_to_your_file'
Let me know if that did the trick! :)
In your something.js file, you can add export someFunction near the bottom of the file. This will then allow you to import that function using the import { someFunction } from './something.js'; you have earlier.
I have the following class definition:
class EmberReflux{
static createActions(actions) {
console.log(actions);
}
}
export { EmberReflux };
When I import it from a different file:
import EmberReflux from '../utils/ember-reflux';
let TodoActions = EmberReflux.createActions(
[
"addItem",
"undo",
"redo"
]);
export { TodoActions };
The transpiled looks like this
define('ember-reflux/utils/todo-actions', ['exports', 'ember-reflux/utils/ember-reflux'], function (exports, EmberReflux) {
'use strict';
var TodoActions = EmberReflux['default'].createActions(["addItem", "undo", "redo"]);
exports.TodoActions = TodoActions;
});
I'm not sure what the default is in EmberReflux['default']
I want to call the static class method like this:
EmberReflux.createActions
But instead I have to call it like this:
EmberReflux.EmberReflux.createActions
You have two options:
Export EmberReflux like you are doing:
export { EmberReflux };
and then import it like:
import { EmberReflux } from '../utils/ember-reflux';
Use default when exporting:
export default EmberReflux;
and import it (like you are doing):
import EmberReflux from '../utils/ember-reflux';
In both cases you can then use your EmberReflux like:
EmberReflux.createActions();
I don't have enough reputation to comment, the alexpods's answer is perfect, but for matters of understanding our friend Ced asked:
Why do we need the default in the 2nd example ? In other words why can't we have export EmberReflux directly ?
When you wrote like this:
export { EmberReflux };
It's the same writing like this:
export { EmberReflux: EmberReflux };
That's why you need to run EmberReflux.EmberReflux, the solution is very simple:
export default EmberReflux;
class EmberReflux {
//...
}
module.exports = EmberReflux