Hone logo
Hone
Problems

Vue Component Tree Shaking

Vue's reactivity system, while powerful, can sometimes lead to larger bundle sizes if not managed carefully. This challenge focuses on a core optimization technique: tree shaking. You'll implement a simplified version of how Vue's build tools might identify and remove unused code from your components.

Problem Description

The goal is to create a mechanism that analyzes Vue component code (represented as strings in this challenge) and identifies "unused" imports. We will define "unused" as imports that are declared but never actually referenced within the component's template or script logic. This helps reduce the final bundle size by eliminating dead code.

Key Requirements:

  1. Parsing Component Code: You need to parse the provided Vue component string, separating its <script>, <template>, and <style> blocks.
  2. Identifying Imports: Within the <script> block, identify import statements (e.g., import { something } from 'vue').
  3. Detecting Usage: Analyze the <template> and <script> blocks for any references to the imported identifiers.
  4. Reporting Unused Imports: Generate a list of import identifiers that are declared but not used.

Expected Behavior:

The function should take a Vue component's code as a string and return an array of strings, where each string is the name of an unused imported identifier.

Edge Cases to Consider:

  • Components with no <script> or <template> blocks.
  • Components with multiple import statements for the same module.
  • Imported identifiers that are used only within comments.
  • Imported identifiers that are used in the <style> block (these should generally be ignored for this specific challenge, as we're focusing on template and script usage).
  • * imports (e.g., import * as utils from './utils'). For simplicity, we will consider the alias utils as used if any of its properties are accessed (e.g., utils.someMethod()). If no properties are accessed, utils is unused.
  • default imports (e.g., import MyComponent from './MyComponent'). MyComponent is considered used if it's referenced.

Examples

Example 1:

Input:
`<template>
  <div>{{ message }}</div>
</template>

<script lang="ts">
import { ref, computed } from 'vue';
import { unusedFunction } from './utils';

export default {
  setup() {
    const message = ref('Hello, Vue!');
    const doubleCount = computed(() => 10 * 2); // unused but declared
    return {
      message,
    };
  }
}
</script>

<style>
.container {
  padding: 10px;
}
</style>`

Output:
`['unusedFunction', 'doubleCount']`

Explanation:
`unusedFunction` is imported but never called or referenced in the template or script logic. `doubleCount` is defined within the `setup` function but not returned or used.

**Example 2:**

Input: `<template> <MyButton :label="buttonLabel" @click="handleClick" /> </template>

<script lang="ts"> import { defineComponent, ref } from 'vue'; import MyButton from './MyButton.vue'; import { someHelper } from './helpers'; export default defineComponent({ setup() { const buttonLabel = ref('Click Me'); const handleClick = () => { console.log('Button clicked!'); }; someHelper(); // Used return { buttonLabel, handleClick }; } }); </script>`

Output: []

Explanation: All imported identifiers (MyButton, someHelper) are referenced either directly in the template or within the script logic.

Example 3:

Input:
`<template>
  <div :class="styles.container">
    <p>{{ greeting }}</p>
  </div>
</template>

<script lang="ts">
import * as styles from './styles.css';
import { greet } from './greetings';

export default {
  setup() {
    const greeting = greet('World'); // Used
    return {
      styles, // Used as styles.container
      greeting,
    };
  }
}
</script>`

Output:
`[]`

Explanation:
`styles` is used via `styles.container`. `greet` is used by calling `greet('World')`.

## Constraints

*   The input component code will be a valid string.
*   The `<script>` block will use standard JavaScript/TypeScript syntax for imports.
*   We will only consider `import { identifier } from '...'` and `import identifier from '...'` and `import * as alias from '...'`.
*   The analysis of usage should be case-sensitive.
*   Assume that the template syntax is generally parsable for identifier references (e.g., `{{ identifier }}`, `v-bind:identifier`, `:identifier`, `v-on:identifier`, `@identifier`, `identifier(...)`).
*   We will not attempt to resolve dynamic imports or complex conditional exports.

## Notes

This challenge is a simplification of real-world tree shaking. A production-ready solution would involve Abstract Syntax Tree (AST) parsing for more robust analysis, but for this exercise, we'll rely on string manipulation and regular expressions.

Consider how you will extract the content of each block. Regular expressions can be helpful here.

Think about how to store the identified imports and then efficiently check for their presence in other parts of the code.

For identifying used identifiers, you might need to consider simple string searching, but be mindful of false positives (e.g., an identifier name appearing as a substring of another word). However, for this challenge, a basic string search within the template and script will suffice to pass the provided examples.
Loading editor...
typescript