手撸ts自动编译器

        这两天刚刚开始对ts的学习,感受到了ts的魅力,但是对于ts这个指令编译我觉得过于麻烦了,即使有tsc xxx.ts -w这样的监控指令我也觉得有点麻烦,毕竟不能监控整个文件夹下的所有ts文件,由此我就想到了自己做一个ts自动编译器。

        好的,以上就是背景了,那么现在我们要开始实现了,其实这个自动编译很简单,就两步,第一步监听文件内容变化,第二步,对ts文件进行编译并生成js文件,知道了具体内容,那么接下来就是实现了,首先我们先来第一步,这里需要使用node。

const fs = require('fs');

        因为需要对文件进行监控,所以要引用fs模块,接着就是使用里面的watch方法,对文件进行监控。watch方法接受三个参数:

用法:

fs.watch( filename[, options][, listener] )

参数:此方法接受上述和以下所述的三个参数:

  • filename:它是一个字符串,Buffer或URL,表示要监视的文件或目录的名称。
  • options:它是可用于修改方法行为的字符串或对象。它是一个可选参数。它具有以下参数:
    • persistent:它是一个布尔值,用于指定只要正在监视文件,该过程是否应继续。默认值是true。
    • recursive:它是一个布尔值,用于指定是否应监视给定目录的所有子目录。默认值为false。
    • encoding:它是一个字符串,它指定用于传递给侦听器的文件名的字符编码。
  • listener:它是在访问或修改文件时调用的函数。它是一个可选参数。
    • eventType:它是一个字符串,它指定文件进行的修改的类型。
    • filename:它是一个字符串或Buffer,它指定触发事件的文件名。

        然后由于我们需要监听的是整个文件夹,所以filename可以是当前文件夹的路径。

        recursive需要设置为true。

        然后回调里需要输出本次修改的类型以及当前修改的文件名字,方便之后做处理,所以我们的代码如下:

import fs from 'fs';
fs.watch('../TS', {
    recursive: true
}, ((event, filename) => {
    console.log(`检测到文件变化.....变化类型为${event}文件名字是${filename}`);
}))

让我们看看运行后的结果:

手撸ts自动编译器_第1张图片

现在看起来是完成了,但是还是有问题,因为我们要做的是ts的编译器,所以我们应该只对ts文件进行编译,所以我们这里应该加一个分支;

import fs from 'fs';
let flag = true; //作为开关控制是否开启编译
fs.watch('../TS', {
    recursive: true
}, ((event, filename) => {
    flag = true; //手动初始化
    if (filename.endsWith('ts')) {
        flag = false;
    }
    if (flag) return //如果当前文件不是ts文件则不进行编译
    console.log(`检测到文件变化.....变化类型为${event}文件名字是${filename}`);
}))

现在我们已经完成了第一步,成功的监听到了文件的变化,接下来做第二步,对ts文件进行编译并生成js文件。

        当然这里我不会自己去写个编译器(别问,问就是不会),那不写编译器怎么办呢?我们日常是怎么编译的?是不是用指令tsc xxx.ts,那如果我们可以使用node自动运行这段指令,是不是问题就迎刃而解了。那么我们现在的问题就由编译ts文件,变成了运行ts指令,那么我们现在先来模拟一下;

import fs from 'fs';
let flag = true; //作为开关控制是否开启编译
let t = fs.watch('../TS', {
    recursive: true
}, ((event, filename) => {
    flag = true;
    if (filename.endsWith('ts')) {
        flag = false;
    }
    if (flag) return //如果当前文件不是ts文件则不进行编译
    console.log(`检测到文件变化.....变化类型为${event}文件名字是${filename}`);
    make(filename)
}))
function make(filename) { //编译方法
    console.log(filename+'文件已被编译');    
}

现在来运行一下,看看输出结果;

手撸ts自动编译器_第2张图片

触发是触发了,但是有个问题就是为什么会触发两次?这里我并不知道真正的原因,在我查询了许久之后找到了这样的一篇回答:

手撸ts自动编译器_第3张图片

翻译过来就是:

在某些情况下,您可能会注意到,单个创建事件会生成多个由组件处理的 Created 事件。例如,如果使用 FileSystemWatcher 组件监视目录中新文件的创建,然后使用记事本创建文件对其进行测试,则即使只创建了单个文件,也可能会看到生成的两个 Created 事件。这是因为记事本在写入过程中执行多个文件系统操作。记事本分批写入磁盘,创建文件内容,然后创建文件属性。其他应用程序可能以相同的方式执行。由于 FileSystemWatcher 监视操作系统活动,因此将选取这些应用程序触发的所有事件。 

 那么由此可知,第二次回调的触发是不可避免的,那我们现在要做的就是上锁,忽视掉多余的哪次调用;

import fs from 'fs';
let flag = true; //作为开关控制是否开启编译
let timeEr = null;
let t = fs.watch('../TS', {
    recursive: true
}, ((event, filename) => {
    flag = true;
    if (timeEr) {
        return
    }
    if (filename.endsWith('ts')) {
        flag = false;
    }
    if (flag) return //如果当前文件不是ts文件则不进行编译
    console.log(`检测到文件变化.....变化类型为${event}文件名字是${filename}`);
        
        timeEr = setTimeout(()=>{
            make(filename);
            timeEr = null
        },50)
}))
function make(filename) { //编译方法
    console.log(filename+'文件已被编译');    
}

运行结果为:

 那么基本的设置就完成了,现在要做的就是真的运行指令,这里我们用到的是node里的exec模块;

function make(filename) { //编译方法
    console.log(filename+'文件已被编译');    
    let order = `tsc ./${filename}`;
//第一个参数时要运行的指令 第二个时运行之后触发的回调
    exec(order, (err, stdout, stderr) => {
        if (err) {
            console.log('err',stdout);
            console.log('stderr',stderr);
            return;
        }
        console.log('编译完成');
    })
}

手撸ts自动编译器_第4张图片

但是这里我们需要对运行的指令进行一个修改,因为这这样简单的tsc会让编译后的js文件和ts文件处于同一个文件夹下,不免显得有点难看,这里我们稍微修改一下;

import fs from 'fs';
import { exec } from'child_process';
import path from 'path';
let flag = true; //作为开关控制是否开启编译
let timeEr = null;
let t = fs.watch('../TS', {
    recursive: true
}, ((event, filename) => {
    flag = true;
    if (timeEr) {
        return
    }
    if (filename.endsWith('ts')) {
        flag = false;
    }
    if (flag) return //如果当前文件不是ts文件则不进行编译
    console.log(`检测到文件变化.....变化类型为${event}文件名字是${filename}`);
    const file = path.parse(filename).name;
        timeEr = setTimeout(()=>{
            make(filename,file);
            timeEr = null
        },50)
}))
function make(filename,file) { //编译方法
    console.log(filename+'文件已被编译');    
    let order = `tsc --outFile ./dist/${file}.js ./${filename}`;
    exec(order, (err, stdout, stderr) => {
        if (err) {
            console.log('err',stdout);
            console.log('stderr',stderr);
            return;
        }
        console.log('编译完成');
        console.log('-----------------------------');
    })
}

那么到这里,一个简单的ts自动编译器就完成了。 

你可能感兴趣的:(vue.js,前端,javascript,node.js)