Vue Component Bundling with a Custom Rollup Plugin
This challenge focuses on creating a custom Rollup plugin to bundle Vue components within a Vue project. Many projects benefit from custom bundling strategies, such as optimizing component sizes, pre-compiling templates, or injecting specific metadata. This exercise will guide you through building a simple plugin that transforms Vue component files (.vue) into JavaScript modules.
Problem Description
You are tasked with creating a Rollup plugin that processes .vue files and transforms them into standard JavaScript modules suitable for bundling. The plugin should:
-
Identify
.vuefiles: The plugin should recognize files ending with the.vueextension. -
Extract Component Definition: For each
.vuefile, extract the component's definition (includingscript,template, andstylesections). Assume the.vuefile structure is standard (i.e.,<script setup>,<template>,<style>). -
Generate JavaScript Module: Create a JavaScript module that exports a function. This function should return a JavaScript object representing the Vue component definition. The object should have the following structure:
{ script: string; // The content of the <script> tag template: string; // The content of the <template> tag style: string[]; // An array of strings, each representing the content of a <style> tag } -
Handle Multiple Styles: The plugin must correctly handle multiple
<style>tags within a.vuefile. -
Preserve File Path: The plugin should preserve the original file path for debugging and error reporting.
Expected Behavior:
When a .vue file is encountered during the Rollup build process, the plugin should transform it into a JavaScript module that exports the component definition as described above. The resulting module should be compatible with Vue's component loading mechanism.
Edge Cases to Consider:
- Empty
<script>,<template>, or<style>tags. .vuefiles that don't conform to the standard structure (though for simplicity, assume they do).- Files that are not
.vuefiles should be ignored.
Examples
Example 1:
Input: my-component.vue (content: `<template><div>Hello</div><style>h1 { color: blue; }</style><script>export default { data() { return { message: 'World' } } }</script>`)
Output: A JavaScript module exporting:
{
script: "export default { data() { return { message: 'World' } } }",
template: "<div>Hello</div>",
style: ["h1 { color: blue; }"]
}
Explanation: The plugin extracts the script, template, and style content and formats them into the expected JavaScript module.
Example 2:
Input: another-component.vue (content: `<template><h1>Component</h1></template><script setup></script>`)
Output: A JavaScript module exporting:
{
script: "",
template: "<h1>Component</h1>",
style: []
}
Explanation: Handles a component with only a template and a <script setup> tag (empty script content).
Example 3:
Input: component-with-multiple-styles.vue (content: `<template><div>Test</div></template><style>p { color: red; }</style><style>h2 { font-weight: bold; }</style><script>export default {}</script>`)
Output: A JavaScript module exporting:
{
script: "export default {}",
template: "<div>Test</div>",
style: ["p { color: red; }", "h2 { font-weight: bold; }"]
}
Explanation: Correctly handles multiple <style> tags, returning them as an array.
Constraints
- The plugin must be written in TypeScript.
- The plugin should be compatible with Rollup v3.
- The plugin should not introduce any external dependencies beyond those commonly available in a Node.js environment (e.g.,
fs,path). - The plugin should be reasonably performant; avoid unnecessary file I/O or complex string manipulations.
- The plugin should handle file paths correctly, ensuring they are relative to the project root.
Notes
- You'll need to use Rollup's plugin API to create the plugin. Refer to the Rollup documentation for details: https://rollupjs.org/docs/api/#plugin-api
- Consider using a library like
vue-template-compiler(though not strictly required) to parse the.vuefile content more robustly. However, for this challenge, simple string manipulation is acceptable. - Focus on the core functionality of extracting the component definition and generating the JavaScript module. Error handling and advanced features can be omitted for brevity.
- Think about how to use
this.emitFile()to output the generated JavaScript module. - Start with a simple
.vuefile and gradually increase the complexity to test your plugin.