สคริปต์ที่ไม่มีเชลล์ด้วย Execa 7

Mar 12 2023
แม้ว่าเชลล์สคริปต์จะมีประโยชน์มาก แต่นักพัฒนาหลายคนชอบความยืดหยุ่น ความชัดเจน และระบบนิเวศที่มาพร้อมกับภาษาโปรแกรม เช่น JavaScript zx ซึ่งเป็นโครงการยอดนิยมล่าสุดจาก Google ได้รวมสิ่งที่ดีที่สุดของทั้งสองโลกเข้าด้วยกัน
ชายหาดที่แทบไม่มีเปลือกหอย (ภาพโดย Aaron Burden)

แม้ว่าเชลล์สคริปต์จะมีประโยชน์มาก แต่นักพัฒนาหลายคนชอบความยืดหยุ่น ความชัดเจน และระบบนิเวศที่มาพร้อมกับภาษาโปรแกรม เช่น JavaScript zxซึ่งเป็นโครงการยอดนิยมล่าสุดจาก Google ได้รวมสิ่งที่ดีที่สุดของทั้งสองโลกเข้าด้วยกัน

const branch = await $`git branch --show-current`
await $`deploy --branch=${branch}`

import { $ } from 'execa'

const branch = await $`git branch --show-current`
await $`deploy --branch=${branch}`

เหตุใดจึงต้องใช้ทั้ง Node และ Bash ด้วย Execa ไม่มีไวยากรณ์ของเชลล์ที่ต้องจดจำ: ทุกอย่างเป็นเพียง JavaScript ธรรมดา คุณสมบัติเฉพาะของเชลล์เกือบทั้งหมดสามารถแสดงใน JavaScript สำหรับเคสขอบที่เหลือมีshellตัวเลือก ให้เลือก

นี่คือเพิ่มเติม:

  • ปลอดภัย : การฉีดเปลือกไม่สามารถทำได้ในทางเทคนิค
  • ข้ามแพลตฟอร์ม : ไม่ใช่เครื่อง Windows ทุกเครื่องที่มี Bash
  • ประสิทธิภาพ : การวางไข่ของเชลล์สำหรับทุกคำสั่งมีค่าใช้จ่าย สามารถnpxข้ามได้เนื่องจาก Execa สามารถ เรียกใช้ ไบนารีที่ติดตั้งในเครื่องได้โดยตรง
  • # In Bash
    API_KEY="secret" npx deploy "$cluster" &> logs.txt && echo "done"
    // In JavaScript
    import { $ } from 'execa'
    
    const options = { env: { API_KEY: 'secret' } }
    await $(options)`deploy ${cluster}`.pipeAll(’logs.txt’)
    console.log('done')
    

import { $ } from 'execa'
import pRetry from 'p-retry'

await pRetry(
  async () => await $`deploy dev_cluster`,
  { retries: 5 },
)

โมดูลchild_processโหนดหลักมีคุณสมบัติที่มีประโยชน์มากมาย: หมดเวลา การยกเลิกกระบวนการเบื้องหลัง , IPC , PID , UID/GID การอ้างอิงที่อ่อนแอและอื่นๆ Execa เพิ่มอีกไม่กี่รายการ : การสิ้นสุดที่สง่างาม , การล้างข้อมูล , เอาต์พุตแบบแทรกซ้อนและอื่น ๆ สามารถตั้งค่าได้โดยใช้$(options)คำสั่งเดียวหรือหลายคำสั่ง

import { $ } from 'execa'

const $$ = $({ timeout: 5000, all: true })

// `all` retrieves both stdout and stderr
const { all } = $$`deploy dev_cluster`

กระบวนการย่อยอาจแก้ไขจุดบกพร่องได้ยาก นี่คือเหตุผลที่ Execa:

  • รวมถึงverboseตัวเลือกที่สามารถตั้งค่าโดยNODE_DEBUG=execaใช้
  • รายงานข้อความแสดงข้อผิดพลาดและคุณสมบัติโดยละเอียด
  • ไร้สัญชาติอย่างแท้จริง ทำให้ง่ายต่อการค้นหาว่าไดเร็กทอรีปัจจุบันคืออะไร หรือตัวเลือกอื่นใด
  • > NODE_DEBUG=execa node deploy.js
    
    [16:50:03.305] deploy dev_cluster
    ........dev_cluster successfully deployed.
    
    [16:53:06.378] deploy prod_cluster
    .............prod_cluster successfully deployed.
    

import { $ } from 'execa'

// Pipe input from a string or buffer, like <<< in Bash
await $({ input: 'dev_cluster' })`deploy`

// Pipe input from a file, like < in Bash
await $({ inputFile: 'clusters.txt' })`deploy`

// Pipe output to a file, like >, 2> and &> in Bash
await $`deploy dev_cluster`.pipeStdout('stdout.txt')
await $`deploy dev_cluster`.pipeStderr('stderr.txt')
await $({ all: true })`deploy dev_cluster`.pipeAll('logs.txt')

// Pipe output to another command, like | and |& in Bash
await $`deploy dev_cluster`.pipeStdout($`grep done`)

// Pipe output to a stream, like 2>&1 in Bash
const { stdout } = await $`deploy dev_cluster`.pipeStderr(process.stdout)