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
nameandtransformhooks. - Vue SFC Parsing: The plugin must be able to correctly parse
.vuefiles to access their template, script, and style blocks. - Template Inspection: The
transformhook should identify thetemplateblock within the SFC. - Element Identification: Implement logic to find a specific target element within the template. For this challenge, let's target any
divelement that has adata-track-idattribute. - Directive Injection: For each identified element, inject the
v-analyticsdirective 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
templateblock should be ignored. - SFCs with an empty
templateblock should be handled gracefully. - The directive should only be injected if the
data-track-idattribute 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-sfcoracornwith HTML parsing capabilities) to robustly handle SFC structure and HTML. For simplicity,vue/compiler-sfcis 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
.vueextension.
Notes
- Vite's
transformhook receives the code as a string and expects a string (or an object withcodeandmap) as a return value. - Consider how to leverage Abstract Syntax Tree (AST) manipulation for accurate and safe injection of the directive. Using
@vue/compiler-sfcwill provide AST representation of the SFC. - You'll need to add
@vue/compiler-sfcas 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
rewriteFilefunction from@vue/compiler-sfccan be helpful here. - The directive
v-analyticsis a placeholder; your plugin should inject this specific string.