|
1 | 1 | exports.convert = convert;
|
2 |
| -exports.getWatcher = getWatcher; |
| 2 | +exports.dispose = dispose; |
3 | 3 |
|
| 4 | +var sassCompiler = require('./compiler'); |
4 | 5 | var spawn = require('child_process').spawn;
|
5 |
| -var fs = require('fs'); |
6 | 6 | var path = require('path');
|
7 |
| -var choki = require('chokidar'); |
8 |
| -var watcher = null; |
9 |
| -var watchPromisesChain = Promise.resolve(); |
10 | 7 |
|
11 |
| -function convert(logger, projectDir, appDir, options) { |
| 8 | +var watcherProcess = null; |
| 9 | + |
| 10 | +function convert(logger, projectDir, appDir, appResourcesDir, options) { |
12 | 11 | options = options || {};
|
13 |
| - var sassPath = getSassPath(logger); |
14 | 12 | var data = {
|
15 |
| - sassPath, |
16 | 13 | projectDir,
|
17 | 14 | appDir,
|
18 |
| - logger, |
19 |
| - options |
| 15 | + appResourcesDir, |
| 16 | + logger |
20 | 17 | };
|
21 | 18 |
|
22 | 19 | if (options.watch) {
|
23 | 20 | createWatcher(data);
|
| 21 | + return; |
24 | 22 | }
|
25 | 23 |
|
26 |
| - return spawnNodeSass(data); |
27 |
| -} |
28 |
| - |
29 |
| -function getWatcher() { |
30 |
| - return watcher; |
| 24 | + return sassCompiler.compile(data); |
31 | 25 | }
|
32 | 26 |
|
33 | 27 | function createWatcher(data) {
|
34 |
| - var appDir = data.appDir; |
35 |
| - var watcherOptions = { |
36 |
| - ignoreInitial: true, |
37 |
| - cwd: appDir, |
38 |
| - awaitWriteFinish: { |
39 |
| - pollInterval: 100, |
40 |
| - stabilityThreshold: 300 |
41 |
| - }, |
42 |
| - ignored: ['**/.*', '.*'] // hidden files |
43 |
| - }; |
| 28 | + if (watcherProcess) { |
| 29 | + return; |
| 30 | + } |
| 31 | + |
| 32 | + watcherProcess = spawn(process.execPath, [ path.join(__dirname, "./watcher.js"), JSON.stringify({appDir: data.appDir, appResourcesDir: data.appResourcesDir, projectDir: data.projectDir })], { stdio: ["ignore", "ignore", "ignore", "ipc"] }); |
44 | 33 |
|
45 |
| - watcher = choki.watch(['**/*.scss', '**/*.sass'], watcherOptions) |
46 |
| - .on('all', (event, filePath) => { |
47 |
| - watchPromisesChain = watchPromisesChain |
48 |
| - .then(() => spawnNodeSass(data)) |
49 |
| - .catch(err => { |
50 |
| - if (!err.stopExecution && err.errorAsWarning) { |
51 |
| - data.logger.warn(err.message); |
52 |
| - } else { |
53 |
| - throw err; |
54 |
| - } |
55 |
| - }); |
56 |
| - }); |
| 34 | + watcherProcess.on('error', error => { |
| 35 | + throw new Error(error); |
| 36 | + }); |
| 37 | + |
| 38 | + watcherProcess.on('message', message => { |
| 39 | + if (message && message.logLevel) { |
| 40 | + data.logger[message.logLevel](message.message); |
| 41 | + } |
| 42 | + }); |
57 | 43 | }
|
58 | 44 |
|
59 |
| -function getSassPath(logger) { |
60 |
| - var sassPath = require.resolve('node-sass/bin/node-sass'); |
61 |
| - if (fs.existsSync(sassPath)) { |
62 |
| - logger.info('Found peer node-sass'); |
63 |
| - } else { |
64 |
| - throw new Error('node-sass installation local to project was not found. Install by executing `npm install node-sass`.'); |
| 45 | +function dispose() { |
| 46 | + if (watcherProcess && watcherProcess.connected) { |
| 47 | + watcherProcess.disconnect(); |
| 48 | + watcherProcess = null; |
65 | 49 | }
|
66 |
| - |
67 |
| - return sassPath; |
68 | 50 | }
|
69 | 51 |
|
70 |
| -function spawnNodeSass(data) { |
71 |
| - return new Promise(function (resolve, reject) { |
72 |
| - var sassPath = data.sassPath, |
73 |
| - projectDir = data.projectDir, |
74 |
| - appDir = data.appDir, |
75 |
| - logger = data.logger, |
76 |
| - options = data.options; |
77 |
| - |
78 |
| - var importerPath = path.join(__dirname, "importer.js"); |
79 | 52 |
|
80 |
| - // Node SASS Command Line Args (https://github.com/sass/node-sass#command-line-interface) |
81 |
| - // --ouput : Output directory |
82 |
| - // --output-style : CSS output style (nested | expanded | compact | compresed) |
83 |
| - // -q : Supress log output except on error |
84 |
| - // --follow : Follow symlinked directories |
85 |
| - // -r : Recursively watch directories or files |
86 |
| - // --watch : Watch a directory or file |
87 |
| - var nodeArgs = [sassPath, appDir, '--output', appDir, '--output-style', 'compressed', '-q', '--follow', '--importer', importerPath]; |
88 |
| - logger.trace(process.execPath, nodeArgs.join(' ')); |
89 |
| - |
90 |
| - var env = Object.create( process.env ); |
91 |
| - env.PROJECT_DIR = projectDir; |
92 |
| - env.APP_DIR = appDir; |
93 |
| - |
94 |
| - var currentSassProcess = spawn(process.execPath, nodeArgs, { env: env }); |
95 |
| - |
96 |
| - var isResolved = false; |
97 |
| - |
98 |
| - currentSassProcess.stdout.on('data', function (data) { |
99 |
| - var stringData = data.toString(); |
100 |
| - logger.info(stringData); |
101 |
| - }); |
102 |
| - |
103 |
| - currentSassProcess.stderr.on('data', function (err) { |
104 |
| - var message = ''; |
105 |
| - var stringData = err.toString(); |
106 |
| - |
107 |
| - try { |
108 |
| - var parsed = JSON.parse(stringData); |
109 |
| - message = parsed.formatted || parsed.message || stringData; |
110 |
| - } catch (e) { |
111 |
| - message = err.toString(); |
112 |
| - } |
113 |
| - |
114 |
| - logger.info(message); |
115 |
| - }); |
116 |
| - |
117 |
| - currentSassProcess.on('error', function (err) { |
118 |
| - logger.info(err.message); |
119 |
| - if (!isResolved) { |
120 |
| - isResolved = true; |
121 |
| - err.errorAsWarning = true; |
122 |
| - err.stopExecution = false; |
123 |
| - reject(err); |
124 |
| - } |
125 |
| - }); |
126 |
| - |
127 |
| - // TODO: Consider using close event instead of exit |
128 |
| - currentSassProcess.on('exit', function (code, signal) { |
129 |
| - currentSassProcess = null; |
130 |
| - if (!isResolved) { |
131 |
| - isResolved = true; |
132 |
| - if (code === 0) { |
133 |
| - resolve(); |
134 |
| - } else { |
135 |
| - var error = new Error('SASS compiler failed with exit code ' + code); |
136 |
| - error.errorAsWarning = true; |
137 |
| - error.stopExecution = false; |
138 |
| - reject(error); |
139 |
| - } |
140 |
| - } |
141 |
| - }); |
142 |
| - }); |
143 |
| -} |
0 commit comments