It allows switching node versions easily.
# Download and install
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
NOTE: Restart your terminal for your changes to take effect.
# Check if installed
nvm -v
# List versions
nvm ls
# Install latest nodejs
nvm install node
# Install specific version
nvm install 17.9.1
# Use latest version
nvm use node
# Use specific version
nvm use 17.9.1
# Set default for reboots
nvm alias default 17.9.1
NOTE: If you get this error...
/usr/bin/env: 'node': No such file or directory
Fix it with...
sudo ln -s "$(which node)" /usr/local/bin/node
# manual location
sudo ln -s /home/user/.nvm/versions/node/v17.9.1/bin/node /usr/bin/node
WARNING: If you install node with apt-get, you'll end up with v10.19.0, which is the latest version in the ubuntu app store, but it's not the latest released version of NodeJS.
# remove old version
sudo apt-get purge nodejs
sudo apt-get autoremove
sudo rm -rf /usr/local/bin/node
sudo rm -rf /usr/local/lib/node_modules/npm/
# install new one
sudo apt-get update
sudo apt-get install nodejs
# Check install
node -v
npm -v
CommonJS | ES6 |
---|---|
require | import |
modules.exports | export |
You can't selectively load only the pieces you need with require but with imports, you can selectively load only the pieces you need. That can save memory.
Loading is synchronous (step by step) for require on the other hand import can be asynchronous(without waiting for previous import) so it can perform a little better than require.
- CommonJS (CJS) format. Used in Node.js and uses
require
andmodule.exports
to define dependencies and modules. The npm ecosystem is built upon this format.exports = module.exports
// lib.js
// Export the function
function sayHello() {
console.log("Hello");
}
// Do not export the function
function somePrivateFunction() {
// ...
}
module.exports.sayHello = sayHello;
let sayHello = require("./lib").sayHello;
sayHello();
// => Hello
- ES Module (ESM) format. As of ES6 (ES2015), JavaScript supports a native module format. It uses an
export
keyword to export a module’s public API and animport
keyword to import it.
// lib.js
// Export the function
export function sayHello() {
console.log("Hello");
}
// Do not export the function
function somePrivateFunction() {
// ...
}
import { sayHello } from "./lib";
// import * as lib from './lib';
sayHello();
// => Hello
CommonJS, AMD, UMD, ES Modules.
Instead of writing all the code in one giant file, we can split the code into multiple files called modules
. Only things that are highly related should go in a module.
This increases maintainability, code reuse and abstraction (blackbox).
CommonJS (old) - Synchronous
// foo.js module
function foo() {
return "bar";
}
module.exports.foo = foo;
// index.js use
const { foo } = require("foo");
ES6 - Must use Babel, can be asynchronous
// foo.js module
export function foo() {
return "bar";
}
// index.js use
import { foo } from "foo";
Every file in Node is considered a module. Everything declared inside is scoped to the file i.e. they are private.
Node does not give access to the global scope. In order to use the content of a module, we need to export it i.e. make it public.
var message = "hello";
console.log(global.message); // undefined
A proper format, unlike the CommonJS convention.
// add.js
export function add(a, b) {
return a + b;
}
// index.js
import { add } from "./add";
Modules are exported with export
and imported with import
. We can export one or more objects from a module.
There are default
and named
exports. We use a default export if there is a single object we want to export.
module
import { Person } from "./person";
// Named export
export function promote() {}
// Default export
export default class Teacher extends Person {
constructor(name, degree) {
super(name);
this.degree = degree;
}
teach() {
console.log("teach");
}
}
import
import Teacher, { promote } from "./teacher";
// Default -> import ... from "";
// Named -> import { ... } from "";
const teacher = new Teacher("John", "MSc");
teacher.teach();
Must include the .js
file extension during import.
circle.js
// Implementation detail, not exported
const _radius = new WeakMap(); // private property
// Public interface i.e. exported part
export class Circle {
constructor(radius) {
_radius.set(this, radius);
}
draw() {
console.log("Circle with radius" + _radius.get(this));
}
}
index.js
import { Circle } from "./circle.js"; // Must include the .js file extension
const c = new Circle(10);
c.draw(); // Circle with radius 10
index.html
We need to add the module type in order to avoid the Uncaught SyntaxError: Unexpected token {
error, caused by the import
curly brace.
<script type="module" src="index.js"></script>
Conventions/syntax for defining modules. ES6 natively supports them.
- CommonJS - Loads files synchronously.
Since ES5 doesn't support modules, developers came up with different syntaxes to define them. These are only used in legacy applications.
- AMD (Browser) - Asynchronous Module Definition.
- UMD (Browser / Node)- Universal Module Definition.
Two problems:
- Browsers cannot load files synchronously. This is solved via bundling a huge file including everything, even unused things.
- JS engine cannot tell what a module exports until it runs it.
// add.js
function add(a, b) {
return a + b;
}
module.exports = add;
// index.js
const add = require("./add"); // Loads synchronously
add(2, 3); // 5
CommonJS defines the:
module.exports
for exporting modules. It represents the object that is exported from a module.module
refers to the current module (file).exports
is an object and property ofmodule
.
require("./module")
for importing modules.
When we import the foo.js
module, we directly get the Foo
class.
class Foo {}
module.exports = Foo;
We can import the exports
objects and access its properties.
class Foo {}
class Bar {}
module.exports.Foo = Foo;
module.exports.Bar = Bar;
circle.js
// Implementation detail, not exported
const _radius = new WeakMap(); // private property
// Public interface i.e. exported part
class Circle {
constructor(radius) {
_radius.set(this, radius);
}
draw() {
console.log("Circle with radius" + _radius.get(this));
}
}
module.exports = Circle;
index.js
const Circle = require("./circle");
const c = new Circle(10);
c.draw(); // Circle with radius 10