Skip to content

Commit

Permalink
fix: compatibility with vue-tsc 2.x (#327)
Browse files Browse the repository at this point in the history
* fix: compatibility with vue-tsc 2.x

* Create funny-maps-give.md

* Update funny-maps-give.md

* fix: correctly load typescript plugin

* Update tsup.config.ts

* fix: vscode-uri import

* ci: bump nodejs version

* fix: bypass typescript regex validation

* chore: fix build

* refactor: move languageplugins to ts

* Update tsconfig.json

* Update languagePlugins.cts

* Update languagePlugins.cts

* Update tsup.config.ts

* Update tsup.config.ts

* Update tsup.config.ts

* Update tsup.config.ts

* Update packages/vite-plugin-checker/src/checkers/vueTsc/languagePlugins.cts

Co-authored-by: Johnson Chu <[email protected]>

* chore: organize code

* refactor: use path.dirname

* test: update test

* test: update unit test snapshot

* chore: add `@vue/language-core` to devDeps

* refactor: use js again

* fix: add allowJs

* fix:  types

* should use cjs

* docs: fix build

* fix: build and update snapshot

* ci: Windows serializer

* chore: bump vitest

* chore: should be minor change

* try remove

* replace all

---------

Co-authored-by: Johnson Chu <[email protected]>
Co-authored-by: fi3ework <[email protected]>
  • Loading branch information
3 people authored Jun 29, 2024
1 parent 0a2a2e0 commit 0747729
Show file tree
Hide file tree
Showing 50 changed files with 8,518 additions and 6,648 deletions.
5 changes: 5 additions & 0 deletions .changeset/funny-maps-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vite-plugin-checker": minor
---

fix: compatibility with vue-tsc 2.x
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
node_version: [16, 18, 20]
node_version: [18, 20]
include:
# Active LTS + other OS
- os: macos-latest
node_version: 16
node_version: 20
- os: windows-latest
node_version: 16
node_version: 20
fail-fast: false

name: 'Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}'
Expand Down
4 changes: 2 additions & 2 deletions docs/checkers/vue-tsc.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# vue-tsc (Volar)
# vue-tsc (Vue Language Tools)

You can use vue-tsc checker for your Vue3 project. If you're still using Vue2, choose [VLS](/checkers/vls) checker.

Expand All @@ -11,7 +11,7 @@ You can use vue-tsc checker for your Vue3 project. If you're still using Vue2, c
```

::: tip
The `vue-tsc` version **must** be >= `0.33.9`. `vue-tsc` has released a `1.0.0` version, it's recommended to try it out.
The `vue-tsc` version **must** be >= `2.0.0`.
:::

2. Add `vueTsc` field to plugin config.
Expand Down
1 change: 1 addition & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"private": true,
"name": "docs",
"type": "module",
"dependencies": {
"@vueuse/core": "^8.9.4",
"body-scroll-lock": "4.0.0-beta.0",
Expand Down
8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"private": true,
"version": "0.0.0",
"engines": {
"pnpm": "^7.0.0",
"pnpm": "^9.0.0",
"yarn": "forbidden, use pnpm",
"npm": "forbidden, use pnpm"
},
Expand All @@ -25,7 +25,7 @@
}
}
},
"packageManager": "pnpm@7.5.0",
"packageManager": "pnpm@9.4.0",
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "pnpm -r --filter=./packages/** --parallel run dev",
Expand Down Expand Up @@ -71,7 +71,6 @@
"@types/node": "^16.0.0",
"@types/prompts": "^2.0.13",
"@types/rimraf": "^3.0.0",
"@types/semver": "^7.3.6",
"@types/ws": "^8.5.3",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
Expand All @@ -93,15 +92,14 @@
"prompts": "^2.4.1",
"publint": "^0.1.9",
"rimraf": "^3.0.2",
"semver": "^7.5.0",
"simple-git-hooks": "^2.8.0",
"sort-deep-object-arrays": "^1.1.2",
"strip-ansi": "^7.0.0",
"tiny-invariant": "^1.1.0",
"typescript": "^5.0.4",
"vite": "^4.3.0",
"vite-plugin-checker": "workspace:*",
"vitest": "^0.30.1",
"vitest": "^1.6.0",
"ws": "^8.5.0"
}
}
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
"@vitejs/plugin-vue": "^2.0.1",
"vite": "^4.3.0",
"vue": "^3.3.4",
"vue-tsc": "^1.6.1"
"vue-tsc": "^2.0.14"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ exports[`logger > normalizeEslintDiagnostic > get multiple diagnostics 1`] = `
[
{
"checker": "ESLint",
"codeFrame": " [0m [90m 1 |[39m [36mimport[39m { text } [36mfrom[39m [32m'./text'[39m[0m
[0m [90m 2 |[39m[0m
[0m[31m[1m>[22m[39m[90m 3 |[39m [36mvar[39m hello [33m=[39m [32m'Hello'[39m[0m
[0m [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[0m
[0m [90m 4 |[39m [36mvar[39m hello1 [33m=[39m [32m'Hello1'[39m[0m
[0m [90m 5 |[39m[0m
[0m [90m 6 |[39m [36mconst[39m rootDom [33m=[39m document[33m.[39mquerySelector([32m'#root'[39m)[33m![39m[0m",
"codeFrame": " [0m [90m 1 |[39m [36mimport[39m { text } [36mfrom[39m [32m'./text'[39m
[90m 2 |[39m
[31m[1m>[22m[39m[90m 3 |[39m [36mvar[39m hello [33m=[39m [32m'Hello'[39m
[90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
[90m 4 |[39m [36mvar[39m hello1 [33m=[39m [32m'Hello1'[39m
[90m 5 |[39m
[90m 6 |[39m [36mconst[39m rootDom [33m=[39m document[33m.[39mquerySelector([32m'#root'[39m)[33m![39m[0m",
"conclusion": "",
"id": "/Users/vite-plugin-checker/playground/eslint/src/main.ts",
"level": 1,
Expand All @@ -63,13 +63,13 @@ exports[`logger > normalizeEslintDiagnostic > get multiple diagnostics 1`] = `
},
{
"checker": "ESLint",
"codeFrame": " [0m [90m 2 |[39m[0m
[0m [90m 3 |[39m [36mvar[39m hello [33m=[39m [32m'Hello'[39m[0m
[0m[31m[1m>[22m[39m[90m 4 |[39m [36mvar[39m hello1 [33m=[39m [32m'Hello1'[39m[0m
[0m [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[0m
[0m [90m 5 |[39m[0m
[0m [90m 6 |[39m [36mconst[39m rootDom [33m=[39m document[33m.[39mquerySelector([32m'#root'[39m)[33m![39m[0m
[0m [90m 7 |[39m rootDom[33m.[39minnerHTML [33m=[39m hello [33m+[39m text[0m",
"codeFrame": " [0m [90m 2 |[39m
[90m 3 |[39m [36mvar[39m hello [33m=[39m [32m'Hello'[39m
[31m[1m>[22m[39m[90m 4 |[39m [36mvar[39m hello1 [33m=[39m [32m'Hello1'[39m
[90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
[90m 5 |[39m
[90m 6 |[39m [36mconst[39m rootDom [33m=[39m document[33m.[39mquerySelector([32m'#root'[39m)[33m![39m
[90m 7 |[39m rootDom[33m.[39minnerHTML [33m=[39m hello [33m+[39m text[0m",
"conclusion": "",
"id": "/Users/vite-plugin-checker/playground/eslint/src/main.ts",
"level": 1,
Expand Down
13 changes: 6 additions & 7 deletions packages/vite-plugin-checker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@
"homepage": "https://github.com/fi3ework/vite-plugin-checker",
"dependencies": {
"@babel/code-frame": "^7.12.13",
"@volar/typescript": "^2.3.0",
"ansi-escapes": "^4.3.0",
"chalk": "^4.1.1",
"chokidar": "^3.5.1",
"commander": "^8.0.0",
"fast-glob": "^3.2.7",
"fs-extra": "^11.1.0",
"npm-run-path": "^4.0.1",
"semver": "^7.5.0",
"strip-ansi": "^6.0.0",
"tiny-invariant": "^1.1.0",
"vscode-languageclient": "^7.0.0",
Expand All @@ -64,7 +64,7 @@
"vite": ">=2.0.0",
"vls": "*",
"vti": "*",
"vue-tsc": ">=1.3.9"
"vue-tsc": ">=2.0.0"
},
"peerDependenciesMeta": {
"eslint": {
Expand Down Expand Up @@ -95,17 +95,16 @@
"devDependencies": {
"@types/eslint": "^7.2.14",
"@types/fs-extra": "^11.0.1",
"@types/semver": "^7.3.13",
"@volar/vue-typescript": "^0.33.0",
"@vue/language-core": "^2.0.14",
"esbuild": "^0.14.27",
"meow": "^9.0.0",
"npm-run-all": "^4.1.5",
"optionator": "^0.9.1",
"stylelint": "^14.0.0",
"tsup": "^6.7.0",
"typescript": "^5.0.4",
"vls": "^0.7.6",
"vti": "^0.1.7",
"vue-tsc": "^1.6.1"
"vls": "^0.8.5",
"vti": "^0.1.11",
"vue-tsc": "^2.0.14"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function parseArgsStringToArgv(value: string, env?: string, file?: string): stri

// (['"])([^\5]*?)\5 or Match "quoted text" without quotes
// `\3` and `\5` are a backreference to the quote style (' or ") captured
// @ts-expect-error Bypass typescript validation
const myRegexp = /([^\s'"]([^\s'"]*(['"])([^\3]*?)\3)+[^\s'"]*)|[^\s'"]+|(['"])([^\5]*?)\5/gi
const myString = value
const myArray: string[] = []
Expand Down
3 changes: 1 addition & 2 deletions packages/vite-plugin-checker/src/checkers/vls/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import {
StreamMessageWriter,
} from 'vscode-languageserver/node.js'
import type { URI as IURI } from 'vscode-uri'
import pkg from 'vscode-uri'
const { URI } = pkg
import { URI } from 'vscode-uri'

import {
diagnosticToTerminalLog,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const path = require('path')
const { removeEmitGlobalTypes } = require('vue-tsc')

const vueTscDir = path.dirname(require.resolve('vue-tsc/package.json'))
const vue = /** @type {typeof import('@vue/language-core')} */ (
require(require.resolve('@vue/language-core', { paths: [vueTscDir] }))
)
const windowsPathReg = /\\/g

// #region copied from https://github.com/vuejs/language-tools/blob/0781998a29f176ad52c30d3139d5c78a5688bd5d/packages/tsc/index.ts
/**
* @param {typeof import('typescript')} ts
* @param {import('typescript').CreateProgramOptions} options
*/
exports.getLanguagePlugins = (ts, options) => {
const { configFilePath } = options.options
const vueOptions =
typeof configFilePath === 'string'
? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/'))
.vueOptions
: vue.resolveVueCompilerOptions({})
const host = /** @type {import('typescript').CompilerHost} */ (options.host)
const writeFile = host.writeFile.bind(host)
host.writeFile = (fileName, contents, ...args) => {
return writeFile(fileName, removeEmitGlobalTypes(contents), ...args)
}
const vueLanguagePlugin = vue.createVueLanguagePlugin(
ts,
(id) => id,
() => '',
(fileName) => {
const fileMap = new vue.FileMap(host?.useCaseSensitiveFileNames?.() ?? false)
for (const vueFileName of options.rootNames.map((rootName) =>
rootName.replace(windowsPathReg, '/')
)) {
fileMap.set(vueFileName, undefined)
}
return fileMap.has(fileName)
},
options.options,
vueOptions
)
return [vueLanguagePlugin]
}
// #endregion
57 changes: 27 additions & 30 deletions packages/vite-plugin-checker/src/checkers/vueTsc/prepareVueTsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fsExtra from 'fs-extra'
import { createRequire } from 'module'
import path, { dirname } from 'path'
import { fileURLToPath } from 'url'
import semver from 'semver'
import { writeFile, access, readFile, rm } from 'fs/promises'

const { copy, mkdir } = fsExtra
Expand All @@ -11,7 +10,8 @@ const _require = createRequire(import.meta.url)
// isomorphic __dirname https://antfu.me/posts/isomorphic-dirname
const _filename = fileURLToPath(import.meta.url)
const _dirname = dirname(_filename)
const proxyApiPath = _require.resolve('vue-tsc/out/index')
let proxyApiPath = _require.resolve('@volar/typescript/lib/node/proxyCreateProgram')
let runExtensions = ['.vue']

export async function prepareVueTsc() {
// 1. copy typescript to folder
Expand Down Expand Up @@ -42,48 +42,45 @@ export async function prepareVueTsc() {
await writeFile(vueTscFlagFile, proxyApiPath)

// 2. sync modification of lib/tsc.js with vue-tsc
await overrideTscJs(
_require.resolve(path.resolve(targetTsDir, 'lib/typescript.js')),
currTsVersion
)
await overrideTscJs(_require.resolve(path.resolve(targetTsDir, 'lib/typescript.js')))
}

return { targetTsDir }
}

async function overrideTscJs(tscJsPath: string, version: string) {
async function overrideTscJs(tscJsPath: string) {
const languagePluginsFile = path.resolve(_dirname, 'languagePlugins.cjs')
let tsc = await readFile(tscJsPath, 'utf8')
// #region copied from https://github.com/johnsoncodehk/volar/blob/54f7186485d79bc0e9b7ec59ecbc01d681ee5310/vue-language-tools/vue-tsc/bin/vue-tsc.js
// #region copied from https://github.com/volarjs/volar.js/blob/ae7f2e01caa08f64cbc687c80841dab2a0f7c426/packages/typescript/lib/quickstart/runTsc.ts
// add *.vue files to allow extensions
tryReplace(/supportedTSExtensions = .*(?=;)/, (s: string) => s + '.concat([[".vue"]])')
tryReplace(/supportedJSExtensions = .*(?=;)/, (s: string) => s + '.concat([[".vue"]])')
tryReplace(/allSupportedExtensions = .*(?=;)/, (s: string) => s + '.concat([[".vue"]])')
const extsText = runExtensions.map((ext) => `"${ext}"`).join(', ')
tsc = replace(tsc, /supportedTSExtensions = .*(?=;)/, (s) => s + `.concat([[${extsText}]])`)
tsc = replace(tsc, /supportedJSExtensions = .*(?=;)/, (s) => s + `.concat([[${extsText}]])`)
tsc = replace(tsc, /allSupportedExtensions = .*(?=;)/, (s) => s + `.concat([[${extsText}]])`)

// proxy createProgram apis
tryReplace(
// proxy createProgram
tsc = replace(
tsc,
/function createProgram\(.+\) {/,
(s: string) =>
s + ` return require(${JSON.stringify(proxyApiPath)}).createProgram(...arguments);`
(s) =>
`var createProgram = require(${JSON.stringify(proxyApiPath)}).proxyCreateProgram(` +
[
`new Proxy({}, { get(_target, p, _receiver) { return eval(p); } } )`,
`_createProgram`,
`require(${JSON.stringify(languagePluginsFile)}).getLanguagePlugins`,
].join(', ') +
`);\n` +
s.replace('createProgram', '_createProgram')
)

// patches logic for checking root file extension in build program for incremental builds
if (semver.gt(version, '5.0.0')) {
tryReplace(
`for (const existingRoot of buildInfoVersionMap.roots) {`,
`for (const existingRoot of buildInfoVersionMap.roots
.filter(file => !file.toLowerCase().includes('__vls_'))
.map(file => file.replace(/\.vue\.(j|t)sx?$/i, '.vue'))
) {`
)
}

function tryReplace(search: any, replace: any) {
const before = tsc
tsc = tsc.replace(search, replace)
const after = tsc
function replace(_text: string, ...[search, replace]: Parameters<String['replace']>) {
const before = _text
const text = _text.replace(search, replace)
const after = text
if (after === before) {
throw 'Search string not found: ' + JSON.stringify(search.toString())
}
return after
}
// #endregion

Expand Down
1 change: 1 addition & 0 deletions packages/vite-plugin-checker/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"@tsconfig/esm/tsconfig"
],
"compilerOptions": {
"allowJs": true,
"isolatedModules": true,
"noUnusedParameters": false,
"exactOptionalPropertyTypes": false
Expand Down
27 changes: 20 additions & 7 deletions packages/vite-plugin-checker/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { defineConfig, Options } from 'tsup'
import { copyFile } from 'fs/promises'

const shared: Options = {
entry: ['src'],
entry: ['src', '!src/checkers/vueTsc/languagePlugins.cjs'],
splitting: false,
bundle: false,
sourcemap: true,
Expand All @@ -12,20 +13,32 @@ const shared: Options = {
}

export default defineConfig([
{
format: ['esm'],
outDir: 'dist/esm',
...shared,
},
{
format: ['cjs'],
outDir: 'dist/cjs',
shims: true,
outExtension({ format }) {
outExtension() {
return {
js: `.js`,
}
},
async onSuccess() {
await copyFile(
'src/checkers/vueTsc/languagePlugins.cjs',
'dist/cjs/checkers/vueTsc/languagePlugins.cjs'
)
},
...shared,
},
{
format: ['esm'],
outDir: 'dist/esm',
async onSuccess() {
await copyFile(
'src/checkers/vueTsc/languagePlugins.cjs',
'dist/esm/checkers/vueTsc/languagePlugins.cjs'
)
},
...shared,
},
])
Loading

0 comments on commit 0747729

Please sign in to comment.