Skip to content

Node基础

I/O 处理

异步非阻塞 I/O

js
fs.readFile('./download.js', (err, data) => {
  if (err) throw err
  console.log(data, data.toString())
})

~(async () => {
  const fs = require('fs')
  const { promisify } = require('util')
  const readFile = promisify(fs.readFile)
  const data = await readFile('./download.js')
  console.log(data.toString())
})()

Buffer 缓冲区

  • Buffer 用于 TCP 流、文件系统操作、以及其他上下文中与八位字节流进行交互
  • 八位字节组成的数组,可以有效的在 JS 中存储二进制数据
js
// 创建一个长度为10字节以0填充的Buffer
const buf1 = Buffer.alloc(10)
console.log(buf1) // <Buffer 00 00 00 00 00 00 00 00 00 00>

// 创建一个Buffer包含ascii.
const buf2 = Buffer.from('a')
console.log(buf2, buf2.toString()) // <Buffer 61> a

// 创建Buffer包含UTF-8字节
const buf3 = Buffer.from('中文')
console.log(buf3) // <Buffer e4 b8 ad e6 96 87>

// 合并Buffer
const buf4 = Buffer.concat([buf2, buf3])
console.log(buf4, buf4.toString()) // <Buffer 61 e4 b8 ad e6 96 87> a中文

http 服务

js
const http = require('http')
const fs = require('fs')
const server = http.createServer((request, response) => {
  // response.end('hello ...')
  const { url, method, headers } = request
  if (url === '/' && method === 'GET') {
    // 静态页面服务
    fs.readFile('index.html', (err, data) => {
      response.statusCode = 200
      response.setHeader('Content-Type', 'text/html')
      response.end(data)
    })
  } else if (url === '/users' && method === 'GET') {
    // Ajax服务
    response.writeHead(200, {
      'Content-Type': 'application/json'
    })
    response.end(
      JSON.stringify({
        name: 'laowang'
      })
    )
  } else if (method === 'GET' && headers.accept.includes('image/*')) {
    // 图片文件服务
    fs.createReadStream('./' + url).pipe(response)
  }
})
server.listen(3000)

stream 流

  • stream 是用于 node 中流数据交互的接口
js
const fs = require('fs')
const rs = fs.createReadStream('./img.png')
const ws = fs.createWriteStream('./img2.png')
rs.pipe(ws)

CLI 工具

注意:需要安装特定版本的 ora、chalk、open

bash
npm i commander download-git-repo handlebars figlet clear open@8 chalk@4 ora@5 -s

定制命令行页面

js
#!/usr/bin/env node
const program = require('commander')
program.version(require('../package.json').version)
program.command('init <name>').description('init project').action(require('../lib/init'))
program.parse(process.argv)

lib\init.js

js
const { promisify } = require('util')
const figlet = promisify(require('figlet'))
const clear = require('clear')
const chalk = require('chalk')
const open = require('open')
const clone = require('./download')

const log = content => console.log(chalk.green(content))

const asyncSpawn = async (...args) => {
  const { spawn } = require('child_process')
  return new Promise(resolve => {
    const proc = spawn(...args)
    proc.stdout.pipe(process.stdout)
    proc.stderr.pipe(process.stderr)
    proc.on('close', () => {
      resolve()
    })
  })
}

module.exports = async name => {
  clear()
  const data = await figlet('Welcome')
  log(data)

  log(`创建项目:${name}`)
  await clone('github:su37josephxia/vue-template', name)

  log(`安装依赖:${name}`)
  const npmRun = process.platform === 'win32' ? 'npm.cmd' : 'npm'
  await asyncSpawn(npmRun, ['install'], {
    cwd: `./${name}`
  })
  log(`
    安装完成:
    To get Start:
    ===========================
      cd ${name}
      npm run serve
    ===========================
  `)

  log('打开浏览器')
  open('http://localhost:8080')
  await asyncSpawn(npmRun, ['run', 'serve'], { cwd: `./${name}` })
}

lib\download.js

js
const { promisify } = require('util')
const download = promisify(require('download-git-repo'))
const ora = require('ora')

module.exports = async (repo, desc) => {
  const process = ora(`下载... ${repo}`)
  process.start()
  try {
    await download(repo, desc)
  } catch (error) {
    console.log('err', error)
    process.fail()
  }
  process.succeed()
}

约定路由功能

  • loader 文件
  • 代码模板渲染 hbs Mustache 风格模板
js
import fs from 'fs'
import handlebars from 'handlebars'
import chalk from 'chalk'

export default async () => {
  // 获取页面列表
  const list = fs
    .readdirSync('./src/views')
    .filter(v => v !== 'Home.vue')
    .map(v => ({
      name: v.replace('.vue', '').toLowerCase(),
      file: v
    }))

  console.log('list', list)

  // 生成路由定义
  compile(
    {
      list
    },
    './src/router.js',
    './template/router.js.hbs'
  )

  // 生成菜单
  compile(
    {
      list
    },
    './src/App.vue',
    './template/App.vue.hbs'
  )

  /**
   * 编译模板文件
   * @param meta 数据定义
   * @param filePath 目标文件路径
   * @param templatePath 模板文件路径
   */
  function compile(meta, filePath, templatePath) {
    if (fs.existsSync(templatePath)) {
      const content = fs.readFileSync(templatePath).toString()
      const result = handlebars.compile(content)(meta)
      fs.writeFileSync(filePath, result)
    }
    console.log(chalk.green(`🚀${filePath} 创建成功`))
  }
}

发布 npm

bash
#!/usr/bin/env bash
npm config get registry # 检查仓库镜像库
npm config set registry=http://registry.npmjs.org
echo '请进行登录相关操作:'
npm login # 登陆
echo "-------publishing-------"
npm publish # 发布
npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像
echo "发布完成"
exit

常备不懈,才能有备无患