Node.js Snippets

388
Node.js Snippets
Node.js Snippets

Модуль http

// Простой сервер
import http from 'http'

const server = http.createServer((req, res) => {
  // write status and headers
  res.writeHead(200, { 'Content-Type': 'text/plain' })
  // send plain text
  res.write('hi\n')

  // some json
  const json = {
    message: 'bye'
  }
  // send json
  res.end(JSON.stringify(json))
})

server.listen(
  3000,
  /* host - localhost or 127.0.0.1 by default */
  (e) => {
    if (e) {
      console.error(e)
    }
    console.log('🚀')
  }
)


// Ответ сервера в виде HTML-файла
const filePath = `${__dirname}/index.html`

const server = http.createServer(async (req, res) => {
  if (req.url === '/hi') {
    res.writeHead(200, { 'Content-Type': 'text/html' })

    try {
      const content = await fs.readFile(filePath, 'utf-8')
      return res.end(content)
    } catch (e) {
      console.error(e)
    }
  }
  res.writeHead(200, { 'Content-Type': 'text/plain' })
  res.write('bye')
  res.end()
})


// Ответ сервера в виде аудио-файла
import { promises as fs, constants, createReadStream } from 'fs'

// path to audio
const filePath = `${__dirname}/audio.mp3`

const server = http.createServer(async (req, res) => {
  switch (req.url) {
    case '/': {
      res.writeHead(200, { 'Content-Type': 'text/plain' })
      res.write('hi')
      return res.end()
    }
    case '/audio': {
      try {
        res.writeHead(200, { 'Content-Type': 'audio/mp3' })
        // check if file exists
        await fs.access(filePath, constants.F_OK)
        // create read stream
        const stream = createReadStream(filePath)
        // create pipe
        return stream.pipe(res)
      } catch (e) {
        res.end('not found')
      }
    }
  }
})

Модуль fs

import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import { promises as fs } from 'fs'

// absolute path to current working directory
const __dirname = dirname(fileURLToPath(import.meta.url))

// with `join()`
const dirPath = join(__dirname, 'files')
// without `join()`
const filePath = `${dirPath}/message.txt`

const content = 'hi'

// create
try {
  // create dir
  await fs.mkdir(dirPath, { recursive: true })
  // create file
  await fs.writeFile(filePath, content)
  console.log('created')
} catch (e) {
  console.error(e)
}

// read
try {
  const content = await fs.readFile(filePath, 'utf-8')
  console.log(content) // hi
} catch (e) {
  console.error(e)
}

// append
try {
  await fs.appendFile(filePath, '\nbye')
  const content = await fs.readFile(filePath, 'utf-8')
  console.log(content) // hi \nbye
} catch (e) {
  console.error(e)
}

// remove
try {
  // remove file
  await fs.unlink(filePath)
  // remove dir
  await fs.rmdir(dirPath)
} catch (e) {
  console.error(e)
}

Безопасное создание, чтение и удаление файла

// root path
const ROOT_PATH = `${__dirname}/files`
// check if dir or file not exists
const notExist = (e) => e.code === 'ENOENT'
// truncate path
const truncPath = (p) => p.split('/').slice(0, -1).join('/')

// create
async function createFile(fileData, filePath, fileExt = 'json') {
  const fileName = `${ROOT_PATH}/${filePath}.${fileExt}`

  try {
    // create file
    await fs.writeFile(fileName, JSON.stringify(fileData, null, 2))
  } catch (e) {
    if (notExist(e)) {
      // create dir
      await fs.mkdir(truncPath(`${ROOT_PATH}/${filePath}`), {
        recursive: true
      })
      // create file after dir has been created
      return createFile(fileData, filePath, fileExt)
    }
    console.error(e)
  }
}

