1 | var _ = require('lodash');
|
2 | var async = require('async');
|
3 | var chalk = require('chalk');
|
4 | var chokidar = require('chokidar');
|
5 | var freeport = require('freeport');
|
6 | var fs = require('fs-extra');
|
7 | var mutil = require('miaow-util');
|
8 | var path = require('path');
|
9 |
|
10 | var compile = require('./compile');
|
11 | var config = require('./config');
|
12 | var LiveReload = require('./livereload');
|
13 | var Module = require('./module');
|
14 |
|
15 | function watch(options) {
|
16 | options = config(options);
|
17 |
|
18 | compile(options, function (err, cache) {
|
19 | if (err) {
|
20 | mutil.log(chalk.red.bold('编译失败, 不能启动文件监听模式'));
|
21 |
|
22 | err.showStack = false;
|
23 | console.error(err.toString());
|
24 |
|
25 | process.exit(1);
|
26 | return;
|
27 | }
|
28 |
|
29 |
|
30 | var liveload = new LiveReload(options.liveReloadPort);
|
31 |
|
32 |
|
33 | var compileQueue = async.queue(function (srcPath, cb) {
|
34 | var modifyTime = new Date().getTime();
|
35 | mutil.log('开始编译 ' + chalk.green.underline.bold(srcPath));
|
36 | var module = new Module(srcPath, options, cache);
|
37 | module.compile(function (err) {
|
38 | if (err) {
|
39 | err.showStack = false;
|
40 | console.error(err.toString());
|
41 | return cb();
|
42 | }
|
43 |
|
44 | liveload.change(srcPath, modifyTime);
|
45 | mutil.log('成功编译 ' + chalk.green.underline.bold(srcPath));
|
46 | cb();
|
47 | });
|
48 | }, 1);
|
49 |
|
50 |
|
51 | function getDependedList(srcPath) {
|
52 | var modules = cache.modules;
|
53 | var dependedList = [];
|
54 | var searchList = [srcPath];
|
55 |
|
56 | function isDepend(module, item) {
|
57 | return _.includes(module.dependencies, item);
|
58 | }
|
59 |
|
60 | while (searchList.length) {
|
61 | var _searchList = searchList;
|
62 | searchList = [];
|
63 |
|
64 | _.each(modules, function (module, srcPath) {
|
65 | if (_.any(_searchList, isDepend.bind(this, module))) {
|
66 | dependedList.push(srcPath);
|
67 | searchList.push(srcPath);
|
68 | }
|
69 | });
|
70 | }
|
71 |
|
72 | dependedList.push(srcPath);
|
73 |
|
74 | return dependedList;
|
75 | }
|
76 |
|
77 |
|
78 | function compileChangedFile(filePath) {
|
79 | var srcPath = path.relative(options.cwd, filePath);
|
80 | var fileList = getDependedList(srcPath);
|
81 |
|
82 | _.each(fileList, function (srcPath) {
|
83 | var module = cache.get(srcPath);
|
84 |
|
85 | if (module) {
|
86 | module.remove();
|
87 | }
|
88 | });
|
89 |
|
90 | mutil.log('修改文件 ' + chalk.underline.bold(srcPath));
|
91 | compileQueue.push(fileList);
|
92 | }
|
93 |
|
94 | function compileAddedFile(filePath) {
|
95 | var srcPath = path.relative(options.cwd, filePath);
|
96 |
|
97 | mutil.log('新增文件 ' + chalk.underline.bold(srcPath));
|
98 | compileQueue.push(srcPath);
|
99 | }
|
100 |
|
101 | function compileDeletedFile(filePath) {
|
102 | var srcPath = path.relative(options.cwd, filePath);
|
103 |
|
104 | var module = cache.get(srcPath);
|
105 |
|
106 | if (module) {
|
107 | module.remove();
|
108 | }
|
109 |
|
110 | mutil.log('删除文件 ' + chalk.red.underline.bold(srcPath));
|
111 | }
|
112 |
|
113 | var watcher = chokidar.watch('**/*', {cwd: options.cwd, ignored: options.exclude || []})
|
114 | .on('ready', function () {
|
115 | mutil.log('开始监听');
|
116 |
|
117 | watcher.on('add', compileAddedFile);
|
118 | watcher.on('change', compileChangedFile);
|
119 | watcher.on('unlink', compileDeletedFile);
|
120 | });
|
121 | });
|
122 | }
|
123 |
|
124 | module.exports = function (options) {
|
125 | freeport(function (err, port) {
|
126 | if (err) {
|
127 | mutil.log(chalk.red.bold('获取端口失败, 不能启动自动刷新功能'));
|
128 | } else {
|
129 | options.liveReloadPort = port;
|
130 | }
|
131 |
|
132 | watch(options);
|
133 | });
|
134 | };
|