2022-04-23 13:26:53 +01:00
|
|
|
|
---
|
|
|
|
|
tags:
|
|
|
|
|
- node-js
|
|
|
|
|
---
|
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
# Modules
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
> Modules are partitioned files where we define our variables and functions.
|
|
|
|
|
> Values defined in modules are scoped to that specific module, constituting a
|
|
|
|
|
> unique name space. This avoids name clashes in large programs.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
- Every file in a Node application is considered a module.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
- The variables and methods in a module are equivalent to `private` properties
|
|
|
|
|
and methods in object-oriented programming.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
- If you wish to use a function or variable defined in a module outside of its
|
|
|
|
|
modular container you need to explicitly export it and make it public.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
## Structure of a module
|
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
Node keeps an internal record of the properties of a module. To see this we can
|
|
|
|
|
log the property `module` to the console.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
// index.js
|
2022-09-06 15:44:40 +01:00
|
|
|
|
console.log(module);
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```
|
2022-09-06 15:44:40 +01:00
|
|
|
|
|
2022-04-23 13:26:53 +01:00
|
|
|
|
This gives us:
|
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```plaintext
|
2022-09-06 15:44:40 +01:00
|
|
|
|
Module {
|
|
|
|
|
id: '.',
|
|
|
|
|
path: '/home/thomas/repos/node-learning',
|
|
|
|
|
exports: {},
|
|
|
|
|
filename: '/home/thomas/repos/node-learning/index.js',
|
|
|
|
|
loaded: false,
|
|
|
|
|
children: [],
|
|
|
|
|
paths: [
|
|
|
|
|
'/home/thomas/repos/node-learning/node_modules',
|
|
|
|
|
'/home/thomas/repos/node_modules',
|
|
|
|
|
'/home/thomas/node_modules',
|
|
|
|
|
'/home/node_modules',
|
|
|
|
|
'/node_modules'
|
|
|
|
|
]
|
2022-04-23 13:26:53 +01:00
|
|
|
|
}
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```
|
2022-09-06 15:44:40 +01:00
|
|
|
|
|
2022-04-23 13:26:53 +01:00
|
|
|
|
## Exports
|
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
- Whenever we export a property or method from a module we are directly
|
|
|
|
|
targeting the `exports` property of the module object.
|
|
|
|
|
- Once we add exports to a file they will be displayed under that property of
|
|
|
|
|
the module object.
|
|
|
|
|
- We can export the entire module itself as the export (typically used when the
|
|
|
|
|
module is a single function or class) or individual properties.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
### Exporting a whole module
|
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
_The example below is a module file that consists in a single function_
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
module.exports = function (...params) {
|
2022-09-06 15:44:40 +01:00
|
|
|
|
// function body
|
|
|
|
|
};
|
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
Note the module is unnamed. We would name it when we import:
|
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2023-02-10 18:22:04 +00:00
|
|
|
|
const myFunction = require("./filenme");
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
### Exporting sub-components from a module
|
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
In the example below we export a variable and function from the same module.
|
|
|
|
|
Note only those values prefixed with `exports` are exported.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
exports.myFunc = (...params) => {
|
2022-09-06 15:44:40 +01:00
|
|
|
|
// function bod[]()y
|
|
|
|
|
};
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
exports.aVar = 321.3;
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
var nonExportedVar = true;
|
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
This time the exports are already name so we would import with the following:
|
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2023-02-10 18:22:04 +00:00
|
|
|
|
const { myFunc, aVar } = require("./filename");
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
We can also do the exporting at the bottom when the individual components are
|
|
|
|
|
named:
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
const myNamedFunc = (val) => {
|
|
|
|
|
return val + 1;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function anotherNamedFunc(val) {
|
|
|
|
|
return val * 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This time we export at the bottom
|
|
|
|
|
exports.myNamedFunc = myNamedFunc;
|
|
|
|
|
exports.differentName = anotherNamedFunc; // We can use different names
|
|
|
|
|
|
|
|
|
|
// Or we could export them together
|
2023-02-10 18:22:04 +00:00
|
|
|
|
module.exports = { myNamedFunc, anotherNamedFunc };
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
The import is the same:
|
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```js
|
2023-02-10 18:22:04 +00:00
|
|
|
|
const { myNamedFunc, anotherNamedFunc } = require("./modules/multiExports");
|
2022-09-06 15:44:40 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
|
|
|
|
## Structuring modules
|
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
The techniques above are useful to know but generally you would want to enforce
|
|
|
|
|
a stricter structure than a mix of exported and private values in the one file.
|
|
|
|
|
The best way to do this is with a single default export.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
Here the thing exported could be a composite function or an object that
|
|
|
|
|
basically acts like a class with methods and properties.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
_Export a composite single function_
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
module.exports = () => {
|
|
|
|
|
foo() {...}
|
|
|
|
|
bar() {...}
|
2022-04-23 13:26:53 +01:00
|
|
|
|
}
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
_Export an object_
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-09-06 15:44:40 +01:00
|
|
|
|
module.exports = {
|
2022-04-23 13:26:53 +01:00
|
|
|
|
foo : () => {...},
|
2022-09-06 15:44:40 +01:00
|
|
|
|
bar: () => {...}
|
2022-04-23 13:26:53 +01:00
|
|
|
|
}
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
**Both of these structures would be referred to in the same way when importing
|
|
|
|
|
and using them.**
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
Or you could export an actual class as the default. This is practically the same
|
|
|
|
|
as the two above other than that you would have to use `new` to initiate an
|
|
|
|
|
instance of the class.
|
2022-04-23 13:26:53 +01:00
|
|
|
|
|
2022-08-01 19:30:05 +01:00
|
|
|
|
```js
|
2022-04-23 13:26:53 +01:00
|
|
|
|
export default class {
|
2022-09-06 15:44:40 +01:00
|
|
|
|
foo() {}
|
|
|
|
|
bar() {}
|
|
|
|
|
}
|
2022-08-02 19:00:04 +01:00
|
|
|
|
```
|
2022-09-06 15:44:40 +01:00
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
|
Every method and property within the export will be public by default, whether
|
|
|
|
|
it is an object, class or function. If you wanted to keep certain
|
|
|
|
|
methods/properties private, the best approach is to define them as variables and
|
|
|
|
|
functions within the module file but outside of the `export` block.
|