Hone logo
Hone
Problems

Vite Plugin for Custom Vue Component Transformation

This challenge will guide you through creating a Vite plugin that intercepts Vue Single File Components (SFCs) during the build process. Your plugin will automatically inject a specific directive into every template that meets a certain condition, demonstrating how to hook into Vite's asset processing pipeline for Vue projects.

Problem Description

You need to develop a Vite plugin written in TypeScript that targets Vue Single File Components (.vue files). This plugin should scan the template section of each SFC. If the template contains a specific HTML element (e.g., a div with a certain class, or any element with a particular attribute), your plugin should automatically inject a custom Vue directive (e.g., v-analytics) into that element. This is useful for automatically adding analytics tracking or other boilerplate to specific components without manual intervention.

Key Requirements:

  • Plugin Structure: Implement a standard Vite plugin object with name and transform hooks.
  • Vue SFC Parsing: The plugin must be able to correctly parse .vue files to access their template, script, and style blocks.
  • Template Inspection: The transform hook should identify the template block within the SFC.
  • Element Identification: Implement logic to find a specific target element within the template. For this challenge, let's target any div element that has a data-track-id attribute.
  • Directive Injection: For each identified element, inject the v-analytics directive into its opening tag.
  • Code Generation: The plugin should return the modified SFC content.
  • TypeScript Support: The plugin itself must be written in TypeScript.

Expected Behavior:

When a Vue SFC is processed by Vite, and its template contains an element like <div data-track-id="some-value">...</div>, the plugin should transform it to <div v-analytics data-track-id="some-value">...</div>.

Edge Cases:

  • SFCs without a template block should be ignored.
  • SFCs with an empty template block should be handled gracefully.
  • The directive should only be injected if the data-track-id attribute is present.
  • The plugin should not modify script or style blocks.
  • Consider how to handle self-closing tags if applicable (though for this challenge, focus on standard opening/closing tags).

Examples

Example 1:

Input Vue SFC Content:

<template>
  <div>
    <h1>Welcome</h1>
    <p>This is a sample component.</p>
    <div data-track-id="user-profile">
      User details here.
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'UserProfile'
});
</script>

<style scoped>
h1 {
  color: blue;
}
</style>

Output Vue SFC Content:

<template>
  <div>
    <h1>Welcome</h1>
    <p>This is a sample component.</p>
    <div v-analytics data-track-id="user-profile">
      User details here.
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
  name: 'UserProfile'
});
</script>

<style scoped>
h1 {
  color: blue;
}
</style>

Explanation: The plugin identified the div with data-track-id="user-profile" and injected v-analytics into its opening tag.

Example 2:

Input Vue SFC Content:

<template>
  <div>
    <button>Click me</button>
    <span data-track-id="footer-link">About Us</span>
  </div>
</template>

<script setup lang="ts">
const message = 'Hello';
</script>

Output Vue SFC Content:

<template>
  <div>
    <button>Click me</button>
    <span v-analytics data-track-id="footer-link">About Us</span>
  </div>
</template>

<script setup lang="ts">
const message = 'Hello';
</script>

Explanation: The span element with data-track-id="footer-link" was correctly modified.

Example 3:

Input Vue SFC Content:

<template>
  <div>
    <p>No tracking elements here.</p>
  </div>
</template>

<script lang="ts">
export default {
  name: 'NoTrackingComponent'
};
</script>

Output Vue SFC Content:

<template>
  <div>
    <p>No tracking elements here.</p>
  </div>
</template>

<script lang="ts">
export default {
  name: 'NoTrackingComponent'
};
</script>

Explanation: Since no div with data-track-id was found, the template remains unchanged.

Constraints

  • The plugin must be implemented using TypeScript.
  • You should use a parsing library (e.g., @vue/compiler-sfc or acorn with HTML parsing capabilities) to robustly handle SFC structure and HTML. For simplicity, vue/compiler-sfc is recommended.
  • The transformation logic for injecting the directive should be performant enough for typical project build times.
  • The plugin should only target files with the .vue extension.

Notes

  • Vite's transform hook receives the code as a string and expects a string (or an object with code and map) as a return value.
  • Consider how to leverage Abstract Syntax Tree (AST) manipulation for accurate and safe injection of the directive. Using @vue/compiler-sfc will provide AST representation of the SFC.
  • You'll need to add @vue/compiler-sfc as a development dependency to your project.
  • Think about how to correctly parse the template content and then modify the HTML string or its AST representation before returning the transformed code. The rewriteFile function from @vue/compiler-sfc can be helpful here.
  • The directive v-analytics is a placeholder; your plugin should inject this specific string.
Loading editor...
typescript