Import
Introduction
When we develop, we need to use multiple interconnected code files to organize, reuse functionalities to avoid repetition, facilitate maintenance by centralizing useful functions, which reduces the lines of code in general and consequently greatly reduces bugs.
So we centralize the code that is useful into a code file that can be imported by others who can easily reuse it.
Here we will demonstrate some solutions that Netuno presents to perform code reuse.
Polyglot Core
In any programming language supported by Netuno, we can import any code file that is in the server/core
folder of
the application.
The simplified way that Netuno offers is to use a special comment format for importing code, where the commented
line has the prefix _core:
, and then has the path of the code file from the server/core
folder of the
application.
So to import the code file:
server/core/example/file
The file must have the extension according to the programming language used.
It is possible to import the file at the beginning of any other code file, for example from services.
In the case of JavaScript, Groovy and Kotlin:
// _core: example/file
...
In the case of Python and Ruby:
# _core: example/file
...
In this special import comment it is not necessary to put the file extension, Netuno detects it automatically.
The variables, constants, functions, classes, etc., declared in the imported file are made available for use in the file that performs the import with this type of comment at the beginning.
To import multiple files, simply repeat the import comment with the path of the other files.
In the case of JavaScript, Groovy and Kotlin, to import multiple files:
// _core: example/file1
// _core: example/file2
// _core: example/file3
...
In the case of Python and Ruby, to import multiple files:
# _core: example/file1
# _core: example/file2
# _core: example/file3
...
Exec Resource
Through the _exec
resource we can import code at any time during execution.
Variables, constants, functions, classes, etc., declared in the imported code file can be used.
core
For example, to import a code file that is in the server/core
folder:
_exec.core('path/of/file')
It is not necessary to put the file extension that Netuno detects automatically.
services
Example of how to import a code file that is in the server/services
folder:
_exec.service('path/of/file')
It is not necessary to put the file extension that Netuno detects automatically.
JavaScript
Since Netuno uses GraalVM, it allows you to import files in a way that is natively compatible.
When using native import, unlike the previous examples, only what is explicitly exported will be imported, based on the CommonJS or ECMAScript Modules standard.
CJS (CommonJS)
To perform the import in the CommonJS standard we use the require
function, while the export is done with
module.exports
.
See how in the following example...
When creating a service in server/services/example.js
.
We can import a core
file as follows:
const main = require("../core/my-code/main.cjs")
main.execute()
Note that the file path indication in
require
will be relative to the service file that is being coded, this same logic is applicable to any other type of JavaScript code file.
The value of the main
constant will be what is exported by the core/my-code/main.cjs
file, for example:
const execute = () => {
// my code here...
}
module.exports = {
execute
};
It can either have the .cjs
or .js
extension, using the .cjs
extension is recommended because it better indicates
that it is a file that performs module.exports
.
MJS (ECMAScript Modules)
To perform the import in the ECMAScript Modules standard we use the import
instruction, while the export is done with
the export default
.
See how in the following example...
When creating a service in server/services/example.mjs
.
Note that the service file extension is
.mjs
.All files, both the one that imports and the one that is imported, must have the extension:
.mjs
Therefore, for correct operation, it is important that all files involved in processing have the .mjs
extension, to
provide compatibility where the import
instruction is supported.
So it is possible to import a core
file as follows:
import main from "./core/my-code/main.mjs"
main.execute()
Note that the file path indicated in
import
will be from the application'sserver
folder, and is not relative to the file being developed.It is important that the path starts with:
./
The ./
in import
is equivalent to the /server
folder within the application.
The value of main
will be what was exported by the file core/my-code/main.mjs
, for example:
const execute = () => {
// my code here...
}
export default {
execute
};
NPM - External Dependencies
External NPM dependencies can be installed inside the /server
folder inside the application, where package.json
is located.
Just install the dependency normally with the npm install
command.
For example, you can install momentjs
:
npm install moment
To import the dependency in .js
and .cjs
files, require
is used, see the example:
const moment = require('moment')
_out.json(moment().format())
And to import external dependencies in .mjs
files, import
is normally used, however only libraries that use the
.mjs
extension in the code files can be imported, this is a major limitation that we have and this makes it
difficult to use.
This happens because all files involved in processing need to have the .mjs
extension, but most dependencies do not
use this type of extension.
NodeJS Native Modules
Since GraalVM is not fully compatible with NodeJS native modules, to work around this it is possible to obtain greater compatibility with external dependencies that implement an alternative solution to these modules.
So it may be necessary to install some external dependencies as an alternative that provide compatibility as if they were native modules.
Below is a list of modules that are supported as alternatives to replace the native NodeJS modules, and their respective installation commands:
- Buffer:
npm install buffer
- Events:
npm install events
- Util:
npm install util
- Path:
npm install path-browserify
- Stream:
npm install stream-browserify
- HTTP:
npm install http-browserify
- HTTPS:
npm install https-browserify
In other words, by installing these modules above in /server
within the application, compatibility with the native
NodeJS modules is provided and these alternative modules will be used.
Conclusion
We can organize our code in different ways, but reusing code and avoiding repetition is always very important.
The more lines of code there are, the more likely there are to be bugs.
Remember to organize your code well and centralize its reuse, it facilitates maintenance, avoids bugs, and increases productivity in general.
Although there are still some limitations with the use of external dependencies, we are working to improve the ecosystem.
Meanwhile, Neptune offers a variety of low-code and polyglot features that cover most needs.