Hone logo
Hone
Problems

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:

  1. Extract <script setup> or <script> blocks: Identify and extract the JavaScript/TypeScript code from the script section of a Vue SFC.
  2. Transform <template> blocks: Convert the HTML template into JavaScript render functions.
  3. Extract <style> blocks: Identify and extract CSS from the style sections.
  4. 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 lang attribute 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-sfc and @vue/compiler-dom to parse and compile Vue SFCs.
  • Consider how the CSS from <style> blocks will be handled. Common approaches include generating separate .css files 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 transform hook 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!

Loading editor...
typescript