Let's say I need a promise module, and I am using it in multiple files, I include all those files in app.js. Do I have to use require the promise module in each of them? Is there a way to pass it to the imported module?
Yes, you should put a var Promise = require('bluebird') statement at the top of every file that uses it. This is how node/commonjs express dependencies. Sometimes people react to this initially by wanting to go back to global variables and just require something in one file and have it be implicitly/globally available in every other file in their application, but as an industry we have had years and years on both approaches and explicit dependency stating via require makes dependency management more, well manageable, overall. This is especially true in the case of automated tooling (browserify, webpack, etc).
Related
I've written PWA application, application isn't big, but now my app.js has 800 lines of the code. It has many methods. How to move these methods to another files divided thematically?
require doesn't work
You have a few options depending on what browsers you support.
You may be able to use native support for modules. You can find more information about this in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules This would be one of the simpler solutions as it does not require any additional tooling but at this time the support outside chrome is not very good.
A second alternative is to break up your code into multiple JS files and just load them all separately. This can have performance implications but if your files are small and few it wont cause too many problems. Just ensure that the code produced in these files put themselves onto a name object to avoid conflicts.
Ex file
(function() {
window.mycode = {};
window.mycode.func = function() {...};
})();
A third option is to use an existing module loader in the browser such as https://requirejs.org/
The fourth option, which is probably the most common, is to integrate a build step into your code that uses npm and a module loader such as webpack or browserify. This also lets you integrate babel which is really common among large javascript projects. The downside is it adds a step to your deployment that needs to be run and you need to learn how to use tools like webpack(which is surprisingly complicated). However, if you do javascript dev you will need to be familiar with them eventually.
I have app.js here:
let x = 5;
const print = require('./print')
print()
I have print.js here
module.exports = function(){
console.log(x)
}
Is there a good way I can use the variables in app.js in the print.js function? I'm working with much more variables in my actual application so I would like to avoid using parameters.
You can't or shouldn't. That's not how the modular architecture in node.js works. Unlikely the messy world of the browser where many bodies of code just declare a zillion things in the global scope that everything can then use, node.js is modular. Each file is typically its own module. It must export things that it wishes to share and other modules must import it's exports in order to use them.
If you want to share data with another module, you call some function and pass it that data.
While there are globals in node.js (you can assign things like global.x = 5 and then reference those anywhere), using globals are strongly, strongly discouraged for anything except built-in node.js functionality defined by the platform (not defined by an app).
There are dozens of reasons why globals are problematic and it gets worse the larger a project is, the more people there are working on it or the more 3rd party code libraries you use. If you really want to know more about that, you can just search "why are globals bad in Javascript" and find all sorts of discussion on the topic.
The modular architecture of node.js is one of the reasons that we have NPM and tens of thousands of easily reusable modules of code that work in node.js. These pieces of code all use the same modular architecture making them able to uniformly be used in any app with far less risk of symbol conflicts or modules conflicting with existing code. And, the modular architecture clearly defines dependencies on other pieces of code so a module can be self-contained and load any of the modules it depends on, even different versions of a module than other code in the project is using. None of that works when sharing code via globals.
I will repeat. In node.js, if you want to share a function or data between modules, you export that in one module and import it in another module.
Assign those variables to the global object.
global.x = 5;
const print = require('./print')
print()
module.exports = function(){
console.log(global.x)
}
Please tell me which option is better ?
Option 1: All these methods will be in Track module
getTrendingTracks
getMyFavoriteTracks
likeTrack
unlikeTrack
getMyPlayedTracks
playTrack
getArtistTracks
Option 2: These methods will be in separate modules
Track module
getTrendingTracks
Like module
getMyFavoriteTracks
likeTrack
unlikeTrack
ListeningHistory module
getMyPlayedTracks
playTrack
Artist module
getArtistTracks
It depends on the size and the future development of the application.
If the project is small and you don't expect to have a lot of new functionality option 1 is a good choice. It will keep all things close to one another and you will be able to find and modify them easily.
For projects with a lot of functionality and longer lifespans option 2 is better. This way you will be able to create smaller and more cohesive modules. These modules will depend on other modules, so you can create a module dependency map. This way you can manage the dependencies in your application better so you don't end up with spaghetti code.
When you want to add new functionality you will have to do one of several things:
Add a new module. This is the coolest thing in options 2. You just add a completely new thing to get new functionality.
Extend an already existing module. Having smaller modules makes this a lot easier.
Extend a small number of modules. Having smaller cohesive modules makes this a lot easier too
I highly recommend taking a look at Unreal Engine. It has a very good modular architecture. It has a huge codebase, so in order for it to be manageable, they split the Engine into modules. You can check it here
I really like the way NodeJS (and it's browser-side counterparts) handle modules:
var $ = require('jquery');
var config = require('./config.json');
module.exports = function(){};
module.exports = {...}
I am actually rather disappointed by the ES2015 'import' spec which is very similar to the majority of languages.
Out of curiosity, I decided to look for other languages which implement or even support a similar export/import style, but to no avail.
Perhaps I'm missing something, or more likely, my Google Foo isn't up to scratch, but it would be really interesting to see which other languages work in a similar way.
Has anyone come across similar systems?
Or maybe someone can even provide reasons that it isn't used all that often.
It is nearly impossible to properly compare these features. One can only compare their implementation in specific languages. I collected my experience mostly with the language Java and nodejs.
I observed these differences:
You can use require for more than just making other modules available to your module. For example, you can use it to parse a JSON file.
You can use require everywhere in your code, while import is only available at the top of a file.
require actually executes the required module (if it was not yet executed), while import has a more declarative nature. This might not be true for all languages, but it is a tendency.
require can load private dependencies from sub directories, while import often uses one global namespace for all the code. Again, this is also not true in general, but merely a tendency.
Responsibilities
As you can see, the require method has multiple responsibilities: declaring module dependencies and reading data. This is better separated with the import approach, since import is supposed to only handle module dependencies. I guess, what you like about being able to use the require method for reading JSON is, that it provides a really easy interface to the programmer. I agree that it is nice to have this kind of easy JSON reading interface, however there is no need to mix it with the module dependency mechanism. There can just be another method, for example readJson(). This would separate the concerns, so the require method would only be needed for declaring module dependencies.
Location in the Code
Now, that we only use require for module dependencies, it is a bad practice to use it anywhere else than at the top of your module. It just makes it hard to see the module dependencies when you use it everywhere in your code. This is why you can use the import statement only on top of your code.
I don't see the point where import creates a global variable. It merely creates a consistent identifier for each dependency, which is limited to the current file. As I said above, I recommend doing the same with the require method by using it only at the top of the file. It really helps to increase the readability of the code.
How it works
Executing code when loading a module can also be a problem, especially in big programs. You might run into a loop where one module transitively requires itself. This can be really hard to resolve. To my knowledge, nodejs handles this situation like so: When A requires B and B requires A and you start by requiring A, then:
the module system remembers that it currently loads A
it executes the code in A
it remembers that is currently loads B
it executes the code in B
it tries to load A, but A is already loading
A is not yet finished loading
it returns the half loaded A to B
B does not expect A to be half loaded
This might be a problem. Now, one can argue that cyclic dependencies should really be avoided and I agree with this. However, cyclic dependencies should only be avoided between separate components of a program. Classes in a component often have cyclic dependencies. Now, the module system can be used for both abstraction layers: Classes and Components. This might be an issue.
Next, the require approach often leads to singleton modules, which cannot be used multiple times in the same program, because they store global state. However, this is not really the fault of the system but the programmers fault how uses the system in the wrong way. Still, my observation is that the require approach misleads especially new programmers to do this.
Dependency Management
The dependency management that underlays the different approaches is indeed an interesting point. For example Java still misses a proper module system in the current version. Again, it is announced for the next version, but who knows whether this will ever become true. Currently, you can only get modules using OSGi, which is far from easy to use.
The dependency management underlaying nodejs is very powerful. However, it is also not perfect. For example non-private dependencies, which are dependencies that are exposed via the modules API, are always a problem. However, this is a common problem for dependency management so it is not limited to nodejs.
Conclusion
I guess both are not that bad, since each is used successfully. However, in my opinion, import has some objective advantages over require, like the separation of responsibilities. It follows that import can be restricted to the top of the code, which means there is only one place to search for module dependencies. Also, import might be a better fit for compiled languages, since these do not need to execute code to load code.
I'm new to Node.js, but quite like the module system and require().
That being said, coming from a C background, it makes me uneasy seeing the same module being require()'d everywhere. All in all, it leads me to some design choices that deviate from how things are done in C. For example:
Should I require() mongoose in every file that defines a mongoose model? Or inject a mongoose instance into each file that defines a model.
Should I require() my mongoose models in every module that needs them? Or have a model provider that is passed around and used to provide these models.
Ect. For someone who uses dependency injection a lot - my gut C feeling is telling me to require() a module only once, and pass it around as needed. However, after looking at some open-source stuff, this doesn't seem to be Node way of things. require() does make things super easy..
Does it hurt to overuse this mechanism?
require() caches modules when you use it. When you see the same file or module required everywhere it's only being loaded once, and the stored module.exports is being passed around instead. This means that you can use require everywhere and not worry about performance and memory issues.
As cptroot states requiring a module everywhere you need it instead of passing it around as an argument is safe to do and is also much easier. However, you should view any require call as a hardcoded dependency which you can't change easily. E.g. if you want to mock a module for testing these hardcoded dependencies will hurt.
So passing a module instance around as an argument instead of just requiring it again and again reduces the amount of hardcoded dependencies because you inject this dependency now. E.g. in your tests you will benefit from easily injecting a mock instead.
If you go down this road you will want to use a dependency injection container that helps you injecting all your dependencies and get rid of all hardcoded require calls. To choose a dependency injection container appropriate for your project you should read this excellent article. Also check out Fire Up! which I implemented.