Skip to content

refactor: drop Vue 2 support #5365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 0 additions & 227 deletions extensions/vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,233 +11,6 @@

This project is community-driven. If you would like to support this project, consider joining the [Insiders Program](https://github.com/vuejs/language-tools/wiki/Get-Insiders-Edition) to improve the sustainability of this project and unlock more features.

<!--

## Usage

<details>
<summary>Setup for Vue 2</summary>

1. Add `@vue/runtime-dom`

This extension requires Vue 3 types from the `@vue/runtime-dom`.

Vue 3 and Vue 2.7 has built-in JSX types. For Vue version \<= 2.6.14 you need to add JSX types by install `@vue/runtime-dom`:

```jsonc
// package.json
{
"devDependencies": {
"@vue/runtime-dom": "latest"
}
}
```

2. Remove `Vue.extend`

Template type-checking is not supported with `Vue.extend`. You can use [composition-api](https://github.com/vuejs/composition-api), [vue-class-component](https://github.com/vuejs/vue-class-component), or `export default { ... }` instead of `export default Vue.extend`.

Here is a compatibility table for different ways of writing the script blocks:

| | Component options type-checking in `<script>` | Interpolation type-checking in `<template>` | Cross-component props type-checking |
|:-----------------------------------------|:----------------------------------------------|:--------------------------------------------|:------------------------------------|
| `export default { ... }` with JS | Not supported | Not supported | Not supported |
| `export default { ... }` with TS | Not supported | Supported but deprecated | Supported but deprecated |
| `export default Vue.extend({ ... })` with JS | Not supported | Not supported | Not supported |
| `export default Vue.extend({ ... })` with TS | Limited (supports `data` types but not `props` types) | Limited | Not supported |
| `export default defineComponent({ ... })` | Supported | Supported | Supported |
| Class component | Supported | Supported with additional code ([#21](https://github.com/vuejs/language-tools/issues/21)) | Supported with [additional code](https://github.com/vuejs/language-tools/pull/750#issuecomment-1023947885) |

Note that you can use `defineComponent` even for components that are using the `Options API`.

3. Support for Vue 2 template

Volar preferentially supports Vue 3. Vue 3 and Vue 2 templates have some differences. You need to set the `target` option to support the Vue 2 templates.

```jsonc
// tsconfig.json
{
"compilerOptions": {
// ...
},
"vueCompilerOptions": {
"target": 2.7,
// "target": 2, // For Vue version <= 2.6.14
}
}
```

4. remove `.d.ts` files if they exist.

For projects generated by the [Vue CLI](https://cli.vuejs.org/), `.d.ts` files are included. Remove these files.

```
rm src/shims-tsx.d.ts src/shims-vue.d.ts
```

</details>

<details>
<summary>Define Global Components</summary>

PR: https://github.com/vuejs/vue-next/pull/3399

Local components, Built-in components, native HTML elements Type-Checking is available with no configuration.

For Global components, you need to define `GlobalComponents` interface, for example:

```typescript
// components.d.ts
declare module 'vue' { // Vue >= 2.7
// declare module '@vue/runtime-dom' { // Vue <= 2.6.14
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

export {}
```

</details>

## Notes

### Vetur

You need to disable Vetur to avoid conflicts.

Recommended use css / less / scss as `<style>` language, because these base on [vscode-css-languageservice](https://github.com/microsoft/vscode-css-languageservice) to provide reliable language support.

If use postcss / stylus / sass, you need to install additional extension for syntax highlighting. I tried these and it works, you can also choose others.

- postcss: [language-postcss](https://marketplace.visualstudio.com/items?itemName=cpylua.language-postcss).
- stylus: [language-stylus](https://marketplace.visualstudio.com/items?itemName=sysoev.language-stylus)
- sass: [Sass](https://marketplace.visualstudio.com/items?itemName=Syler.sass-indented)

Volar does not include ESLint and Prettier, but the official [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extensions support Vue, so you could install these yourself if needed.

If using Vetur's [Customizable Scaffold Snippets](https://vuejs.github.io/vetur/guide/snippet.html#customizable-scaffold-snippets), recommend use [Snippet Generator](https://marketplace.visualstudio.com/items?itemName=wenfangdu.snippet-generator) convert to VSCode Snippets. There are also snippets on the VSCode Marketplace, such as Sarah Drasner's [Vue VSCode Snippets](https://marketplace.visualstudio.com/items?itemName=sdras.vue-vscode-snippets), if you prefer ready-made snippets without customization.

If VSCode gives an error for `class` and `slot` like this:

<kbd><img width="483" src="https://user-images.githubusercontent.com/3253920/145134536-7bb090e9-9dcd-4a61-8096-3c47d6c1a699.png" /></kbd>

This is because one of the packages installed in your project uses `@types/react` which breaks some parts of Volar.

Please see the following solutions:
- https://github.com/vuejs/language-tools/discussions/592
- https://github.com/vuejs/language-tools/discussions/592#discussioncomment-1763880

### Recursive components

Volar can't typecheck recursive components out of the box due to TS limitation.
But there's a workaround, you can explicitly specify component's props like so:

`Bar.vue`

```vue
<template>
<Bar :a="'wrong'" />
</template>

<script setup lang="ts">
import { defineAsyncComponent, type DefineComponent } from 'vue'

interface Props {
a: number
}

const Bar = defineAsyncComponent<DefineComponent<Props>>(
() => import('./Bar.vue') as any
)
defineProps<Props>()
</script>
```

### Custom File Extensions

Syntax highlighting and intellisense can be applied to additional file extensions beyond just `vue`. This will need to be configured in three different places for full support.

In VS Code settings for the Volar extension add any additional extensions you need to `Additional Extensions`. Such as `ext`.

In your tsconfig.json file you will need to make sure your custom extension is included by TypeScript. If you have an include value for `./src/*.vue` then you would want to add an include for `./src/*.ext` as well.

```json
"include": [
"./src/*.ts",
"./src/*.vue",
"./src/*.ext",
]
```

Finally you need to make VS Code recognize your new extension and automatically associate it with the Vue language format. To do this you need to configure your File Associations setting to map `*.ext` to the language value `vue`. This can be done under Text Editor &gt; Files, or with the key `files.associations`.

-->

## Sponsors

<!-- <table>
<tbody>
<tr>
<td align="center" valign="middle" colspan="2">
<b>Special Sponsor</b>
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="2">
<a href="https://stackblitz.com/">
<img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/StackBlitz.svg" height="80" />
</a>
<p>Stay in the flow with instant dev experiences.<br>No more hours stashing/pulling/installing locally</p>
<p><b> — just click, and start coding.</b></p>
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="2">
<b>Platinum Sponsors</b>
</td>
</tr>
<tr>
<td align="center" valign="middle" width="50%">
<a href="https://vuejs.org/">
<img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/Vue.svg" height="80" />
</a>
<p>An approachable, performant and versatile framework for building web user interfaces.</p>
</td>
<td align="center" valign="middle" width="50%">
<a href="https://astro.build/">
<img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/Astro.svg" height="80" />
</a>
<p>Astro powers the world's fastest websites, client-side web apps, dynamic API endpoints, and everything in-between.</p>
</td>
</tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.jetbrains.com/">
<img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/JetBrains.svg" height="80" />
</a>
<p>Essential tools for software developers and teams.</p>
</td>
<td align="center" valign="middle">
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="2">
<b>Silver Sponsors</b>
</td>
</tr>
<tr>
<td align="center" valign="middle">
<a href="https://www.prefect.io/"><img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/Prefect.svg" height="50" /></a>
</td>
<td align="center" valign="middle">
<a href="https://www.techjobasia.com/"><img src="https://raw.githubusercontent.com/johnsoncodehk/sponsors/master/logos/TechJobAsia.svg" height="50" /></a>
</td>
</tr>
</tbody>
</table> -->

<p align="center">
<a href="https://cdn.jsdelivr.net/gh/johnsoncodehk/sponsors/sponsors.svg">
<img src="https://cdn.jsdelivr.net/gh/johnsoncodehk/sponsors/sponsors.png"/>
Expand Down
4 changes: 1 addition & 3 deletions packages/component-meta/lib/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as vue from '@vue/language-core';
import { posix as path } from 'path-browserify';
import type * as ts from 'typescript';
import { code as typeHelpersCode } from 'vue-component-type-helpers';
import { code as vue2TypeHelpersCode } from 'vue-component-type-helpers/vue2';

import type {
ComponentMeta,
Expand Down Expand Up @@ -236,7 +235,7 @@ interface ComponentMeta<T> {
exposed: ComponentExposed<T>;
};

${commandLine.vueOptions.target < 3 ? vue2TypeHelpersCode : typeHelpersCode}
${typeHelpersCode}
`.trim();
return code;
}
Expand Down Expand Up @@ -894,7 +893,6 @@ function readTsComponentDefaultProps(
return component;
}
// export default defineComponent({ ... })
// export default Vue.extend({ ... })
else if (ts.isCallExpression(component)) {
if (component.arguments.length) {
const arg = component.arguments[0];
Expand Down
17 changes: 0 additions & 17 deletions packages/component-type-helpers/vue2.ts

This file was deleted.

8 changes: 2 additions & 6 deletions packages/language-core/lib/codegen/globalTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { VueCompilerOptions } from '../types';
import { getSlotsPropertyName } from '../utils/shared';

export function getGlobalTypesFileName({
lib,
Expand Down Expand Up @@ -79,7 +78,7 @@ export function generateGlobalTypes({
type __VLS_FunctionalComponent<T> = (props: ${fnPropsType}, ctx?: any) => __VLS_Element & {
__ctx?: {
attrs?: any,
slots?: T extends { ${getSlotsPropertyName(target)}: infer Slots } ? Slots : Record<string, any>,
slots?: T extends { $slots: infer Slots } ? Slots : Record<string, any>,
emit?: T extends { $emit: infer Emit } ? Emit : {},
props?: ${fnPropsType},
expose?: (exposed: T) => void,
Expand Down Expand Up @@ -167,10 +166,7 @@ export function generateGlobalTypes({
function __VLS_makeOptional<T>(t: T): { [K in keyof T]?: T[K] };
function __VLS_asFunctionalComponent<T, K = T extends new (...args: any) => any ? InstanceType<T> : unknown>(t: T, instance?: K):
T extends new (...args: any) => any ? __VLS_FunctionalComponent<K>
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>${(
target === 2.7
? `: T extends import('${lib}').AsyncComponent ? (props: {}, ctx?: any) => any`
: ``)}
: T extends () => any ? (props: {}, ctx?: any) => ReturnType<T>
: T extends (...args: any) => any ? T
: __VLS_FunctionalComponent<{}>;
function __VLS_functionalComponentArgsRest<T extends (...args: any) => any>(t: T): 2 extends Parameters<T>['length'] ? [any] : [];
Expand Down
3 changes: 1 addition & 2 deletions packages/language-core/lib/codegen/localTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { VueCompilerOptions } from '../types';
import { getSlotsPropertyName } from '../utils/shared';
import { endOfLine } from './utils';

export function getLocalTypesGenerator(vueCompilerOptions: VueCompilerOptions) {
Expand Down Expand Up @@ -32,7 +31,7 @@ type __VLS_WithDefaults<P, D> = {
() => `
type __VLS_WithSlots<T, S> = T & {
new(): {
${getSlotsPropertyName(vueCompilerOptions.target)}: S;
$slots: S;
${vueCompilerOptions.jsxSlots ? `$props: ${PropsChildren.name}<S>;` : ''}
}
};
Expand Down
17 changes: 2 additions & 15 deletions packages/language-core/lib/codegen/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { Code, Sfc, VueCompilerOptions } from '../../types';
import { codeFeatures } from '../codeFeatures';
import { generateGlobalTypes, getGlobalTypesFileName } from '../globalTypes';
import type { TemplateCodegenContext } from '../template/context';
import { endOfLine, generateSfcBlockSection, newLine } from '../utils';
import { generateSfcBlockSection, newLine } from '../utils';
import { generateComponentSelf } from './componentSelf';
import { createScriptCodegenContext, type ScriptCodegenContext } from './context';
import { generateScriptSetup, generateScriptSetupImports } from './scriptSetup';
Expand Down Expand Up @@ -55,7 +55,7 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code,
yield* generateScriptSetupImports(options.sfc.scriptSetup, options.scriptSetupRanges);
}
if (options.sfc.script && options.scriptRanges) {
const { exportDefault, classBlockEnd } = options.scriptRanges;
const { exportDefault } = options.scriptRanges;
const isExportRawObject = exportDefault
&& options.sfc.script.content[exportDefault.expression.start] === '{';
if (options.sfc.scriptSetup && options.scriptSetupRanges) {
Expand Down Expand Up @@ -96,19 +96,6 @@ export function* generateScript(options: ScriptCodegenOptions): Generator<Code,
yield options.vueCompilerOptions.optionsWrapper[1];
yield generateSfcBlockSection(options.sfc.script, exportDefault.expression.end, options.sfc.script.content.length, codeFeatures.all);
}
else if (classBlockEnd !== undefined) {
if (options.vueCompilerOptions.skipTemplateCodegen) {
yield generateSfcBlockSection(options.sfc.script, 0, options.sfc.script.content.length, codeFeatures.all);
}
else {
yield generateSfcBlockSection(options.sfc.script, 0, classBlockEnd, codeFeatures.all);
yield `__VLS_template = () => {${newLine}`;
const templateCodegenCtx = yield* generateTemplate(options, ctx);
yield* generateComponentSelf(options, ctx, templateCodegenCtx);
yield `}${endOfLine}`;
yield generateSfcBlockSection(options.sfc.script, classBlockEnd, options.sfc.script.content.length, codeFeatures.all);
}
}
else {
yield generateSfcBlockSection(options.sfc.script, 0, options.sfc.script.content.length, codeFeatures.all);
yield* generateScriptSectionPartiallyEnding(options.sfc.script.name, options.sfc.script.content.length, '#3632/script.vue');
Expand Down
8 changes: 3 additions & 5 deletions packages/language-core/lib/codegen/script/scriptSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,11 +433,9 @@ function* generateComponentProps(

yield `type __VLS_BuiltInPublicProps = ${options.vueCompilerOptions.target >= 3.4
? `import('${options.vueCompilerOptions.lib}').PublicProps`
: options.vueCompilerOptions.target >= 3.0
? `import('${options.vueCompilerOptions.lib}').VNodeProps`
+ ` & import('${options.vueCompilerOptions.lib}').AllowedComponentProps`
+ ` & import('${options.vueCompilerOptions.lib}').ComponentCustomProps`
: `globalThis.JSX.IntrinsicAttributes`
: `import('${options.vueCompilerOptions.lib}').VNodeProps`
+ ` & import('${options.vueCompilerOptions.lib}').AllowedComponentProps`
+ ` & import('${options.vueCompilerOptions.lib}').ComponentCustomProps`
}`;
yield endOfLine;

Expand Down
6 changes: 2 additions & 4 deletions packages/language-core/lib/codegen/template/element.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as CompilerDOM from '@vue/compiler-dom';
import { camelize, capitalize } from '@vue/shared';
import type { Code, VueCodeInformation } from '../../types';
import { getSlotsPropertyName, hyphenateTag } from '../../utils/shared';
import { hyphenateTag } from '../../utils/shared';
import { codeFeatures } from '../codeFeatures';
import { createVBindShorthandInlayHintInfo } from '../inlayHints';
import { endOfLine, identifierRegex, newLine, normalizeAttributeValue } from '../utils';
Expand Down Expand Up @@ -143,9 +143,7 @@ export function* generateComponent(
else if (!isComponentTag) {
yield `const ${componentOriginalVar} = ({} as __VLS_WithComponent<'${getCanonicalComponentName(node.tag)}', __VLS_LocalComponents, `;
if (options.selfComponentName && possibleOriginalNames.includes(options.selfComponentName)) {
yield `typeof __VLS_self & (new () => { `
+ getSlotsPropertyName(options.vueCompilerOptions.target)
+ `: __VLS_Slots }), `;
yield `typeof __VLS_self & (new () => { $slots: __VLS_Slots }), `;
}
else {
yield `void, `;
Expand Down
Loading