前端工程師寫 Node.js 腳本,能解決很多重複勞動。整理一些實用的腳本開發技巧。
基礎工具庫
bash
npm i -g commander # 命令行參數解析
npm i -g chalk # 終端顏色
npm i -g inquirer # 交互式問答
npm i -g ora # 加載動畫
npm i -g fs-extra # 增強的 fs 模塊
批量重命名文件
javascript
#!/usr/bin/env node
// rename-images.js:把 img001.jpg 批量改成 product-001.jpg
const fs = require("fs-extra");
const path = require("path");
const chalk = require("chalk");
async function renameImages(dir, prefix) {
const files = await fs.readdir(dir);
const images = files.filter((f) => /\.(jpg|png|webp)$/i.test(f));
console.log(chalk.blue(`找到 ${images.length} 張圖片`));
for (let i = 0; i < images.length; i++) {
const ext = path.extname(images[i]);
const newName = `${prefix}-${String(i + 1).padStart(3, "0")}${ext}`;
await fs.rename(path.join(dir, images[i]), path.join(dir, newName));
console.log(chalk.green(`✅ ${images[i]} → ${newName}`));
}
}
renameImages("./images", "product");
交互式腳手架
javascript
#!/usr/bin/env node
// create-component.js:快速創建 Vue 組件
const inquirer = require("inquirer");
const fs = require("fs-extra");
const path = require("path");
const TEMPLATE = (name, hasProps) => `<template>
<div class="${name.toLowerCase()}">
<slot />
</div>
</template>
<script>
export default {
name: '${name}',
${
hasProps
? `props: {
value: {
type: String,
default: ''
}
},`
: ""
}
data() {
return {}
}
}
</script>
<style lang="scss" scoped>
.${name.toLowerCase()} {
}
</style>
`;
async function main() {
const answers = await inquirer.prompt([
{
type: "input",
name: "name",
message: "組件名稱 (PascalCase):",
validate: (v) => /^[A-Z]/.test(v) || "請使用 PascalCase",
},
{
type: "list",
name: "dir",
message: "放在哪個目錄:",
choices: ["components", "views", "layouts"],
},
{
type: "confirm",
name: "hasProps",
message: "添加 Props 模板?",
default: false,
},
]);
const { name, dir, hasProps } = answers;
const filePath = path.join("src", dir, `${name}.vue`);
if (await fs.pathExists(filePath)) {
console.log(chalk.red(`❌ ${filePath} 已存在`));
return;
}
await fs.ensureDir(path.dirname(filePath));
await fs.writeFile(filePath, TEMPLATE(name, hasProps));
console.log(chalk.green(`✅ 創建成功: ${filePath}`));
}
main();
檢查依賴更新
javascript
#!/usr/bin/env node
// check-updates.js:找出有新版本的依賴
const { execSync } = require("child_process");
const pkg = require("./package.json");
function getLatestVersion(name) {
try {
return execSync(`npm view ${name} version`, { encoding: "utf8" }).trim();
} catch {
return null;
}
}
async function checkUpdates() {
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
const outdated = [];
for (const [name, version] of Object.entries(deps)) {
const current = version.replace(/[\^~]/, "");
const latest = getLatestVersion(name);
if (latest && latest !== current) {
outdated.push({ name, current, latest });
}
}
if (outdated.length === 0) {
console.log("✅ 所有依賴都是最新的");
return;
}
console.log("\n有更新的依賴:");
outdated.forEach(({ name, current, latest }) => {
console.log(` ${name}: ${current} → ${latest}`);
});
}
checkUpdates();
實用的 npm scripts 組合
json
{
"scripts": {
"new:component": "node scripts/create-component.js",
"check:updates": "node scripts/check-updates.js",
"rename:images": "node scripts/rename-images.js",
"precommit": "lint-staged",
"prepare": "husky install",
"analyze": "ANALYZE=true npm run build",
"size": "size-limit"
}
}
小結
commander解析命令行參數,inquirer做交互式問答fs-extra是fs的增強版,支持 Promise 和額外方法(ensureDir、copy、move)- 腳本放
scripts/目錄,通過npm scripts暴露給團隊 - 用
#!/usr/bin/env node讓腳本直接執行