观察、重新编译和重启

Watch, recompile, and restart

我一直在寻找使用 Grunt 的监视模块在发生文件更改时按顺序执行几个步骤的方法的示例。我还没有找到任何一个很好的例子,所以如果有人能给我指出正确的方向,那就太好了。

  1. 构建 TypeScript 项目(我有这个工作)
  2. 监视目录中的文件更改(这也有效)
  3. 在节点进程中启动 运行 已编译的 JavaScript,同时仍在监视文件更改(通过 Grunt 执行此操作的最佳方法是什么?监视模块似乎启动了重新编译任务好的)
  4. 在文件更改时,停止其他 运行 进程,重新编译,完成后重新启动。继续观察变化(不知道这个 - 重启是棘手的部分!)

我尝试了几种不同的方法,例如使用 Grunt 启动子进程,但我总是遇到悬空进程、锁定端口、误导 STDIO 或其他问题。如果 Grunt 进程退出,我希望子进程被杀死。

请问有什么好的方法可以解决这个问题吗?谢谢!

Start running the compiled JavaScript in a node process, while still watching for file changes (what's the best way to do this via Grunt? The watch module seems to kick off the recompile task OK)

使用类似 Nodemon 的东西:https://www.npmjs.com/package/nodemon 还有 grunt / gulp 包。

On file change, stop the other running process, recompile, and restart when finished

Nodemon 将停止对 js 的更改并重新启动应用程序。

我最终不得不自己动手处理子进程。 Nodemon 将阻止 watch 发生并且不够灵活以处理重新编译步骤。

这是我的 Gruntfile,使用了 watch、copy、clean 和 TypeScript 模块。

var loader = require('load-grunt-tasks');
var cp = require('child_process');

module.exports = function (grunt) {
  loader(grunt, {});

  grunt.initConfig({
    tsFiles: [
      "**/*.ts",
      "!typings/**/*.ts",
      "typings/tsd.d.ts",
      "!build/**/*.ts",
      "!bower_modules/**/*.ts",
      "!node_modules/**/*.ts",
    ],
    buildDir: 'build/',

    clean: {
      build: '<%= buildDir %>'
    },

    ts: {
      build: {
        src: [
          "**/*.ts",
          "!typings/**/*.ts",
          "typings/tsd.d.ts",
          "!build/**/*.ts",
          "!bower_modules/**/*.ts",
          "!node_modules/**/*.ts",
        ],
        outDir: '<%= buildDir %>',
        options: {
          "target": 'ES5',
          "module": 'commonjs',
          "sourceMap": true,
        }
      }
    },

    copy: {
      build: {
        expand: true,
        cwd: './',
        src: [
          '*.json',
          'config/**/*.json',
          'test/**/*.js'
        ],
        dest: '<%= buildDir %>/',
        filter: 'isFile'
      }
    },

    watch: {
      run: {
        files: [
          '**/*.ts',
          '**/*.js',
          '**/*.json',
          '!.*/**/*.*',
          '!build/**/*.*',
          '!node_modules/**/*.*',
          '!logs/**/*.*'
        ],
        tasks: ['server-stop', 'build', 'server-restart'],
        options: {
          spawn: false
        }
      }
    }
  });

  var child = null;
  function killChild(){
    if (child){
      child.kill();
      child.disconnect();
      child = null;
    }    
  }

  grunt.registerTask('server-stop', 'Stop the dev server', function(){
    killChild();
  });

  grunt.registerTask('server-restart', 'Stop the dev server', function(){
    killChild();
    child = cp.fork('./build/app.js');
  });

  grunt.registerTask('build', ['copy', 'ts']);
  grunt.registerTask('rebuild', ['clean', 'build']);
  grunt.registerTask('default', ['rebuild']);
  grunt.registerTask('run', ['default', 'server-restart', 'watch']);
};

这是我的解决方案。我有一个 nodemon 监视 src 文件夹并在看到更改时触发构建周期 + 节点调用。使用 npm run dev:src 调用它。这是一个非常简单的解决方案:

package.json

"scripts": {
  ...
  "build:dev": "npm run clean && npm run compile:dev",
  "clean": "rimraf dist",
  "compile": "babel src -d dist && npm run copy:static",
  "compile:dev": "babel src -d dist -s && npm run copy:static",
  "copy:static": "cp -R src/static dist/static",
  "dev:dist": "npm run build:dev && node --inspect dist/server.js",
  "dev:src": "npm run build:dev && nodemon --watch src --exec npm run dev:dist",
}

编辑:

这是一种古老的技术选择。我知道这可能超出范围,但我建议采用 webpack/rollup 方法,例如:

"scripts": {
    "start": "node build/index.js",
    "build": "webpack",
    "dev": "cross-env NODE_ENV=development nodemon --watch src --watch package.* --watch .env --watch .env.development --watch .env.development.local --watch webpack.config.js --exec \"npm run build && node build/index.js\"",
    "lint": "eslint ./src --ext .js && prettier --check ./src/**/*{.js,.mjs}",
    "lint:fix": "eslint ./src --ext .js --fix && prettier --write ./src/**/*{.js,.mjs}",
  },

或强烈考虑 Kent C. Dodds 的方法:

"scripts": {
    "start": "node .",
    "build": "babel --delete-dir-on-start --out-dir dist --copy-files --ignore \"**/__tests__/**,**/__mocks__/**\" --no-copy-ignored src"
  }

https://kentcdodds.com/blog/how-i-structure-express-apps

我通过 package.json 配置的简单实现使用 nodemon 监视 src 的 ts 文件更改并使用 tsc 编译 typescript/ts 文件...

"scripts" 来自 package.json 的部分:

  "scripts": {
     "debug": "nodemon -e js,ts --watch src --exec \"yarn run build:ts && yarn run start:app\"",
     "build:ts": "node_modules/.bin/tsc",
     "start:app": "node dist/app"
  },

tsconfig.json

{
   "compilerOptions": {
     "target": "es6",
     "module": "commonjs",
     "outDir": "dist"
   },
   "include": [
     "src/**/*.ts"
   ],
   "exclude": [
     "node_modules"
   ]
}