Node.js 与前端开发实战 | 青训营笔记

68 阅读3分钟
  • 这是我参与第五届青训营伴学笔记创作活动的第8天

Node.js的应用场景

  • 前端工程化
    • Bundle:webpack vite esbuild parcel
    • Uglify: uglifyjs
    • Transpile: bablejs typescript
    • 其他语言加入竞争:esbuild parcel prisma
    • 难以替代

image.png

  • Web服务端应用
    • 效率接近常见编译语言
    • 生态丰富 npm V8-inspector
    • 结合前端优势SSR
    • 有独特优势

image.png

  • Electron跨端桌面应用

    • vscode slack dscord zoom
    • 大型公司效率化工具
    • 大部分场景值得考虑 image.png
  • Nodejs在字节

    • BFF SSR应用: Modern.js
    • 服务端: 头条 西瓜 懂车
    • Electron: 飞连 飞书
      image.png

Node.js运行时结构

image.png

  • V8: JavaScript Runtime, 诊断调试工具inspector
  • libuv: eventloop事件循环 syscall系统调用

特点

  • 异步I/O
  • 单线程
    • 不用考虑多线程同步 高效利用系统资源
    • 阻塞产生负面影响
  • 跨平台
    • 开发成本低 (大部分功能 api)

编写Http Server

安装Nodejs

NVM_NODEJS_ORG_MIRROR = https://npmmirror.com/mirrors/node nvm install 16

image.png

编写Http Server + Client 收发Get Post请求

  • http server
// 1. 通过 http.createServer 创建一个 http 服务
// 2. 通过 req.on('data') 接收请求体
// 3. 通过 req.on('end') 接收请求体结束
// 4. 通过 Buffer.concat(bufs).toString('utf8') 将请求体转换为字符串
// 5. 通过 JSON.parse(buf) 将请求体转换为对象
// 6. 通过 res.setHeader 设置响应头
// 7. 通过 res.end 发送响应
//
const http = require('http')

const server = http.createServer((req, res) => {
  const bufs = []
  req.on('data', (buf) => {
    bufs.push(buf)
  })

  req.on('end', () => {
    const buf = Buffer.concat(bufs).toString('utf8')
    let msg = 'Hello'
    try {
      const ret = JSON.parse(buf)
      msg = ret.msg
    } catch (e) {
      
    }

    const responseJson = {
      msg: `received: ${msg}`
    }
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify(responseJson))
  })
})

const port = 3000

server.listen(port, () => {
  console.log(`Server is running on port ${port}`)
})
  • http client
// 1. 引入http模块
// 2. 创建一个客户端
// 3. 设置请求头
// 4. 发送请求
// 5. 接收响应
// 6. 打印响应内容
//
// 1. 通过node http_server.js启动服务
// 2. 通过node http_client.js启动客户端
const http = require('http')

const body  = JSON.stringify({
  msg: 'Hello from my client'
})

const req = http.request('http://127.0.0.1:3000', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    }
}, (res) => {
    const bufs = []
    res.on('data', (buf) => {
      bufs.push(buf)
    })

  res.on('end', () => {
    const buf = Buffer.concat(bufs)
     const json = JSON.parse(buf.toString('utf8'))
    console.log(json)
  })
})

req.end(body)

编写静态文件服务器

  • static server
// 创建一个文件注释头
// 1. 通过http模块创建一个http服务
// 2. 通过fs模块读取文件
// 3. 通过path模块获取文件路径
// 4. 通过url模块获取请求的url
// 5. 通过stream风格的api来读取文件,减少内存占用

var http = require('http');
var fs = require('fs');
var path = require('path');
var url = require('url');

const folderPath = path.join(__dirname, './static')

var server = http.createServer((req,res) => {

  const info = url.parse(req.url)

  // static/index.html
  const filePath = path.resolve(folderPath, './'+ info.path)

  console.log(filePath);

  //stream风格api可以帮助我们占用尽可能少的内存空间
  const filestream = fs.createReadStream(filePath, {autoClose:true})

  filestream.pipe(res)
})

const port = 3001

server.listen(port, () => {
  console.log(`listening on port: ${port}`)
})

编写React SSR 服务

  • SSR (server side rendering) 什么特点
    • 相比于传统的HTML模板引擎 避免重复编码代码
    • 相比于SPA(single page application) 首屏渲染更快 SEO友好
    • 缺点
      • qps较低 前端代码需要考虑服务端渲染情况
  • ssr_example.js
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const http  = require('http');

function App(props){
  return  React.createElement('div', {}, props.children || 'Hello')
}

const server = http.createServer((req,res) => {
  res.end(`
    <!DOCTYPE html>
    <head>
      <title>My Application</title>
    </head>
    <body>
      ${ReactDOMServer.renderToString(
        React.createElement(App, {}, 'my-app'))}
    </body>
    </html>
  `)
})

const port = 3001

server.listen(port, () => {
  console.log(`listening on port: ${port}`)
})
  • SSR难点
    • 需要处理打包代码
    • 需要思考前端代码在后端服务端运行时的逻辑
    • 移除对服务端无意义的副作用 或重置环境

使用inspector 进行调试诊断

  • V8 Inspector: 开箱即用 特性丰富 与前端开发一致 跨平台
  • 场景
    • 查看clog内容
    • breakpoint
    • 高CPU 死循环:couprofiule
    • 高内存占用 heapsnapshot
    • 性能分析

部署简介

  • 部署主要问题
    • 守护进程
    • 多进程
    • 记录进程状态
  • 容器环境
    • 通常有健康检查手段 只需要考虑多核cpu利用率即可

延伸话题

  • 如何贡献
  • 编译nodejs
  • 诊断/追踪
  • WASM / NAPI image.png