1 | 'use strict';
|
2 |
|
3 | const fs = require('fs');
|
4 | const pad = require('pad');
|
5 | const path = require('path');
|
6 | const chalk = require('chalk');
|
7 | const yargs = require('yargs');
|
8 | const rimraf = require('rimraf');
|
9 | const chokidar = require('chokidar');
|
10 | const pkg = require('../package.json');
|
11 | const utils = require('../utils');
|
12 | const logger = utils.logger({ name: 'dev' });
|
13 |
|
14 | const argv = yargs.argv
|
15 | const PACKAGE_ROOT = process.cwd();
|
16 |
|
17 | start();
|
18 |
|
19 | async function start() {
|
20 | logger.log(chalk.green('start'));
|
21 |
|
22 | const linkPath = checkLinkPath(argv.link);
|
23 | if (!linkPath) return logger.log(chalk.red(`Error: no --link path provided`));
|
24 |
|
25 | cleanupLinkPath({ linkPath });
|
26 |
|
27 | process.on('exit', cleanupLinkPath.bind(null, { linkPath, exit: true }));
|
28 | process.on('SIGINT', cleanupLinkPath.bind(null, { linkPath, exit: true }));
|
29 | process.on('SIGTERM', cleanupLinkPath.bind(null, { linkPath, exit: true }));
|
30 | process.on('SIGUSR1', cleanupLinkPath.bind(null, { linkPath, exit: true }));
|
31 | process.on('SIGUSR2', cleanupLinkPath.bind(null, { linkPath, exit: true }));
|
32 |
|
33 | const binaries = {};
|
34 |
|
35 | for (const binary in pkg.bin) {
|
36 | if (pkg.bin.hasOwnProperty(binary)) {
|
37 | let binPath = path.relative(PACKAGE_ROOT, pkg.bin[binary]);
|
38 | binaries[binPath] = binary;
|
39 | }
|
40 | }
|
41 |
|
42 | const targetPath = path.join(linkPath, 'node_modules', pkg.name);
|
43 | utils.ensureDirectoryExists(path.join(targetPath, 'index.js'), PACKAGE_ROOT);
|
44 |
|
45 | const linker = chokidar.watch('.', { ignored: ['./node_modules', './scripts', /(^|[/\\])\../] });
|
46 |
|
47 | linker.on('all', async (event, destPath) => {
|
48 | let relPath = path.relative(PACKAGE_ROOT, destPath);
|
49 | let copyPath = path.resolve(targetPath, relPath);
|
50 | utils.ensureDirectoryExists(relPath, copyPath);
|
51 | fs.copyFileSync(destPath, copyPath);
|
52 |
|
53 | logger.log(chalk.blue(pad('copy', 5)), chalk.white(relPath), chalk.blue('→'), chalk.magenta(copyPath));
|
54 |
|
55 | if (binaries[destPath]) {
|
56 | let binaryLinkPath = path.join(linkPath, 'node_modules', '.bin', binaries[destPath]);
|
57 | if (fs.existsSync(binaryLinkPath)) {
|
58 | fs.unlinkSync(binaryLinkPath);
|
59 | }
|
60 | fs.symlinkSync(path.relative(path.dirname(binaryLinkPath), copyPath), binaryLinkPath);
|
61 | fs.chmodSync(copyPath, '0755');
|
62 | logger.log(chalk.blue(pad('link', 5)), chalk.white(copyPath), chalk.blue('→'), chalk.magenta(binaryLinkPath));
|
63 | }
|
64 | });
|
65 |
|
66 | linker.on('ready', async () => {
|
67 | logger.log(chalk.green('ready'));
|
68 | });
|
69 | }
|
70 |
|
71 | function checkLinkPath(link) {
|
72 | if (!link) return false;
|
73 | let linkPath = path.resolve(PACKAGE_ROOT, link);
|
74 |
|
75 | if (!fs.existsSync(linkPath)) {
|
76 | logger.log(chalk.yellow(`warning: link path ${linkPath} does not exist`));
|
77 | return null;
|
78 | }
|
79 |
|
80 | let stats = fs.statSync(linkPath);
|
81 |
|
82 | if (!stats.isDirectory()) {
|
83 | logger.log(chalk.yellow(`warning: link path must be a directory, provided ${linkPath}`));
|
84 | return null;
|
85 | }
|
86 |
|
87 | return linkPath;
|
88 | }
|
89 |
|
90 | let cleaningup = false;
|
91 |
|
92 | function cleanupLinkPath({ linkPath, exit }) {
|
93 | if (exit) {
|
94 | if (cleaningup) {
|
95 | return;
|
96 | }
|
97 | cleaningup = true;
|
98 | logger.log(chalk.blue('cleanup'));
|
99 | }
|
100 |
|
101 | for (const binary in pkg.bin) {
|
102 | if (pkg.bin.hasOwnProperty(binary)) {
|
103 | let unlinkPath = path.join(linkPath, 'node_modules', '.bin', binary);
|
104 | if (fs.existsSync(unlinkPath)) {
|
105 | logger.log(chalk.blue('unlink'), chalk.gray(unlinkPath));
|
106 | fs.unlinkSync(unlinkPath);
|
107 | }
|
108 | }
|
109 | }
|
110 |
|
111 | let targetPath = path.join(linkPath, 'node_modules', pkg.name);
|
112 | if (fs.existsSync(targetPath)) {
|
113 | logger.log(chalk.blue('rmdir'), chalk.gray(targetPath));
|
114 | rimraf.sync(targetPath);
|
115 | }
|
116 |
|
117 | if (exit) {
|
118 | return process.exit();
|
119 | }
|
120 | }
|