Blank Lines Between JS Functions with Prettier and ESLint

Summary

During a recent refactor of a large-scale JavaScript codebase, our CI/CD pipeline flagged inconsistent styling patterns. Specifically, multiple function declarations were being collapsed onto a single line without a separator, creating significant readability debt and increasing the cognitive load during code reviews. While the team expected the automated formatter (Prettier/VSCode) to enforce a newline between function blocks, it failed to do so, treating them as distinct but adjacent statements.

Root Cause

The issue stems from a misunderstanding of how AST (Abstract Syntax Tree) parsers and formatters interpret statement boundaries.

  • Statement vs. Block Structure: Formatters like Prettier primarily focus on statement separation. In JavaScript, two function declarations are technically two separate statements.
  • Implicit vs. Explicit Rules: Most default formatting configurations prioritize reducing vertical whitespace unless a specific rule dictates a “gap” between certain node types.
  • The “If-Else” Exception: The reason if/else blocks behave differently is that else is a keyword that syntactically attaches to the preceding if block, creating a single Control Flow Statement. Function declarations, however, are independent entities with no structural link.

Why This Happens in Real Systems

In massive production repositories, formatting is rarely governed by “gut feeling” and is instead governed by deterministic rulesets.

  • Rule Ambiguity: Standard formatters often lack a specific rule for “maximum vertical whitespace between declarations.”
  • Parser Logic: The formatter sees FunctionDeclaration -> FunctionDeclaration. Without a rule that says if (node == FunctionDeclaration) add_newline(), the engine optimizes for density.
  • Config Drift: Different developers may have different local VSCode settings (like formatOnSave) that conflict with the project’s .prettierrc or .eslintrc, leading to “formatting wars” in Pull Requests.

Real-World Impact

  • Reduced Scannability: Engineers spend more time “parsing” code visually to find where one function ends and another begins.
  • Merge Conflict Bloat: If one developer manually adds a newline and another’s formatter removes it, every subsequent touch to that file generates unnecessary git diffs.
  • Code Review Friction: Senior engineers spend time correcting whitespace instead of reviewing logic and architectural integrity.

Example or Code

// Current problematic state
function initializeService() {
  console.log("Service started");
} function shutdownService() {
  console.log("Service stopped");
}

// Desired state after correct configuration
function initializeService() {
  console.log("Service started");
}

function shutdownService() {
  console.log("Service stopped");
}

How Senior Engineers Fix It

Senior engineers do not solve this by manually pressing “Enter.” They solve it through systemic enforcement.

  • Configuration Overhaul: Instead of fighting the formatter, we define a strict Prettier or ESLint configuration that enforces newline-per-function logic if the tool supports it.
  • Custom ESLint Rules: If the standard formatter is too opinionated, we implement a custom rule using eslint-plugin-style or a regex-based lint rule to mandate a blank line between FunctionDeclaration nodes.
  • Pre-commit Hooks: We use Husky and lint-staged to ensure that no code can be committed unless it satisfies the newline requirements, making the fix invisible to the daily workflow.

Why Juniors Miss It

  • Focus on Syntax over Semantics: Juniors often view the problem as a “VSCode glitch” rather than a parser configuration issue.
  • Manual Correction Habit: A junior will often manually add the newline, only to have the formatter strip it away seconds later, leading to frustration and wasted time.
  • Missing the “Why”: They may not realize that the if/else behavior is due to language grammar (the else belonging to the if), leading to incorrect assumptions about how the formatter views “blocks.”

Leave a Comment