Node.js ist eine JavaScript Runtime
Verwendung für:
npm = Node package manager
ist in der node.js-Installation beinhaltet
Download von https://nodejs.org
Major Releases alle 6 Monate; Long-Term-Support Releases alle 12 Monate
Die npm Registry enthält hauptsächlich open source JavaScript Pakete
Mit über 1 Million Pakete die bei weitem größte Software Registry
Beispiele most depended upon packages
zwei wichtige Package Manager für die npm Registry:
Sowohl öffentliche Pakete als auch private Projekte werden über die Konfigurationsdatei package.json konfiguriert
Um Abhängigkeiten zu installieren können wir mit einer leeren package.json beginnen:
{}
Alternative: package.json mit Inhalten mittels npm init
(oder npm init -y
für Standardoptionen) erstellen
Beispiel zur Installation von Abhängigkeiten:
npm install lodash bootstrap
Wenn wir eine Library entwickeln, die wir in der npm Registry veröffentlichen wollen:
Abhängigkeiten, die nur für die Entwicklung, nicht für die Verwendung von Bedeutung sind werden als dev-dependencies installiert:
npm install eslint --save-dev
Auswirkungen der bisherigen npm install
Befehle:
package.json
- listet Minimalversionen der gerade installierten Paketenode_modules
- Ordner, der alle installierten Pakete enthältpackage-lock.json
- listet exakte Versionen aller Pakete in node_modules
aufDie Datei package.json
listet nun Abhängigkeiten gemeinsam mit deren Version auf.
Die Version verwendet semantic versioning: major.minor.patch
Mögliche Konfigurationen:
"bootstrap": "4.3.1"
- genau diese Version"bootstrap": "~4.3.1"
- Updates der Patch-Version sind erlaubt - z.B. auf 4.3.2
"bootstrap": "^4.3.1"
- Updates der Minor-Version sind erlaubt - z.B. auf 4.4.0
package-lock.json
listet exakte Versionen aller Abhängigkeiten (und derer Abhängigkeiten ...)
enthält die tatsächlichen Pakete
sollte nicht unter Versionskontrolle stehen - kann stattdessen aus package.json
neu generiert werden - durch ausführen von npm install
ohne Argumente
Npm kann verwendet werden, um Scripts / Befehle auszuführen, z.B.:
npm run test
- würde Unit Tests ausführennpm run build
- würde einen Build erstellennpm run start
npm run deploy
Manche npm Scripts haben Abkürzungen, insbesondere npm test
und npm start
Npm Scripts werden package.json
konfiguriert:
{
"scripts": { "start": "node run-server.js" }
}
Node Pakete können global auf einem Computer installiert werden oder direkt aus der npm Registry ausgeführt werden
direkte Ausführung (ohne Installation):
npx cowsay hello
globale Installation von cowsay
:
npm install -g cowsay
cowsay hello
hello.js:
console.log('Hello world!');
node hello.js
Mit Debugging: F5
Ohne Debugging: Ctrl + F5
festlegen, wie JavaScript-Dateien ausgeführt werden sollen:
in der Befehlspalette, suche nach Debug: Open launch.json und wähle Node.js als Umgebung
der Befehl erstellt eine neue Datei unter .vscode/launch.json
Mögliche Konfigurationseinträge (.vscode/launch.json):
{
"name": "Run current file",
"type": "node",
"request": "launch",
"program": "${file}",
"skipFiles": ["<node_internals>/**"]
}
{
"name": "Run index.js",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/index.js",
"skipFiles": ["<node_internals>/**"]
}
Node-Programme können Objekte aus sogenannten Modulen importieren
Kategorien:
moderne Möglichkeit:
import fs from 'fs';
const currentDirectoryContent = fs.readdirSync('.');
console.log(currentDirectoryContent);
ältere Syntax:
const fs = require('fs');
const currentDirectoryContent = fs.readdirSync('.');
console.log(currentDirectoryContent);
für Verwendung der moderneren Syntax: in package.json als "module" deklarieren (benötigt node ≥ 13):
{
"type": "module",
"eslintConfig": {
"sourceType": "module"
}
}
auf die moderne Syntax kann auch individuell in einzelnen Dateien gewechselt werden: verwende dazu die Datiendung .mjs (benötigt node ≥ 13)
Aufgabe: Schreibe ein node-Script, das die alte Syntax benutzt, migriere es dann zur neuen Syntax
Eine JavaScript-Datei, die Objekte exportiert, ist ein sogenanntes Modul
Beispiel für ein Modul mit moderner Syntax:
const message1 = 'hello!';
const message2 = 'have a nice day!';
export { message1, message2 };
es kann einen default Export geben
const mainMessage = 'xyz';
const message1 = 'hello!';
const message2 = 'have a nice day!';
export { message1, message2 };
export default mainMessage;
Lokale Module werden mittels relativer Dateipfade importiert
import mainMessage, { message1 } from './messages.js';
Dateiendung ist optional:
import mainMessage, { message1 } from './messages';
ältere Syntax für den Export:
const message1 = 'hello!';
const message2 = 'have a nice day!';
module.exports.message1 = message1;
module.exports.message2 = message2;
// shorthand
exports.message3 = 'Bye';
default Export:
const mainMessage = 'xyz';
module.exports = mainMessage;
etwas andere globale Objekte als im Browser
nur im Browser:
window
(globaler Namespace) - Alternativname globalThis
fetch
localStorage
, sessionStorage
nur in Node
global
(globaler Namespace) - Alternativname globalThis
process
(z.B. process.argv
)__filename
und __dirname
command line arguments are available via the global process.argv
example:
node program.js 1 2 3
will result in
["node", "/path/to/your/program.js", "1", "2", "3"];
Implement a program that would work like this:
node sum.js 1 2 3
the sum is 6
process
ist eine globale Variable
process.argv
(Kommandozeilenparameter)process.cwd()
process.exit()
Ãœbung: schreibe ein Programm, das wie folgt aufgerufen werden kann:
node sum.js 1 2 3
the sum is 6
mittels des fs-Moduls:
import fs from 'fs';
fs.writeFileSync('message.txt', 'hello world');
dies erstellt eine Textdatei mit UTF-8 als Encoding
const fileContent = fs.readFileSync('package.json', 'utf8');
Beim Lesen von Textdateien muss ein Encoding angegeben werden (in diesem Fall UTF-8)
const myFile = fs.readFileSync('./package.json');
gibt ein buffer-objekt zurück (eie Folge von Bytes)
Umwandeln in einen String:
const fileTextContent = myFile.toString('utf-8');
Lesen einer Datei kann (relativ) lange dauern. Mit dem bisherigen Code kann node währenddessen keinen Code ausführen.
fs.promises
.readFile('read-file.js', 'utf8')
.then(console.log)
.catch(() => {
console.log('error while reading file');
});
const readFileAsync = async () => {
try {
const fileContent = await fs.promises.readFile(
'read-file.js',
'utf8'
);
} catch {
console.log('error while reading file');
}
console.log(fileContent);
};
readFileAsync();
Erstelle einen HTML-"Serienbrief" für verschidene Empfänger aus einer Vorlage
liste alle Dateien eines bestimmten Typs auf (siehe Ãœbung von learnyounode)
"low-level" (einzelne TCP-Pakete):
import http from 'http';
http.get('http://www.google.com', (responseStream) => {
responseStream.setEncoding('latin1');
responseStream.on('data', console.log);
responseStream.on('error', console.error);
});
Übung: rufe die Google-Website ab und schreibe Stücke davon in eine JSON-Array
Libraries für HTTP-Aufrufe:
npm install node-fetch
import fetch from 'node-fetch';
fetch('https://google.com')
.then((res) => res.text())
.then((content) => console.log(content));
siehe https://nodejs.org/en/docs/guides/getting-started-guide/
import http from 'http';
const hostname = '127.0.0.1';
const port = 3000;
const requestHandler = (req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
};
server = http.createServer(requestHandler);
server.listen(port, hostname);
npm-Paket für Command-Line Tools: prompt
Beispiel:
beim Ausführen von node ./hello.js
wünschen wir folgende Interaktion:
prompt: first name: Marko
prompt: birth year: 1988
Hi, Marko!
In the year 2030 you'll be 42!
einfache Verwendung:
import prompt from 'prompt';
const main = async () => {
prompt.start();
const person = await prompt.get([
'first name',
'birth year',
]);
console.log(`Hi, ${person['first name']}!`);
const birthYear = Number(person['birth year']);
console.log(`In 2030 you'll be ${2030 - birthYear}!`);
};
main();
fortgeschrittene Verwendung mit Validierung:
const main = async () => {
prompt.start();
const person = await prompt.get({
properties: {
'first name': {},
'birth year': {
description: 'year when you were born',
pattern: /^\d{4}$/,
},
},
});
console.log(`Hi, ${person['first name']}!`);
const birthYear = Number(person['birth year']);
console.log(`In 2030 you'll be ${2030 - birthYear}!`);
};
npm publish --access public
Erstelle eine .gitignore
oder .npmignore
Datei, die Dateien auflistet, die nicht veröffentlicht werden sollen:
.git
node_modules
package-lock.json
npm publish --access public
Eintrag "bin" in package.json
(sollte mit Paketnamen - ohne eventuellen Benutzernamen - übereinstimmen):
{
"name": "@user/foo-package",
"bin": {
"foo-package": "./foo-bin.js"
}
}
Inhalte von foo-bin.js
:
#! /usr/bin/env node
console.log('this is the npx script of foo-package');