// read
async function readFile(filePath, fileExt = 'json') {
  const fileName = `${ROOT_PATH}/${filePath}.${fileExt}`

  let fileHandler = null
  try {
    // open file
    fileHandler = await fs.open(fileName)
    // read file
    return await fileHandler.readFile('utf-8')
  } catch (e) {
    if (notExist(e)) {
      return console.error('not found')
    }
    console.error(e)
  } finally {
    // close handler
    fileHandler?.close()
  }
}

// remove
async function removeFile(filePath, fileExt = 'json') {
  const fileName = `${ROOT_PATH}/${filePath}.${fileExt}`

  try {
    // remove file
    await fs.unlink(fileName)
    // remove dir
    await removeDir(truncPath(`${ROOT_PATH}/${filePath}`))
  } catch (e) {
    if (notExist(e)) {
      return console.error('not found')
    }
    console.error(e)
  }
}

// remove dir
async function removeDir(dirPath, rootPath = ROOT_PATH) {
  if (dirPath === rootPath) return

  const isEmpty = (await fs.readdir(dirPath)).length < 1

  if (isEmpty) {
    // remove dir if its empty
    await fs.rmdir(dirPath)
    // remove parent dir
    removeDir(truncPath(dirPath), rootPath)
  }
}

// get all file names
async function getFileNames(path = ROOT_PATH) {
  let fileNames = []

  try {
    const files = await fs.readdir(path)

    if (files.length < 1) return fileNames

    for (let file of files) {
      file = `${path}/${file}`

      const isDir = (await fs.stat(file)).isDirectory()

      if (isDir) {
        fileNames = fileNames.concat(await getFileNames(file))
      } else {
        fileNames.push(file)
      }
    }

    return fileNames
  } catch (e) {
    if (notExist(e)) {
      return console.error('not found')
    }
    console.error(e)
  }
}

Проверка среды выполнения кода

const isBrowser = () => ![typeof window, typeof document].includes('undefined')

const isNode = () =>
  typeof process !== 'undefined' &&
  !!process.versions &&
  !!process.versions.node

Создание хеша

import crypto from 'crypto'

const createHash = (val) =>
  crypto.createHash('sha256').update(val).digest('hex')

const hash = createHash('hi')
console.log(hash)
// 8f434346648f6b96df89dda901c5176b10a6d83961dd3c1ac88b59b2dc327aa4

Генерация UUID

const genUUID = () =>
  ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
    (c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
  )

console.log(genUUID())
// 3b472cc4-8370-4469-8c12-428e7da35063

Преобразование строки в base64 и обратно

const btoa = (str) => Buffer.from(str, 'binary').toString('base64')

console.log(btoa('hi')) // aGk=

const atob = (str) => Buffer.from(str, 'base64').toString('binary')

console.log(atob('Ynll')) // bye

multer

import multer from 'multer'

const dirPath = `${__dirname}/files`

const uploadFile = multer({
  storage: multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, dirPath)
    },
    filename: (_, file, cb) => {
      cb(null, file.originalname)
    }
  })
})

// usage
app.post('/upload', uploadFile.single('file'), (req, res) => {
  console.log(req.files)
})

nodemailer + google-spreadsheet

import nodemailer from 'nodemailer'
import { GoogleSpreadsheet } from 'google-spreadsheet'

const doc = new GoogleSpreadsheet(process.env.GOOGLE_SPREADSHEET_ID)

const gmailTransporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.GMAIL_USER,
    pass: process.env.GMAIL_PASSWORD
  }
})

const createMessage = (username, email) => `
  <h1>${username}</h1>
  <p>${email}</p>
`

async function sendMail() {
  try {
    await doc.useServiceAccountAuth({
      client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
      private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n')
    })

    await doc.loadInfo()

    const sheet = doc.sheetsByIndex[0]

    const rows = await sheet.getRows()

    for (const row of rows) {
      await gmailTransporter.sendMail({
        from: 'App name <example.com>',
        to: row.email,
        subject: 'Title',
        text: 'Text fallback',
        html: createMessage(row.username, row.email)
      })
    }
    console.log('All emails has been sent')
  } catch (e) {
    console.error(e)
  }
}