maskletter/tenp

View on GitHub
cli/lib/dev.js

Summary

Maintainability
B
5 hrs
Test Coverage

const { exec, spawn, spawnSync, fork } = require('child_process');
const notifier = require('node-notifier');
const http = require('http');
const ts = require("typescript");
const querystring = require('querystring');
const path = require('path');
const fs = require('fs');
const formatHost = {
    getCanonicalFileName: function (path) { return path; },
    getCurrentDirectory: ts.sys.getCurrentDirectory,
    getNewLine: function () { return ts.sys.newLine; }
};
const { con, extendTenpConfig, sendSystemMessage, getEnv, readJson, cwd, os, getPackConfig } = require('./tool.js');
const tsconfig = readJson(cwd, 'tsconfig.json')
const packConfig = getPackConfig();
let process_server = undefined;

const srcPath = tsconfig.compilerOptions.rootDir ? path.resolve(cwd, tsconfig.compilerOptions.rootDir) : '';
const outPath = tsconfig.compilerOptions.outDir ? path.resolve(cwd, tsconfig.compilerOptions.outDir) : '';

ts.sys.writeFile = function(fileName, data, writeByteOrderMark) {
      // If a BOM is required, emit one
      if (writeByteOrderMark) {
          data = byteOrderMarkIndicator + data;
      }
      var fd;

      data = data.replace(/require\(['"](([\s\S])*?)['"]\)/g, function(a,b,c,d){
        const rootUrl = fileName.replace(outPath,'');
        const importUrl = b.split('/');
        
        if(b[0] == '/' || b.substr(0,2) == './' || b.substr(0,3) == '../'){
            //不需要进行路径修改,忽略
            
        }else{
          //判断根目录是否存在引用的库文件夹
          const url = path.resolve(srcPath, importUrl[0]);

          if(fs.existsSync(url) || fs.existsSync(url+'.ts')  || fs.existsSync(url+'.js')){
            if(packConfig.tenp.staticRequire == true){
              if(os == 'window'){
                return `require("${path.resolve(outPath, b).split(path.sep).join('\\/')}")`
              }else{
                return `require("${path.resolve(outPath, b)}")`
              }
            }else{
              return `require(process.cwd()+"/${tsconfig.compilerOptions.outDir + '/' + b}")`
            }
          }else{
            //自动引用全局或者node_modules目录下
          }
     
        }
        return a;
      })
      try {
          fd = fs.openSync(fileName, "w");
          fs.writeSync(fd, data, /*position*/ undefined, "utf8");
      }
      finally {
          if (fd !== undefined) {
              fs.closeSync(fd);
          }
      }
}






tsWatch(function(){ 


 
  process_server && process_server.kill('SIGTERM');

  setTimeout(function(){
      let env = getEnv(packConfig.tenp.env,'dev') || {};
      if(packConfig.createUrlPath == true || process.argv.indexOf('--url') != -1){
        env.createUrlPath = true;
      }
      process_server = fork('./dist/'+packConfig.main, [], { env: env })  
  }, 0)
    
}, err => {
    const text = ts.flattenDiagnosticMessageText(err.messageText, formatHost.getNewLine());
    con.error(`  Error ${text}`)
});

/*---------------------------全局错误监听---------------------------------*/
process.on('SIGINT', function(){
  closeNode();
})
process.on('uncaughtException', function (err) {
    //打印出错误
    console.log(err);
    //打印出错误的调用栈方便调试
    console.log(err.stack); 
  closeNode();
});

/*---------------------------关闭进程---------------------------------*/
function closeNode(){
  process_server.kill();
  process.exit()
}

/*---------------------------监听ts文件---------------------------------*/
function tsWatch(process_server, error){

    let CompileError = false;
    var configPath = ts.findConfigFile(

    /*searchPath*/ "./", ts.sys.fileExists, "tsconfig.json");
    if (!configPath) {
        return console.log(' tenp error: 未发现tsconfig配置文件')
    }
    var createProgram = ts.createSemanticDiagnosticsBuilderProgram;

    var host = ts.createWatchCompilerHost(configPath, {}, ts.sys, createProgram, reportDiagnostic, reportWatchStatusChanged);
    
    var origCreateProgram = host.createProgram;

    host.createProgram = function (rootNames, options, host, oldProgram) {
        process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H')
        console.log("** 即将开始typescript文件监听! **");
        CompileError = false;
        return origCreateProgram(rootNames, options, host, oldProgram);
    };

    var origPostProgramCreate = host.afterProgramCreate;

    host.afterProgramCreate = function (program) {
        console.log("** typescript文件监听已完成! **");
        origPostProgramCreate(program);
        if(process.argv.indexOf('--build') != -1){
          process.exit();
        }else{
          process_server();
        }
        
    };
    // `createWatchProgram` creates an initial program, watches files, and updates
    // the program over time.
    ts.createWatchProgram(host);

    function reportDiagnostic(diagnostic, loaderOptions, colors, compiler, merge) {
          CompileError = true;
         let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
          if (diagnostic.file) {
            let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
              diagnostic.start
            );
           con.error(
              `  Error ${diagnostic.file.fileName} (${line + 1},${character +
                1}): ${message}`
            );
          } else {
            con.error(`  Error: ${message}`);
          }
      
        error(diagnostic)
    }
    /**
     * Prints a diagnostic every time the watch status changes.
     * This is mainly for messages like "Starting compilation" or "Compilation completed".
     */
    function reportWatchStatusChanged(diagnostic) {
        const error = ts.formatDiagnostic(diagnostic, formatHost);
        con.yellow('\r\n '+error);
        if(CompileError && packConfig.tenp.notice != false){
          sendSystemMessage('Typescript compilation error', error);
          CompileError = false;
        }
    }

}