Shell-free script với Execa 7

Mar 12 2023
Mặc dù shell script rất tiện dụng nhưng nhiều nhà phát triển thích tính linh hoạt, tính biểu cảm và hệ sinh thái đi kèm với các ngôn ngữ lập trình như JavaScript. zx, một dự án phổ biến gần đây của Google, kết hợp những gì tốt nhất của cả hai thế giới.
Bãi biển gần như không có vỏ sò (ảnh của Aaron Burden)

Mặc dù shell script rất tiện dụng nhưng nhiều nhà phát triển thích tính linh hoạt, tính biểu cảm và hệ sinh thái đi kèm với các ngôn ngữ lập trình như JavaScript. zx, một dự án phổ biến gần đây của Google, kết hợp những gì tốt nhất của cả hai thế giới.

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}`

Tại sao lại sử dụng cả Node và Bash? Với Execa, không có cú pháp trình bao nào cần nhớ: mọi thứ chỉ là JavaScript đơn giản. Hầu như tất cả các tính năng dành riêng cho trình bao đều có thể được thể hiện bằng JavaScript. Đối với các trường hợp cạnh còn lại, một shelltùy chọn khả dụng.

Đây là nhiều hơn:

  • Bảo mật : tiêm vỏ không khả thi về mặt kỹ thuật.
  • Đa nền tảng : không phải máy Windows nào cũng có sẵn Bash.
  • Người biểu diễn : sinh ra một trình bao cho mọi lệnh đều phải trả giá. Thậm chí npxcó thể được bỏ qua vì Execa có thể thực thi trực tiếp các tệp nhị phân được cài đặt cục bộ.
  • # 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 },
)

Mô child_process-đun Node lõi bao gồm nhiều tính năng hữu ích: thời gian chờ, hủy, quy trình nền , IPC , PID , UID/GID, tham chiếu yếu , v.v. Execa thêm một vài cái bổ sung : chấm dứt duyên dáng , dọn dẹp , đầu ra xen kẽ , v.v. Những cái đó có thể được đặt bằng cách sử dụng $(options)cho một hoặc nhiều lệnh.

import { $ } from 'execa'

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

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

Quá trình con có thể khó gỡ lỗi. Đây là lý do tại sao Execa:

  • Bao gồm một verbosetùy chọn , có thể được thiết lập bằng cách sử dụng NODE_DEBUG=execa.
  • Báo cáo các thông báo lỗi và thuộc tính chi tiết.
  • Hoàn toàn không trạng thái, giúp dễ dàng tìm ra thư mục hiện tại là gì hoặc bất kỳ tùy chọn nào khác.
  • > 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)