Development Workflow
Optimize your development workflow with modern tools and practices. This is a foundational concept in programming and web interactivity that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world JavaScript experience. Take your time with each section and practice the examples
Development Environment
Set up an efficient development environment with the right tools and configurations.. This is an essential concept that every JavaScript developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
VS Code Configuration
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"emmet.includeLanguages": {
"javascript": "javascriptreact"
},
"files.associations": {
"*.js": "javascript"
}
}Git Hooks
// .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint
npm run test
// .husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx commitlint --edit "$1"CI/CD Pipeline
// .github/workflows/ci.yml
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build
run: npm run buildDocker Development
// Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
// docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
volumes:
- .:/app
environment:
- NODE_ENV=developmentMini-Project: Development CLI
// dev-cli.js
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const chokidar = require('chokidar');
class DevCLI {
constructor() {
this.projectRoot = process.cwd();
this.config = this.loadConfig();
}
loadConfig() {
const configPath = path.join(this.projectRoot, 'dev.config.json');
try {
if (fs.existsSync(configPath)) {
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
}
} catch (error) {
console.error(`Error reading dev.config.json: ${error.message}`);
}
return {
scripts: {
dev: 'npm run dev',
build: 'npm run build',
test: 'npm test',
lint: 'npm run lint'
},
watch: ['src/**/*.js'],
ignore: ['node_modules/**', 'dist/**']
};
}
start() {
console.log('🚀 Starting development environment...');
this.runScript('dev');
}
build() {
console.log('🔨 Building project...');
this.runScript('build');
}
test() {
console.log('🧪 Running tests...');
this.runScript('test');
}
lint() {
console.log('🔍 Running linter...');
this.runScript('lint');
}
watch() {
console.log('👀 Watching for changes...');
chokidar.watch(this.config.watch, {
ignored: this.config.ignore
}).on('change', (filePath) => {
console.log(`File "${filePath}" changed, rebuilding...`);
});
}
runScript(scriptName) {
const script = this.config.scripts[scriptName];
if (script) {
try {
execSync(script, { stdio: 'inherit' });
} catch (error) {
console.error(`Error running ${scriptName}: ${error.message}`);
}
} else {
console.error(`Script ${scriptName} not found`);
}
}
}
// CLI interface
const command = process.argv[2];
const cli = new DevCLI();
switch (command) {
case 'start':
cli.start();
break;
case 'build':
cli.build();
break;
case 'test':
cli.test();
break;
case 'lint':
cli.lint();
break;
case 'watch':
cli.watch();
break;
default:
console.log('Available commands: start, build, test, lint, watch');
}