vite-esbuild-typescript-checker
Version:
* Speeds up [TypeScript](https://github.com/Microsoft/TypeScript) type checking * Supports [Vue Single File Component](https://vuejs.org/v2/guide/single-file-components.html) * Displays nice error messages with the [code frame](https://babeljs.io/docs/en/
131 lines (130 loc) • 4.52 kB
JavaScript
import { Worker } from 'worker_threads';
import path, { dirname } from 'path';
import moment from 'moment';
import pc from 'picocolors';
import { IssueError } from './functions.js';
import { fileURLToPath } from 'url';
const _filename = fileURLToPath(import.meta.url);
const _dirname = dirname(_filename);
export class Helper {
changedFiles = [];
deletedFiles = [];
startTime;
worker;
options;
timeout = undefined;
socket = undefined;
constructor(workerData){
this.options = workerData;
}
workerStart(ws) {
this.socket = ws;
this.worker = new Worker(path.resolve(_dirname, 'worker.js'), {
workerData: this.options
});
this.startTime = new Date().getTime();
this.worker.on('message', (message)=>{
switch(message.type){
case 'diagnostic':
const issues = message.data;
issues.map((issue)=>{
const error = new IssueError(issue);
const file = path.isAbsolute(error.file) ? error.file : path.resolve(this.options.basedir, error.file);
console.log([
pc.red(`ERROR in ${file}`),
`${error.message}`
].join('\n'));
});
if (this.socket && issues.length) {
this.socket.send(this.getPayloadError(issues));
}
if (!this.options.watch) this.worker.postMessage({
type: 'kill'
});
break;
case 'info':
console.log(message.data);
break;
case 'debug':
const time = message.data - this.startTime;
console.log(pc.bgBlue(`[${moment().format('Y-MM-DD H:mm:ss')}] DEBUG ${time}ms.`));
console.log(pc.bgBlue(message.data));
break;
case 'done-time':
if (this.startTime) {
const time = message.data - this.startTime;
console.log(pc.green(`[${moment().format('Y-MM-DD H:mm:ss')}] Types check done in ${time}ms.`));
this.startTime = null;
}
break;
}
});
this.worker.on('error', (e)=>{
console.error(e);
process.exit(1);
});
this.worker.on('exit', (code)=>{
process.exit(code);
});
}
getFilesChange() {
return {
changedFiles: this.changedFiles,
deletedFiles: this.deletedFiles
};
}
clearFiles() {
this.changedFiles = [];
this.deletedFiles = [];
if (this.timeout) clearTimeout(this.timeout);
}
addFile = (file)=>{
if (!file.endsWith('.vue') && !file.endsWith('.ts') && !file.endsWith('.js')) return;
if (this.changedFiles.indexOf(file) === -1) {
this.changedFiles.push(file);
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(this.changeFiles.bind(this), 300);
}
};
deleteFile = (file)=>{
if (!file.endsWith('.vue') && !file.endsWith('.ts') && !file.endsWith('.js') && !file.endsWith('vite.config.ts')) return;
if (this.deletedFiles.indexOf(file) === -1) {
this.deletedFiles.push(file);
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(this.changeFiles.bind(this), 300);
}
};
async changeFiles() {
this.startTime = new Date().getTime();
this.worker.postMessage({
type: 'changeFiles',
data: this.getFilesChange()
});
this.clearFiles();
}
getPayloadError(issues) {
return {
type: 'error',
err: issueToViteError(issues[0])
};
}
}
export function issueToViteError(issue) {
let loc;
if (issue.location) {
loc = {
file: issue.file,
line: issue.location.start.line,
column: issue.location.start.column ?? 0
};
}
return {
message: issue.formatted ?? '',
stack: '',
id: issue.file,
frame: 'issue.stripedCodeFrame',
plugin: `vite-esbuild-typechecker-plugin`,
loc
};
}
export default {};