Vue Component Rollup Plugin
This challenge asks you to create a custom Rollup plugin that optimizes Vue Single File Components (SFCs) during the build process. This is crucial for improving build performance and output bundle size for Vue projects.
Problem Description
You need to develop a Rollup plugin that processes .vue files. This plugin should:
- Extract
<script setup>or<script>blocks: Identify and extract the JavaScript/TypeScript code from the script section of a Vue SFC. - Transform
<template>blocks: Convert the HTML template into JavaScript render functions. - Extract
<style>blocks: Identify and extract CSS from the style sections. - Combine and Output: The plugin should output JavaScript code that can be imported and used as a Vue component, along with handling CSS imports or injection.
Key Requirements:
- The plugin must integrate seamlessly with Rollup.
- It should support both
<script setup>and the traditional<script>block syntax. - It needs to handle different CSS preprocessors (e.g., SCSS, Less) if they are specified via the
langattribute on the<style>tag. - The output JavaScript should be compatible with standard Vue compilation targets.
- The plugin should be written in TypeScript.
Expected Behavior:
When Rollup encounters a .vue file, your plugin should intercept it, process its different blocks, and return a JavaScript module that exports a compiled Vue component definition.
Edge Cases:
- SFCs with no
<script>block (functional components). - SFCs with no
<template>block (e.g., for utility components). - Multiple
<style>blocks (e.g., for different scopes or media queries). - CSS within
<style>blocks that uses specific preprocessor syntax (e.g.,lang="scss"). - SFCs with attributes on blocks (e.g.,
<script lang="ts">,<style scoped>).
Examples
Example 1:
Input:
MyComponent.vue
<template>
<div class="greeting">{{ message }}</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const message = ref('Hello from Vue!');
</script>
<style scoped>
.greeting {
color: blue;
}
</style>
Output (Conceptual JavaScript Module - actual output might differ in AST representation):
// This is a conceptual representation of the transformed JavaScript output.
// The actual output will be generated by Vue's compiler and your plugin.
import { defineComponent, ref } from 'vue';
import './MyComponent.vue.css'; // Or injected via style-loader equivalent
export default defineComponent({
setup() {
const message = ref('Hello from Vue!');
return { message };
},
render() {
return h(
'div',
{ class: 'greeting' },
this.message
);
}
});
Explanation:
The <template> is transformed into a render function. The <script setup> logic is translated into a setup function. The <style> block is handled to ensure its CSS is applied (likely via a separate process or an import).
Example 2:
Input:
AnotherComponent.vue
<template>
<button @click="count++">{{ count }}</button>
</template>
<script>
export default {
data() {
return {
count: 0
};
}
};
</script>
Output (Conceptual JavaScript Module):
import { defineComponent } from 'vue';
// CSS would be handled separately
export default defineComponent({
data() {
return {
count: 0
};
},
render() {
// simplified render logic for illustration
return h(
'button',
{ onClick: () => this.count++ },
this.count
);
}
});
Explanation:
This example demonstrates handling a traditional <script> block with export default and data properties. The template is compiled into a render function.
Constraints
- The plugin should be written in TypeScript.
- It must adhere to the Rollup plugin interface (e.g.,
name,transform). - The solution should aim for efficiency, as this plugin will run during the build process.
- It should leverage existing Vue compilation tools/libraries (e.g.,
@vue/compiler-sfc) where appropriate.
Notes
- You will likely need to use
@vue/compiler-sfcand@vue/compiler-domto parse and compile Vue SFCs. - Consider how the CSS from
<style>blocks will be handled. Common approaches include generating separate.cssfiles and importing them, or using a mechanism to inject styles directly. For this challenge, focus on extracting and preparing the CSS content. - Think about how to maintain source maps for better debugging.
- The output of your
transformhook should be a JavaScript module.
This challenge is designed to give you hands-on experience with the inner workings of build tools and how to customize them for specific frameworks like Vue. Good luck!