Structuring Vue Directives for Readability and Reusability

Discover best practices for writing and organizing custom directives to enhance code clarity and reusability.

0 likes
26 views

Rule Content

{
  "title": "Structuring Vue Directives for Readability and Reusability",
  "description": "Discover best practices for writing and organizing custom directives to enhance code clarity and reusability.",
  "category": "Vue Cursor Rules",
  "rules": [
    {
      "name": "Single Responsibility Principle",
      "description": "Ensure each custom directive focuses on a single task to enhance maintainability and reusability.",
      "examples": {
        "bad": [
          {
            "code": "app.directive('validateAndStyle', {\n  bind(el, binding) {\n    // Validation logic\n    el.addEventListener('input', () => {\n      if (!isValid(el.value)) {\n        el.style.borderColor = 'red';\n      } else {\n        el.style.borderColor = 'green';\n      }\n    });\n  }\n});",
            "explanation": "Combining validation and styling responsibilities in a single directive violates the Single Responsibility Principle."
          }
        ],
        "good": [
          {
            "code": "app.directive('validate', {\n  bind(el, binding) {\n    el.addEventListener('input', () => {\n      if (!isValid(el.value)) {\n        el.setCustomValidity('Invalid input');\n      } else {\n        el.setCustomValidity('');\n      }\n    });\n  }\n});\n\napp.directive('style', {\n  bind(el, binding) {\n    // Default styling\n    el.style.borderColor = 'blue';\n  }\n});",
            "explanation": "Separating validation and styling into distinct directives adheres to the Single Responsibility Principle, making the code more modular and maintainable."
          }
        ]
      }
    },
    {
      "name": "Descriptive Naming Conventions",
      "description": "Use clear and descriptive names for custom directives to convey their purpose effectively.",
      "examples": {
        "bad": [
          {
            "code": "app.directive('myDirective', {\n  // Directive logic\n});",
            "explanation": "The name 'myDirective' is vague and does not indicate the directive's functionality."
          }
        ],
        "good": [
          {
            "code": "app.directive('tooltip', {\n  // Directive logic\n});",
            "explanation": "The name 'tooltip' clearly describes the directive's purpose, enhancing code readability."
          }
        ]
      }
    },
    {
      "name": "Utilize Lifecycle Hooks Appropriately",
      "description": "Implement appropriate lifecycle hooks to manage directive behavior effectively.",
      "examples": {
        "bad": [
          {
            "code": "app.directive('focus', {\n  bind(el) {\n    el.focus();\n  }\n});",
            "explanation": "Using only the 'bind' hook may not handle dynamic updates or cleanup properly."
          }
        ],
        "good": [
          {
            "code": "app.directive('focus', {\n  inserted(el) {\n    el.focus();\n  },\n  update(el, binding) {\n    if (binding.value) {\n      el.focus();\n    }\n  },\n  unbind(el) {\n    // Cleanup logic if necessary\n  }\n});",
            "explanation": "Utilizing 'inserted', 'update', and 'unbind' hooks ensures proper setup, dynamic updates, and cleanup of the directive."
          }
        ]
      }
    },
    {
      "name": "Avoid Hardcoding Values",
      "description": "Use binding values to create dynamic and reusable directives instead of hardcoding values.",
      "examples": {
        "bad": [
          {
            "code": "app.directive('color', {\n  bind(el) {\n    el.style.color = 'red';\n  }\n});",
            "explanation": "Hardcoding the color value limits the directive's reusability."
          }
        ],
        "good": [
          {
            "code": "app.directive('color', {\n  bind(el, binding) {\n    el.style.color = binding.value || 'black'; // Default color\n  }\n});",
            "explanation": "Using 'binding.value' allows the directive to dynamically set the color, enhancing reusability."
          }
        ]
      }
    },
    {
      "name": "Implement Cleanup Logic",
      "description": "Ensure directives include cleanup logic to prevent memory leaks and unintended behavior.",
      "examples": {
        "bad": [
          {
            "code": "app.directive('resize', {\n  bind(el) {\n    const onResize = () => {\n      // Resize logic\n    };\n    window.addEventListener('resize', onResize);\n  }\n});",
            "explanation": "Failing to remove the event listener can lead to memory leaks."
          }
        ],
        "good": [
          {
            "code": "app.directive('resize', {\n  bind(el) {\n    const onResize = () => {\n      // Resize logic\n    };\n    window.addEventListener('resize', onResize);\n    el._onResize = onResize; // Store reference for cleanup\n  },\n  unbind(el) {\n    window.removeEventListener('resize', el._onResize);\n    delete el._onResize;\n  }\n});",
            "explanation": "Implementing 'unbind' hook to remove the event listener ensures proper cleanup and prevents memory leaks."
          }
        ]
      }
    }
  ]
}