index.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. var __importDefault = (this && this.__importDefault) || function (mod) {
  22. return (mod && mod.__esModule) ? mod : { "default": mod };
  23. };
  24. Object.defineProperty(exports, "__esModule", { value: true });
  25. exports.runDev = void 0;
  26. var child_process_1 = require("child_process");
  27. var chokidar_1 = __importDefault(require("chokidar"));
  28. var fs_1 = __importDefault(require("fs"));
  29. var readline_1 = __importDefault(require("readline"));
  30. var kill = require('tree-kill');
  31. var ipc = __importStar(require("./ipc"));
  32. var resolveMain_1 = require("./resolveMain");
  33. var compiler_1 = require("./compiler");
  34. var cfg_1 = require("./cfg");
  35. var notify_1 = require("./notify");
  36. var log_1 = require("./log");
  37. var version = require('../package.json').version;
  38. var tsNodeVersion = require('ts-node').VERSION;
  39. var tsVersion = require('typescript').version;
  40. exports.runDev = function (script, scriptArgs, nodeArgs, opts) {
  41. if (typeof script !== 'string' || script.length === 0) {
  42. throw new TypeError('`script` must be a string');
  43. }
  44. if (!Array.isArray(scriptArgs)) {
  45. throw new TypeError('`scriptArgs` must be an array');
  46. }
  47. if (!Array.isArray(nodeArgs)) {
  48. throw new TypeError('`nodeArgs` must be an array');
  49. }
  50. // The child_process
  51. var child;
  52. var wrapper = resolveMain_1.resolveMain(__dirname + '/wrap.js');
  53. var main = resolveMain_1.resolveMain(script);
  54. var cfg = cfg_1.makeCfg(main, opts);
  55. var log = log_1.makeLog(cfg);
  56. var notify = notify_1.makeNotify(cfg, log);
  57. // Run ./dedupe.js as preload script
  58. if (cfg.dedupe)
  59. process.env.NODE_DEV_PRELOAD = __dirname + '/dedupe';
  60. function initWatcher() {
  61. var watcher = chokidar_1.default.watch([], {
  62. usePolling: opts.poll,
  63. interval: parseInt(opts.interval) || undefined,
  64. });
  65. watcher.on('change', restart);
  66. watcher.on('fallback', function (limit) {
  67. log.warn('node-dev ran out of file handles after watching %s files.', limit);
  68. log.warn('Falling back to polling which uses more CPU.');
  69. log.info('Run ulimit -n 10000 to increase the file descriptor limit.');
  70. if (cfg.deps)
  71. log.info('... or add `--no-deps` to use less file handles.');
  72. });
  73. return watcher;
  74. }
  75. var watcher = initWatcher();
  76. var starting = false;
  77. // Read for "rs" from command line
  78. if (opts.rs !== false) {
  79. var rl = readline_1.default.createInterface({
  80. input: process.stdin,
  81. output: process.stdout,
  82. terminal: false,
  83. });
  84. rl.on('line', function (line) {
  85. if (line.trim() === 'rs') {
  86. restart('', true);
  87. }
  88. });
  89. }
  90. log.info('ts-node-dev ver. ' +
  91. version +
  92. ' (using ts-node ver. ' +
  93. tsNodeVersion +
  94. ', typescript ver. ' +
  95. tsVersion +
  96. ')');
  97. /**
  98. * Run the wrapped script.
  99. */
  100. var compileReqWatcher;
  101. function start() {
  102. if (cfg.clear)
  103. process.stdout.write('\u001bc');
  104. for (var _i = 0, _a = (opts.watch || '').split(','); _i < _a.length; _i++) {
  105. var watched = _a[_i];
  106. if (watched)
  107. watcher.add(watched);
  108. }
  109. var cmd = nodeArgs.concat(wrapper, script, scriptArgs);
  110. var childHookPath = compiler.getChildHookPath();
  111. cmd = (opts.priorNodeArgs || []).concat(['-r', childHookPath]).concat(cmd);
  112. log.debug('Starting child process %s', cmd.join(' '));
  113. child = child_process_1.fork(cmd[0], cmd.slice(1), {
  114. cwd: process.cwd(),
  115. env: process.env,
  116. });
  117. starting = false;
  118. if (compileReqWatcher) {
  119. compileReqWatcher.close();
  120. }
  121. compileReqWatcher = chokidar_1.default.watch([], {
  122. usePolling: opts.poll,
  123. interval: parseInt(opts.interval) || undefined,
  124. });
  125. var currentCompilePath;
  126. fs_1.default.writeFileSync(compiler.getCompileReqFilePath(), '');
  127. compileReqWatcher.add(compiler.getCompileReqFilePath());
  128. compileReqWatcher.on('change', function (file) {
  129. fs_1.default.readFile(file, 'utf-8', function (err, data) {
  130. if (err) {
  131. log.error('Error reading compile request file', err);
  132. return;
  133. }
  134. var split = data.split('\n');
  135. var compile = split[0];
  136. var compiledPath = split[1];
  137. if (currentCompilePath == compiledPath)
  138. return;
  139. currentCompilePath = compiledPath;
  140. if (compiledPath) {
  141. compiler.compile({
  142. compile: compile,
  143. compiledPath: compiledPath,
  144. });
  145. }
  146. });
  147. });
  148. child.on('message', function (message) {
  149. if (!message.compiledPath ||
  150. currentCompilePath === message.compiledPath) {
  151. return;
  152. }
  153. currentCompilePath = message.compiledPath;
  154. compiler.compile(message);
  155. });
  156. child.on('exit', function (code) {
  157. log.debug('Child exited with code %s', code);
  158. if (!child)
  159. return;
  160. if (!child.respawn)
  161. process.exit(code || 0);
  162. child = undefined;
  163. });
  164. if (cfg.respawn) {
  165. child.respawn = true;
  166. }
  167. if (compiler.tsConfigPath) {
  168. watcher.add(compiler.tsConfigPath);
  169. }
  170. // Listen for `required` messages and watch the required file.
  171. ipc.on(child, 'required', function (m) {
  172. var required = m.required;
  173. var isIgnored = cfg.ignore.some(isPrefixOf(required)) ||
  174. cfg.ignore.some(isRegExpMatch(required));
  175. if (!isIgnored && (cfg.deps === -1 || getLevel(required) <= cfg.deps)) {
  176. log.debug(required, 'added to watcher');
  177. watcher.add(required);
  178. }
  179. });
  180. // Upon errors, display a notification and tell the child to exit.
  181. ipc.on(child, 'error', function (m) {
  182. log.debug('Child error');
  183. notify(m.error, m.message, 'error');
  184. stop(m.willTerminate);
  185. });
  186. compiler.writeReadyFile();
  187. }
  188. var killChild = function () {
  189. if (!child)
  190. return;
  191. log.debug('Sending SIGTERM kill to child pid', child.pid);
  192. if (opts['tree-kill']) {
  193. log.debug('Using tree-kill');
  194. kill(child.pid);
  195. }
  196. else {
  197. child.kill('SIGTERM');
  198. }
  199. };
  200. function stop(willTerminate) {
  201. if (!child || child.stopping) {
  202. return;
  203. }
  204. child.stopping = true;
  205. child.respawn = true;
  206. if (child.connected === undefined || child.connected === true) {
  207. log.debug('Disconnecting from child');
  208. child.disconnect();
  209. if (!willTerminate) {
  210. killChild();
  211. }
  212. }
  213. }
  214. function restart(file, isManualRestart) {
  215. if (file === compiler.tsConfigPath) {
  216. notify('Reinitializing TS compilation', '');
  217. compiler.init();
  218. }
  219. compiler.clearErrorCompile();
  220. if (isManualRestart === true) {
  221. notify('Restarting', 'manual restart from user');
  222. }
  223. else {
  224. notify('Restarting', file + ' has been modified');
  225. }
  226. compiler.compileChanged(file);
  227. if (starting) {
  228. log.debug('Already starting');
  229. return;
  230. }
  231. log.debug('Removing all watchers from files');
  232. //watcher.removeAll()ya
  233. watcher.close();
  234. watcher = initWatcher();
  235. starting = true;
  236. if (child) {
  237. log.debug('Child is still running, restart upon exit');
  238. child.on('exit', start);
  239. stop();
  240. }
  241. else {
  242. log.debug('Child is already stopped, probably due to a previous error');
  243. start();
  244. }
  245. }
  246. // Relay SIGTERM
  247. process.on('SIGTERM', function () {
  248. log.debug('Process got SIGTERM');
  249. killChild();
  250. process.exit(0);
  251. });
  252. var compiler = compiler_1.makeCompiler(opts, {
  253. restart: restart,
  254. log: log,
  255. });
  256. compiler.init();
  257. start();
  258. };
  259. /**
  260. * Returns the nesting-level of the given module.
  261. * Will return 0 for modules from the main package or linked modules,
  262. * a positive integer otherwise.
  263. */
  264. function getLevel(mod) {
  265. var p = getPrefix(mod);
  266. return p.split('node_modules').length - 1;
  267. }
  268. /**
  269. * Returns the path up to the last occurence of `node_modules` or an
  270. * empty string if the path does not contain a node_modules dir.
  271. */
  272. function getPrefix(mod) {
  273. var n = 'node_modules';
  274. var i = mod.lastIndexOf(n);
  275. return ~i ? mod.slice(0, i + n.length) : '';
  276. }
  277. function isPrefixOf(value) {
  278. return function (prefix) {
  279. return value.indexOf(prefix) === 0;
  280. };
  281. }
  282. function isRegExpMatch(value) {
  283. return function (regExp) {
  284. return new RegExp(regExp).test(value);
  285. };
  286. }