NodeJS. Part2.

Node JS. Практический курс https://www.udemy.com/course/nodejs-full-guide/ Руководство по Node.js https://metanit.com/web/nodejs/

Урок 1. Что такое NPM

Команды
node -v  - узнать версию node
node – активируется node, консоль работает точно так же, как консоль браузера, в ней можно писать код
.exit или Ctrl+C - выйти из данного режима, в консоли можно вводить команды
  Преимущества
У node только одна платформа, поддерживающая самые новые возможности языка. Не нужно заботится о поддержке устаревших браузеров, не нужно транспилировать код под старые версии

Начало работы В терминале vsc выполняем команду

npm init

Инициализируется новое приложение. Описываем его (название, версия и т.д) можно просто нажимать Enter. Создаётся файл package.json, в котором описывается наше приложение

Что такое npm?
Это инструмент, который является менеджером модулей. С помощью npm модули можно добавлять и удалять.

Добавление модуля

npm install nodemon

,где nodemon - название модуля

Удаление модуля

npm uninstall nodemon

Урок 2. Глобальные объекты и модули

Первая программа на node.js
В редакторе создаём файл index.js
Пишем там код

console.log('Hello');

и запускаем его в консоли Visual Studio Code

Для этого пишем

node index

В консоли появляется строка Hello

Запускаем команду

console.log('Hello', __dirname);

В консоли - путь к папке

Hello C:\Users\Admin\Desktop\nodejs-basic

Запускаем команду

console.log('Hello', __filename);

В консоли - путь к файлу

Hello C:\Users\Admin\Desktop\nodejs-basic\index.js

Модули

Модули в node.js были с самого начала, когда в обычном js о них ещё даже не думали.

Создаём файл user.js, в нём пишем код

const user = {
  name: 'Ann',  
  age: 23  
}

Как нам экспортировать созданный объект?
Пишем

module.exports = user;

Импортируем.
Для этого в index.js пишем

const user = require('./user')

Команда console.log(user) выводит в консоль объект, который был создан в файле user.js

Лайфхак
Если команда node index в терминале уже была введена, чтобы запустить её повторно, достаточно нажать клавишу "стрелка вверх" на клавиатуре 

Экспорт в файле user.js может выглядеть иначе

module.exports = {
  user: user,  
  sayHello() {  
  console.log('Hello')  
  }  
}

Теперь в файле index.js можем получить как объект user, так и функцию sayHello()

const userObj = require('./user');
userObj.sayHello()  // Hello

Ещё одна возможность - экспортировать только некоторые объекты. Если в файле user.js есть два объекта, а экспортируется только первый, то второй будет доступен только в этом файле и больше нигде. Благодаря этому в каждом модуле можно вести независимую разработку

Переменные require, moduleexports, __dirname, __filename называются глобальными объектами.

Урок 3. Модули PATH

Node.js имеет набор стандартных модулей, которые мы получаем устанавливая node на компьютер.

Перечень стандартных модулей есть на сайте node, чтобы их увидеть нужно выбрать номер текущей версии node слева https://nodejs.org/en/docs/

Одним из стандартных модулей является path
Чтобы обратиться к такому модулю, достаточно написать команду

const path = require('path');
console.log(path)

path предназначен для того, чтобы работать с путями в node.js. Можно получить имя файла, расширение файла, имя папки, указать путь к файлу 

Информация о методах path можно найти на официальном сайте node.js https://nodejs.org/api/path.html

Импортируем path:

const path = require('path')
console.log(path.basename(__filename)) // index.js - имя файла
console.log(path.dirname(__filename)) // C:\Users\Admin\Desktop\nodejs-basic - название папки
console.log(path.extname(__filename)) // .js - расширение файла
console.log(path.parse(__filename)) // объект
{
  root: 'C:\\',
  dir: 'C:\\Users\\Admin\\Desktop\\nodejs-basic',
  base: 'index.js',
  ext: '.js',
  name: 'index'
}
console.log(path.join(__dirname, 'test''second.html')) // соединяет строки в один путь
console.log(path.resolve(__dirname, './test''/second.html')) // ещё один способ генерировать пути

Урок 4. Модуль FS

Модуль FS - File System нужен для работы с файлами и папками Он умеет создавать и удалять файлы и папки, переименовывать их, записывать данные, считывать данные

Импортируем fs:

const fs = require('fs')

Создадим папку Для этого есть два метода - асинхронный и синхронный

fs.mkdir
fs.mkdirSync

