I'm making an API for a web application, and I'm running into a weird problem when I try to import a module. I have a folder with a bunch of models used to get data from the database, and I have a folder named "global" with various modules used all over the project.
/
/api
/models
/Users.js
/Trainings.js
/TrainingsTypes.js
/TrainingsSubtypes.js
/global
/Functions.js
Some of the models import other models to check ID, get data, etc. I made a function in Functions.js that also needs some of the models to work. So basically, the import dependencies look like:
I must admit, this is a little crappy when showed like that. But here is my problem. As long as Functions.js doesn't import Users.js, everything is fine. The API works well and there's no crash at all. But, if I import Users.js in Functions.js, I immediatly get this error:
ReferenceError: Cannot access 'Users' before initialization
at file:///C:/Users/USERNAME/Desktop/project-api/global/Functions.js:30:10
at ModuleJob.run (internal/modules/esm/module_job.js:169:25)
at async Loader.import (internal/modules/esm/loader.js:177:24)
at async Object.loadESM (internal/process/esm_loader.js:68:5)
Here is the code of Functions.js (I put a comment to indicate line 30):
import check from "checkers";
import Users from "../api/models/Users.js";
import Trainings from "../api/models/Trainings.js";
import TrainingsTypes from "../api/models/TrainingsTypes.js";
import TrainingsSubtypes from "../api/models/TrainingsSubtypes.js";
/*****************************************************
* SQL Queries
*****************************************************/
export function fieldsToUpdate(fields) {...}
const fillers = {
"user": Users, // Line 30
"trainer": Users,
"type": TrainingsTypes,
"subtype": TrainingsSubtypes
};
export async function fillIDs(db, response) {...}
Moreover, the import itself doesn't cause problems. If I remove Users from the fillers object, there's still no crash. I've seen that might be a cyclic dependencies issue but some says that Node can handle this. I must add that I really need all my models in fillIDs() so I just can't remove all the import and I didn't want to copy/paste this code in every model. There must be a solution, but I need some help.
Have you any idea how to fix this?
Thanks
EDIT 1:
Users.js import these modules:
import bcrypt from "bcryptjs";
import generatePwd from "generate-password";
import { v4 as uuidv4 } from "uuid";
import check from "checkers";
import { fieldsToUpdate, fillIDs } from "../../global/Functions.js";
import { arrayToSerialComma } from "../../global/Converters.js";
import APIResp from "../../global/APIResp.js";
import Mailer from "../../global/Mailer.js";
import Genders from "./Genders.js";
import Roles from "./Roles.js";
import Tokens from "./Tokens.js";
import { Passwords } from "../../config/config.js";
EDIT 2:
Users.js is exported in this way:
const Users = {
isValid,
add,
logIn, getAll, getById, getByEmail, hasForgotPassword, getRolesOf,
update, updatePwd, passwordForgotten,
delete: del,
Trainers: {
getById: getTrainerById,
getAll: getAllTrainers
}
};
export default Users;
I managed to partially solve my problem. I've created a file in global exporting all the files in this folder and did the same for models.
// ROOT/global/global.js
export { default as APIResp } from "./APIResp.js";
export { default as SQLFunctions } from "./SQLFunctions.js";
export { default as Mailer } from "./Mailer.js";
export { default as ModuleConsole } from "./ModuleConsole.js";
// ROOT/api/models/models.js
export { default as Users } from "./Users.js";
export { default as Genders } from "./Genders.js";
export { default as Roles } from "./Roles.js";
export { default as Tokens } from "./Tokens.js";
export { default as Trainings } from "./Trainings.js";
export { default as TrainingsTypes } from "./TrainingsTypes.js";
export { default as TrainingsSubtypes } from "./TrainingsSubtypes.js";
I also removed some functions that was needed in both the front-end and back-end and moved them to an external module. I used madge to generate a dependency graph.
As we can see, it's not perfect yet. All the models files are actually in a big circular dependency but it's much cleaner than before and there are no more crashes.
This may have an impact on performance, and I have to be careful with that.
I mark this answer as correct for now, I may change it if someone else or I found something.
Related
I am trying to understand how authoring libraries works with webpack and while doing works:
import add from 'sample-lib/add'
trying to import anything from the main does not:
import { add, subtract } from 'sample-lib'
Here is the repo for your reference:
https://github.com/rssilvaba/sample-lib
Any ideas why I can't do that? is it because it is umd? something with my package.json? Am I exporting from main in the wrong way?
Also extra question. how could I re export all files without having to manually add all of the files to the main.js?
resolved doing:
export { default as add } from './add'
export { default as subtract } from './subtract'
export * from './others'
I got this error in my browser
Error in ./src/App.js
Module not found: ./components/todo in C:\Users\James\Desktop\react\src
This is what I got in my editor
import {TodoForm, TodoList} from './components/todo'
http://imgur.com/a/8YLod
I even tried import {TodoForm, TodoList} from './components/todo/' I wonder what's wrong.
Imports work on a per module basis for most loaders/bundlers. In other words, you'll need to import the form and list by doing the following:
import { TodoForm } from './components/todo/TodoForm'
import { TodoList } from './components/todo/TodoList'
As a side note, see https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export to make sure that you're exporting the components correctly. The curly braces around your import works for a named export as opposed to a default export.
In order to just import all files from the directory you must have an index.js file that exports everything from the directory
Which in your case the index.js file would look like this
Export * from 'TodoForm'
Export * from 'TodoList'
Note if the export statement doesn't work see this answer to fix the import / export statement
Do you think, when you wrote import {TodoForm, TodoList} from './components/todo', in TodoForm should be value than you exported from file TodoForm.js, and similarly with TodoList? It's don't works.
You should do import from some file. When you wrote from './components/todo' you tried doing import from todo directory. I guess, in egghead video that import works, because, they have index.js file in todo directory. And in this file they do export for every component separately. Try to add index.js file in todo directory with the following contents:
export * from './TodoForm.js';
export * from './TodoList.js';
it's will work.
So the thing is that when you do
import {TodoForm, TodoList} from './components/todo'
What happends is that your compiler will by default search the components TodoForm and TodoList from the index.js file since you have not mentioned explicitly which files to point to
So if in index.js you add something like
export * from './components/todo/TodoForm';
export * from './components/todo/TodoList';
Your approach will work.
I would like to combine some modules into a single file that can be imported. These are local files and not part of an npm module.
Module Kitten (kitten.js)
export function Feed() {}
export function Play() {}
In my code I can access 'Feed' and 'Play':
// This works but I would like to avoid this due to my paths
import { Feed, Play } from './some/long/path/kitten.js'
// Then use it
Feed()
As I have many 'pets' I can contenate them in a master file - say pets.js
export * as Kitten from './some/long/path/kitten.js'
export * as Puppies from './some/long/path/puppies.js'
...
In my code I can then do:
import { Kitten, Puppies } from './pets'
// Then use it as
Kitten.Feed()
is it possible to have both a) the master pets file and b) call Feed() without doing Kitten.Feed()?
The following doesn't work as it's not a valid path. It's possible it would work as 'pets/Kitten' if it was an npm module - am not sure.
import { Feed, Play } from './pets/Kitten'
I was thinking something along the lines of:
import * as Pets from from './pets'
import { Feed, Play } from Pets.Kitten // or 'Pets/Kitten'
But clearly that doesn't work. I am wondering if it's at all possible.
I am using this in Node with Babel 6 and ES6 module loading. I see a lot of similar questions but they all use default exports which I am not using.
But that doesn't allow me to import selected functions.
Sure it does. The relative-path import works the same as module import. You can destructure the results just the same.
import { Play } from 'Pet/Puppy';
// is identical to
import { Play } from '../node_modules/Pet/Puppy';
If you take a look at the import syntax (s15.2.2), you can see that the from part expects a string. It doesn't care what's in the string, that's up to the module system (the browser, node, etc).
Ah.. object destructuring.. Forgot about that.
import { Kitten, Puppies } from './pets'
const {Feed, Play} = Kitten;
Thanks to https://stackoverflow.com/a/30132149/856498
I'm following ES2015. I want to translate regular javascript import statements to ES2015 import statement(s).
What I have:
I have javascript import line as below:
var db = require('../config').get('db')
What I've tried:
import { config } from '../config'
const db = config.db
NOTE
config folder has the index.js which I want to load. In the regular var ... = require('...') statement automatically loads index.js if exists. And I want the ES2015 script also automatically loads when imported.
I think what you're looking for is:
import { db } from '../config'
Assuming db is properly export-ed from config.js, that should work.
Just to clarify, there's three main kinds of imports in JS native modules:
Import the whole module:
import * as foo from 'path/to/foo';
const something = foo.something;
Import specific named exports of the module. This works if the module exports the appropriate objects using export statements:
import { something } from 'path/to/foo';
Import the default export of the module. This only works if the module has an export default statement in it:
import thedefaultexport from 'path/to/foo';
It looks like the '../config' module exports a single object with a get() method. If this is the case, import the whole module, like so:
import * as config from '../config';
And get the database like so:
const db = config.get('db');
If possible, you might want to refactor your '../config' module so that it exports db directly.
export {db};
And then you can use the syntax #AsadSaeeduddin suggested:
import {dp} from '../config';
Problems I have with ember are related to ember-restless module I would like to use instead of ember-data(I have completely removed data module from my project).
I am still learning ember so I am not sure if this has something with latest version, or with programming style, but I saw that in Ember 2.0 we would write
export default RL.Client.create({
adapter: App.RESTAdapter
});
instead of
App.Client = RL.Client.create({
adapter: App.RESTAdapter
});
but it seems that my client is then not recognised(if I write it in first way), as get request are made to localhost instead of url I specified in RESTAdapter class.
Second problem I have is that
import RL from 'ember-restless';
does not work for me, it says that module 'ember-restless' could not be found.
Any help would be appreciated, as I have been struggling with this for some time.
UPDATE
I changed importing syntax to following, and here's the situation:
import { Client } from 'ember-restless';
If a put this import in my model class, I am getting following error in js console:
Error: Could not find module 'ember-restless' imported from 'ember-test2/models/pol'
However, if I remove import from model class, leave adequate imports in RESTAdapter and Client definitions, there are no errors, but services are called on localhost:4200 instead on localhost:8080.
I will provide my definitions from js files here:
models/pol.js
import { RL } from 'ember-restless'; // imports entire library
var Pol = RL.Model.extend({
idPol: RL.attr('integer'),
naziv: RL.attr('string')
});
Pol.reopenClass({
resourceName: 'pol/e'
});
export default Pol;
adapters/application.js
import { RL } from 'ember-restless';
export default RL.RESTAdapter.create({
host: 'http://localhost:8080',
namespace: 'zareps'
});
adapters/client.js
import {RESTAdapter} from '../adapters/application';
import {Client} from 'ember-restless';
export default Client.create({
adapter: RESTAdapter
});
routes/list-pol.js
import Ember from 'ember';
import Pol from '../models/pol';
export default Ember.Route.extend({
model() {
return Pol.find();
}
});