Executando Scripts Node.js em JavaScript
Como executar arquivos JavaScript puros com Node.js - execução direta, scripts npm, linhas shebang e análise de argumentos de linha de comando.
Busque em todas as páginas da documentação
Como executar arquivos JavaScript puros com Node.js - execução direta, scripts npm, linhas shebang e análise de argumentos de linha de comando.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
# Executa um script diretamente
node script.js
# Executa com reinício automático em caso de alterações de arquivo (Node 18.11+)
node --watch script.js
# Executa com variáveis de ambiente
NODE_ENV=production node script.js
# Passa argumentos para o script
node script.js --name Alice --verbose// package.json - scripts npm
{
"name": "my-cli",
"version": "1.0.0",
"type": "module",
"bin": {
"my-cli": "./bin/cli.js"
},
"scripts": {
"start": "node script.js",
"dev": "node --watch script.js",
"cli": "node bin/cli.js"
}
}// bin/cli.js - com shebang
#!/usr/bin/env node
import { parseArgs } from 'node:util';
const { values } = parseArgs({
options: {
name: { type: 'string', short: 'n' },
verbose: { type: 'boolean', short: 'v' },
},
});
console.log(`Olá, ${values.name ?? 'mundo'}!`);# Torna o script executável (apenas Unix/macOS)
chmod +x bin/cli.js
# Em seguida, execute-o diretamente
./bin/cli.js --name AliceQuando usar isso: Scripts de build, tarefas de automação, utilitários únicos, ferramentas CLI ou qualquer coisa que você não queira enviar para um navegador.
Uma CLI completa de renomeação de arquivos que converte nomes de arquivos para minúsculas em um diretório.
#!/usr/bin/env node
// bin/rename-lower.js
import { readdir, rename } from 'node:fs/promises';
import { join } from 'node:path';
import { parseArgs } from 'node:util';
const { values, positionals } = parseArgs({
options: {
dry: { type: 'boolean', short: 'd' },
help: { type: 'boolean', short: 'h' },
},
allowPositionals: true,
});
if (values.help || positionals.length === 0) {
console.log('Uso: rename-lower <dir> [--dry]');
process.exit(values.help ? 0 : 1);
}
const dir = positionals[0];
try {
const files = await readdir(dir);
for (const file of files) {
const lower = file.toLowerCase();
if (file === lower) continue;
const from = join(dir, file);
const to = join(dir, lower);
if (values.dry) {
console.log(`[dry] ${from} -> ${to}`);
} else {
await rename(from, to);
console.log(`renomeado ${from} -> ${to}`);
}
}
} catch (err) {
console.error('Erro:', err.message);
process.exit(1);
}// package.json
{
"name": "rename-lower",
"version": "1.0.0",
"type": "module",
"bin": {
"rename-lower": "./bin/rename-lower.js"
}
}# Tente localmente
npm link
rename-lower ./photos --dry
rename-lower ./photosO que isso demonstra:
node:util parseArgs para análise de argv sem dependênciasbin em package.json para que npm link exponha o comando globalmenteQuando você digita node script.js, o Node.js:
"type": "module" em package.json ou o arquivo termina em .mjs, caso contrário, CommonJS.process, console, Buffer e similares.process.exit().Uma linha shebang como #!/usr/bin/env node informa ao carregador do sistema operacional qual interpretador usar quando o arquivo é executado diretamente. A ferramenta env procura node no PATH, o que é mais portátil do que um /usr/local/bin/node codificado.
process.argv é um array onde o índice 0 é o caminho do binário do Node, o índice 1 é o caminho do script e os índices 2+ são os argumentos fornecidos pelo usuário. É por isso que parseArgs ignora os dois primeiros por padrão.
# Passa argumentos através de um script npm (note o --)
npm run cli -- --name Alice
# Variáveis de ambiente inline
API_KEY=abc node script.js
# Modo de observação (Node 18.11+)
node --watch script.js
# Modo de observação com um ponto de entrada específico
node --watch --watch-path=./src script.js
# Modo de inspeção/depuração
node --inspect-brk script.js
# Analisa argumentos com a utilidade integrada
node -e "console.log(require('node:util').parseArgs({options:{n:{type:'string'}}}))" -- -n hiMesmo para scripts JavaScript puros, você pode optar pela verificação de tipo sem adicionar uma etapa de build ativando // @ts-check no topo do arquivo e criando um jsconfig.json:
// jsconfig.json
{
"compilerOptions": {
"checkJs": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"lib": ["ES2022"]
},
"include": ["bin/**/*.js", "scripts/**/*.js"]
}Adicione tipos JSDoc para parâmetros e o editor - e tsc --noEmit - capturarão erros:
// @ts-check
/** @param {string} name @returns {string} */
function greet(name) {
return `Olá, ${name}!`;
}#!/usr/bin/env node, a execução direta do arquivo (./script.js) em shells Unix gera um erro "exec format error" ou executa o arquivo como um script de shell.chmod +x. Um shebang correto é inútil se o arquivo não for executável. A permissão deve ser adicionada com chmod +x bin/cli.js e o bit confirmado no Git (git update-index --chmod=+x)..js em um pacote com "type": "module" é ESM; o mesmo arquivo em um pacote CJS é CommonJS. Use .mjs/.cjs para ser explícito e evitar ambiguidade.__dirname é indefinido em ESM. Em scripts ESM, você deve reconstruí-lo: const __dirname = path.dirname(fileURLToPath(import.meta.url)).\r\n) falha no Linux/macOS com "bad interpreter". Force LF via .gitattributes: *.js text eol=lf.-- em scripts npm. npm run cli --name Alice passa --name Alice para npm, não para o seu script. Use npm run cli -- --name Alice.process.argv. Os índices 0 e 1 são o binário do Node e o caminho do script - seus argumentos de usuário começam no índice 2.| Ferramenta | Pontos Fortes | Pontos Fracos |
|---|---|---|
node | Integrado, zero configuração, amplamente suportado | Sem TS, sem modo de observação antes de 18.11 |
bun | Inicialização mais rápida, empacotado, executa TS/JSX | Ecossistema mais novo, algumas lacunas de API |
deno | Seguro por padrão, TS nativo, biblioteca padrão | Resolução de módulo diferente, ecossistema menor |
tsx | Executador rápido de TS/ESM sobre Node | Dependência adicional |
pnpm exec | Executa binários locais sem instalações globais | Apenas um executor, não um runtime |
node script.js invoca explicitamente o binário do Node.js. ./script.js depende do sistema operacional para ler a linha shebang e escolher o interpretador - portanto, só funciona se o arquivo começar com #!/usr/bin/env node e tiver o bit de execução definido.
Use process.argv, que é um array começando com o binário do Node (índice 0) e o caminho do script (índice 1). Argumentos do usuário começam no índice 2. Para algo além de flags triviais, use parseArgs de node:util.
Ele mapeia um nome de comando para um arquivo de script. Quando o pacote é instalado globalmente - ou vinculado via npm link - o npm cria um link simbólico em seu diretório bin, para que você possa executar o comando de qualquer lugar.
Use a flag --watch integrada do Node (Node 18.11+): node --watch script.js. Para mais controle, combine-a com --watch-path=./src para restringir os diretórios observados.
Você deve separar as flags npm das flags do seu script com --. Por exemplo: npm run cli -- --name Alice. Sem os dois hifens, o npm consome os argumentos ele mesmo.
Quase sempre finais de linha do Windows. O shell lê a linha shebang incluindo o \r final e tenta executar /usr/bin/env node\r, que não existe. Force finais LF para arquivos de shell e script via .gitattributes.
Sim. Adicione // @ts-check no topo de um arquivo .js, crie um jsconfig.json com "checkJs": true, e anote com JSDoc. Executar tsc --noEmit exibe erros de tipo sem impacto no runtime.
Use tags JSDoc como /** @param {string} name @returns {Promise<void>} */. Editores e tsc entendem essas anotações da mesma forma que entendem tipos TypeScript.
process.env são as variáveis de ambiente em memória que o processo Node.js herdou. Um arquivo .env é apenas um arquivo de texto - o Node.js não o analisa automaticamente. Use --env-file=.env (Node 20.6+) ou uma biblioteca como dotenv.
Chame process.exit(1) após registrar o erro, ou lance um erro não capturado e deixe o Node sair com o código 1 automaticamente. Reserve códigos não zero para falhas reais para que pipelines de shell e sistemas de CI possam detectá-los.
__dirname é um global apenas para CommonJS que aponta para o diretório do script atual. Em ESM, você o reconstrói a partir de import.meta.url com fileURLToPath e path.dirname.
Somente em ESM - ou seja, um arquivo .mjs ou um arquivo em um pacote com "type": "module". Em CommonJS, você deve encapsular o código assíncrono dentro de uma IIFE async.
Revisado por Chris St. John·Última atualização: 10 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