Рекомендуется использовать асинхронные методы, которые не блокируют поток кода. Если папка или файл будут создаваться синхронно, выполнение кода остановится, пока они не будут созданы. Такие паузы в выполнении кода нежелательны. Создать папку notes в текущей директории

const fs = require('fs')
const path = require('path')
fs.mkdir(path.join(__dirname, 'notes'), err => {
  if (err) throw err
  console.log('Папка была создана')
})

Создать файл mynotes.txt внутри папки notes

fs.writeFile(
  path.join(__dirname, 'notes''mynotes.txt'),
  'Hello world',
  (err=> {
    if (err) throw err
    console.log('Файл был создан')
})

Дополнить файл, записать в него ещё какую-то информацию

fs.appendFile(
    path.join(__dirname, 'notes''mynotes.txt'),
    ' From append file',
    err => {
    if (err) throw err
    console.log('Файл был изменен')
})

Прочитать информацию из файла

fs.readFile(
  path.join(__dirname, "notes""mynotes.txt"),
  "utf-8",
  (errdata=> {
    if (err) throw err;
    console.log(data);
  }
);

Переименовать файл

fs.rename(
    path.join(__dirname, 'notes''mynotes.txt'),
    path.join(__dirname, 'notes''notes.txt'),
    err => {
      if (err) throw err
  
      console.log('Файл переименован')
    }
  )

Урок 5. Модуль OS

Модуль OS - Operation System предоставляет данные об операционной системе пользователя

const os = require('os')
// Платформа
console.log(os.platform())
// Архитектура
console.log(os.arch())
// Информация 
console.log(os.cpus())
// Свободная память
console.log(os.freemem())
// Сколько всего памяти
console.log(os.totalmem())
// Корневая директория
console.log(os.homedir())
// Сколько система работает
console.log(os.uptime())

Урок 6. Модуль Events

Модуль Events это работа с событиями

В node.js нет объекта document или window, он не умеет работать с событиями браузера или клавиатуры. События вызываются просто по именам

Создаём класс EventEmitter

const EventEmitter = require('events')

У него есть два метода
.emit - прослушивание событий
.on - выполнение действий при наступлении события

Создаём класс Logger, который наследуется от EventEmitter.

class Logger extends EventEmitter {
  log(message) {
    this.emit('message'`${message} ${Date.now()}`)
  }
}

У класса Logger есть метод  log(message), который принимает сообщение и добавляет к нему текущую дату Создаём экземпляр класса Logger
const logger = new Logger()

У него тоже есть метод .on и при наступлении события 'message' в консоль выводится уведомление

logger.on('message'data => {
  console.log(data)
})

Вызываем

logger.log('Hello') // Hello 1593354220626

Вызов всегда должен быть после того, как добавляем слушателя события. Событие можно вызвать несколько раз

logger.log('Hello1')
logger.log('Hello2')
logger.log('Hello3')

Результат

// Hello1 1593356005054
// Hello2 1593356005061
// Hello3 1593356005061

Урок 7. Модуль http

Модуль http нужен для создания http-сервера Код

const http = require("http");
const server = http.createServer((request,response=> {     
    response.end("Hello NodeJS!");     
})
server.listen(3000"127.0.0.1", () => {
    console.log("Сервер начал прослушивание запросов на порту 3000");
});

Рассмотрим код.

Получаем модуль http const http = require("http"); Используя метод createServer создаём сервер

В качестве коллбек функции данный метод получает функцию с двумя параметрами request и response
request хранит информацию о запросе
response отвечает за отправку ответа
response.end("Hello NodeJS!"); - ответ сервера - строка "Hello NodeJS!"

Можно написать иначеconst server = http.createServer((request,response=> {  
    response.write('11111111');   
    response.end('2222222222');     
})

В ответе будут строки, переданные через write и через end В данных методах можно передать строку, которая содержит теги и инлайн стили для них. Эти теги будут обработаны браузером

Метод listen слушает ответ сервера Он принимает три параметра: локальный порт, локальный адрес (без него тоже работает) и коллбек-функцию, которая запускается при начале прослушивания подключений. Сайт открывается по адресу http://localhost:3000/

Урок 8. Nodemon

Этот модуль мы устанавливали в первом уроке, используя команду npm install nodemon Модуль нужен для обновления данных на сервере без его перезапуска. Можно менять код и наблюдать изменения Запустить nodemon командой nodemon index не получилось.

UPD. Получилось. Для этого nodemon должен быть установлен глобально npm install nodemon -g

Но если в файле package.json написать команды

"scripts": {
  "start""node index",
  "dev""nodemon index"
}

Запускать скрипт станет возможно одной из двух команд npm run start - аналог node index npm run dev - аналог nodemon index

Урок 9. Создание простого Web-сервера

const http = require('http')
const server = http.createServer((reqres=> {
  if (req.method === 'GET') {
    res.writeHead(200, {
      'Content-Type''text/html'
    })
    res.end(`
      <h1>Form</h1>
      <form method="post" action="/">
        <input name="title" type="text" />
        <button type="submit">Send</button>
      </form>
    `)
  } else if (req.method === 'POST') {
    const body = []
    res.writeHead(200, {
      'Content-Type''text/html; charset=utf-8'
    })
    req.on('data'data => {
      body.push(Buffer.from(data))
    })
    req.on('end', () => {
      const message = body.toString().split('=')[1]
      res.end(`
        <h1>Ваше сообщение: ${message}</h1>
      `)
    })
  }
})
server.listen(3000, () => {
  console.log('Server is running...')
})

Разберём код

if (req.method === 'GET') условие показывает, что страница загрузилась
res.writeHead(200, {
      'Content-Type''text/html'
    })

У функции writeHead два параметра: код ответа и объект с заголовком. Указываем что если ответ сервера 200, заголовок документа text/html то есть нужно обрабатывать теги, если бы заголовок был text/json, браузер выводил бы строку

if (req.method === 'POST') условие показывает, что пользователь нажал на кнопку Send
req.on параметр request наследует EventEmitter в том числе метод .on

body.push(Buffer.from(data)) так как сервер получает и отправляет результаты небольшими фрагментами, их нужно соединить все вместе

const message = body.toString().split('=')[1] сообщение приходит вида title="здесь сообщение" Разбиваем строку по знаку равно и берём вторую часть

Урок 10. Web-сервер с HTML-страницами

Рассмотрим роутинг - возможность вынести веб-страницы в отдельные файлы и переключаться между ними. Создадим папку views и в ней два html-файла index.html и about.html В файле index.html разместим ссылку

<a href="/about">About page</a>

В файле about.html разместим ссылку

<a href="/">Home page</a>
В файле index.js  следующий код

const http = require('http')
const path = require('path')
const fs = require('fs')
const server = http.createServer((reqres=> {
  if (req.method === 'GET') {
    res.writeHead(200, {
      'Content-Type''text/html; charset=utf-8'
    })
    if (req.url === '/') {
      fs.readFile(
        path.join(__dirname, 'views''index.html'),
        'utf-8',
        (errcontent=> {
          if (err) {
            throw err
          }
          res.end(content)
        }
      )
    } else if (req.url === '/about') {
      fs.readFile(
        path.join(__dirname, 'views''about.html'),
        'utf-8',
        (errcontent=> {
          if (err) {
            throw err
          }
          res.end(content)
        }
      )
    }
  } 
})
server.listen(3000, () => {
  console.log('Server is running...')
})

Разберём что здесь происходит
Подключаем модули:
 http - создание web-сервера
 fs - позволит прочитать содержимое файлов index.html и about.html
 path - пропишет пути к этим файлам

const http = require("http");
const fs = require("fs");
const path = require("path");

Если страница загружается if (req.method === 'GET') Прописываем заголовок

    res.writeHead(200, {
      'Content-Type''text/html; charset=utf-8'
    })

Если адрес страницы '/' - это главная страница

    if (req.url === '/') {
      fs.readFile(
        path.join(__dirname, 'views''index.html'),
        'utf-8',
        (errcontent=> {
          if (err) {
            throw err
          }
          res.end(content)
        }
      )

Проходим по адресу path.join(__dirname, 'views''index.html') Указываем кодировку 'utf-8' Обрабатываем ошибку

          if (err) {
            throw err
          }

И, если ошибки нет, загружаем контент res.end(content) Для страницы about.html всё точно так же за исключением адреса файла и адреса ссылки

Урок 11. Создание простого REST-сервера

Создадим API-сервер Для этого в коде index.html заменим ссылку

<a href="/api/users">API</a>

А в index.js заменим фрагмент кода, который отвечал за страницу about

    else if (req.url === "/api/users") {
      res.writeHead(200, {
        "Content-Type""text/json",
      });
      const users = [
        { name: "Vlad", age: 25 },
        { name: "Elena", age: 23 },
      ];
      res.end(JSON.stringify(users));
    }

Для удобства просмотра можно установить расширение JSONView