Skip to content

Commit

Permalink
feat(vls): run VLS in worker thread
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework committed Jun 7, 2021
1 parent 20702c8 commit 276cc41
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 34 deletions.
4 changes: 2 additions & 2 deletions examples/vue2-vls/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import ViteComponents from 'vite-plugin-components'
import Checker from 'vite-plugin-ts-checker'
import vlsChecker from 'vite-plugin-ts-checker-preset-vls'
import { serveAndBuild } from 'vite-plugin-ts-checker-preset-vls'
import { resolve } from 'path'

const config = defineConfig({
Expand All @@ -19,7 +19,7 @@ const config = defineConfig({
createVuePlugin({}),
ViteComponents({ transformer: 'vue2' }),
Checker({
checker: vlsChecker(),
checker: serveAndBuild(),
}),
],
server: {
Expand Down
82 changes: 72 additions & 10 deletions presets/vls/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,49 @@
import type { UserConfig, ViteDevServer } from 'vite'
import {
BuildCheckBin,
CheckerFactory,
CreateDiagnostic,
lspDiagnosticToViteError,
DiagnosticOfCheck,
uriToAbsPath,
CheckWorker,
ACTION_TYPES,
ConfigAction,
ConfigureServerAction,
} from 'vite-plugin-ts-checker'
import { isMainThread, parentPort, Worker, workerData } from 'worker_threads'

import { DiagnosticOptions, diagnostics, prettyLspConsole } from './commands/diagnostics'

export const createDiagnostic: CreateDiagnostic = (userOptions = {}) => {
let overlay = true // Vite defaults to true

return {
config: (config: UserConfig) => {
const hmr = config.server?.hmr
config: ({ hmr }) => {
const viteOverlay = !(typeof hmr === 'object' && hmr.overlay === false)

if (userOptions.overlay === false || !viteOverlay) {
overlay = false
}
},
async configureServer(server: ViteDevServer) {
const workDir: string = userOptions.root ?? server.config.root
async configureServer({ root }) {
const workDir: string = userOptions.root ?? root
const errorCallback: DiagnosticOptions['errorCallback'] = (diagnostics) => {
if (!diagnostics.diagnostics.length) return
const overlayErr = lspDiagnosticToViteError(diagnostics)
if (!overlayErr) return

server.ws.send({
type: 'error',
err: overlayErr,
parentPort?.postMessage({
type: 'ERROR',
payload: {
type: 'error',
err: overlayErr,
},
})
// server.ws.send({
// type: 'error',
// err: overlayErr,
// })
diagnostics.diagnostics.forEach((d) => {
prettyLspConsole({
d,
Expand All @@ -45,11 +58,60 @@ export const createDiagnostic: CreateDiagnostic = (userOptions = {}) => {
}
}

export const vlsCheckerFactory: CheckerFactory = () => {
const vlsCheckerFactory: CheckerFactory = () => {
return {
buildBin: ['vite-plugin-ts-checker-preset-vls', ['diagnostics']],
createDiagnostic: createDiagnostic,
}
}

export default vlsCheckerFactory
export const buildBin: BuildCheckBin = ['vite-plugin-ts-checker-preset-vls', ['diagnostics']]

if (isMainThread) {
// initialized in main thread
const createWorker = (userConfigs?: Record<string, never>): CheckWorker => {
const worker = new Worker(__filename, {
workerData: userConfigs,
})

// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
worker,
config: (config) => {
const configAction: ConfigAction = { type: ACTION_TYPES.config, payload: config }
worker.postMessage(configAction)
},
configureServer: (serverConfig) => {
const configureServerAction: ConfigureServerAction = {
type: ACTION_TYPES.configureServer,
payload: serverConfig,
}
worker.postMessage(configureServerAction)
},
}
}

module.exports.createWorker = createWorker
module.exports.serveAndBuild = (config: any) => ({
serve: createWorker(config),
build: buildBin,
})
} else {
// runs in worker thread
let diagnostic: DiagnosticOfCheck | null = null
if (!parentPort) throw Error('should have parentPort as file runs in worker thread')

parentPort.on('message', (action: ConfigAction | ConfigureServerAction) => {
if (action.type === ACTION_TYPES.config) {
const checker = vlsCheckerFactory()
const userConfigs = workerData
diagnostic = checker.createDiagnostic(userConfigs)
diagnostic.config(action.payload)
} else if (action.type === ACTION_TYPES.configureServer) {
if (!diagnostic) throw Error('diagnostic should be initialized in `config` hook of Vite')
diagnostic.configureServer(action.payload)
}
})
}

declare const serveAndBuild: any
export { serveAndBuild }
Empty file added presets/vls/src/typings.d.ts
Empty file.
11 changes: 4 additions & 7 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { spawn } from 'child_process'
import npmRunPath from 'npm-run-path'
import { ConfigEnv, Plugin } from 'vite'

import { BuildCheckBin, CheckWorker, OverlayErrorAction, PluginOptions } from './types'
import { ServeAndBuild, OverlayErrorAction, PluginOptions } from './types'

export * from './types'
export * from './codeFrame'
Expand All @@ -11,17 +11,14 @@ export * from './utils'
function createServeAndBuild(
checker: PluginOptions['checker'],
userOptions?: Partial<PluginOptions>
): { serve: CheckWorker; build: { buildBin: BuildCheckBin } } {
): ServeAndBuild {
if (typeof checker === 'string') {
// build in checkers
// eslint-disable-next-line @typescript-eslint/no-require-imports
const createWorker = require(`./presets/${checker}`).createWorker
// eslint-disable-next-line @typescript-eslint/no-require-imports
const buildBin = require(`./presets/${checker}`).buildBin
// const tscCheckerFactory = require(`./presets/${checker}`).checkerFactory
const { createWorker, buildBin } = require(`./presets/${checker}`)
return { serve: createWorker(userOptions), build: { buildBin } }
}

// @ts-ignore
return checker
}

Expand Down
17 changes: 10 additions & 7 deletions src/presets/tsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ import ts from 'typescript'
import { ErrorPayload } from 'vite'
import { isMainThread, parentPort, Worker, workerData } from 'worker_threads'

import {
ACTION_TYPES,
import { ACTION_TYPES } from '../types'
import { ensureCall, formatHost, tsDiagnosticToViteError } from '../utils'

import type {
CheckWorker,
ConfigAction,
ConfigureServerAction,
CreateDiagnostic,
CheckerFactory,
DiagnosticOfCheck,
BuildCheckBin,
} from '../types'
import { ensureCall, formatHost, tsDiagnosticToViteError } from '../utils'

import type { CheckerFactory, DiagnosticOfCheck, BuildCheckBin } from '../types'
/**
* Prints a diagnostic every time the watch status changes.
* This is mainly for messages like "Starting compilation" or "Compilation completed".
Expand Down Expand Up @@ -82,6 +84,7 @@ const createDiagnostic: CreateDiagnostic = (userOptions = {}) => {
err: currErr,
},
})

// server.ws.send({
// type: 'error',
// err: currErr,
Expand Down Expand Up @@ -117,8 +120,6 @@ const checkerFactory: CheckerFactory = () => {
}
}

export const buildBin: BuildCheckBin = ['tsc', ['--noEmit']]

if (isMainThread) {
// initialized in main thread
const createWorker = (userConfigs?: Record<string, never>): CheckWorker => {
Expand Down Expand Up @@ -161,3 +162,5 @@ if (isMainThread) {
}
})
}

export const buildBin: BuildCheckBin = ['tsc', ['--noEmit']]
51 changes: 46 additions & 5 deletions src/presets/vue-tsc.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,70 @@
import { CreateDiagnostic } from '../types'
import { isMainThread, parentPort, Worker, workerData } from 'worker_threads'

import type { CheckerFactory } from '../types'
import { ACTION_TYPES } from '../types'

import type {
CheckerFactory,
CheckWorker,
ConfigAction,
ConfigureServerAction,
CreateDiagnostic,
BuildCheckBin,
} from '../types'
import type { UserConfig, ViteDevServer } from 'vite'

// TODO: watch mode is note supported
/**
* Prints a diagnostic every time the watch status changes.
* This is mainly for messages like "Starting compilation" or "Compilation completed".
*
*/
// @ts-ignore
export const createDiagnostic: CreateDiagnostic = (userOptions = {}) => {
return {
config: (config: UserConfig) => {
// TODO: watch mode is note supported
//
},
configureServer(server: ViteDevServer) {
// TODO: watch mode is note supported
//
},
}
}

export const buildBin: BuildCheckBin = ['vue-tsc', ['--noEmit']]

export const checkerFactory: CheckerFactory = () => {
return {
buildBin: ['vue-tsc', ['--noEmit']],
createDiagnostic: createDiagnostic,
}
}

export type VueTscCheckerOptions = Record<string, never>
// TODO: watch mode is note supported
// Nothing will happened, just satisfy type check
if (isMainThread) {
// initialized in main thread
const createWorker = (userConfigs?: Record<string, never>): CheckWorker => {
const worker = new Worker(__filename, {
workerData: userConfigs,
})

return {
worker,
config: (config) => {
const configAction: ConfigAction = { type: ACTION_TYPES.config, payload: config }
worker.postMessage(configAction)
},
configureServer: (serverConfig) => {
const configureServerAction: ConfigureServerAction = {
type: ACTION_TYPES.configureServer,
payload: serverConfig,
}
worker.postMessage(configureServerAction)
},
}
}

module.exports.createWorker = createWorker
} else {
//
}
11 changes: 8 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import type { HMRPayload, ServerOptions, ConfigEnv } from 'vite'
import type { Worker } from 'worker_threads'

export type CheckerFactory = (options?: unknown) => Checker
export type CheckerFactory = (options?: unknown) => ServeChecker

export type BuildCheckBin = [string, ReadonlyArray<string>]

export interface Checker {
export interface ServeAndBuild {
serve: CheckWorker
build: { buildBin: BuildCheckBin }
}

export interface ServeChecker {
createDiagnostic: CreateDiagnostic
}

Expand Down Expand Up @@ -61,7 +66,7 @@ export interface PluginOptions {
* Use `"tsc"` or `"vue-tsc"` or an custom checker
* @defaultValue `"tcs"`
*/
checker: 'tsc' | 'vue-tsc' | Checker
checker: 'tsc' | 'vue-tsc' | ServeAndBuild
/**
* Enable checking in build mode
* @defaultValue `true`
Expand Down

0 comments on commit 276cc41

Please sign in to comment.