Skip to content

Commit 52b2bb2

Browse files
author
Fatme
authored
Merge pull request #71 from NativeScript/fatme/choki
Fix node-sass watcher
2 parents d6da8d3 + e318082 commit 52b2bb2

File tree

3 files changed

+125
-88
lines changed

3 files changed

+125
-88
lines changed

src/lib/after-watch.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
var converter = require('./converter');
22

33
module.exports = function ($logger) {
4-
var sass = converter.getSassProcess();
5-
if (sass) {
6-
$logger.info("Stopping sass watch");
7-
sass.kill("SIGINT")
4+
var watcher = converter.getWatcher();
5+
if (watcher) {
6+
$logger.info("Stopping nativescript-dev-sass watcher");
7+
watcher.close();
88
}
99
}

src/lib/converter.js

+120-84
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,130 @@
11
exports.convert = convert;
2-
exports.getSassProcess = getSassProcess;
2+
exports.getWatcher = getWatcher;
33

44
var spawn = require('child_process').spawn;
55
var fs = require('fs');
66
var path = require('path');
7-
var currentSassProcess = null;
7+
var choki = require('chokidar');
8+
var watcher = null;
9+
var watchPromisesChain = Promise.resolve();
810

911
function convert(logger, projectDir, appDir, options) {
10-
return new Promise(function (resolve, reject) {
11-
options = options || {};
12-
var sassPath = require.resolve('node-sass/bin/node-sass');
13-
var importerPath = path.join(__dirname, "importer.js");
14-
15-
if (fs.existsSync(sassPath)) {
16-
try {
17-
logger.info('Found peer node-sass');
18-
} catch (err) { }
19-
} else {
20-
throw Error('node-sass installation local to project was not found. Install by executing `npm install node-sass`.');
21-
}
22-
23-
// Node SASS Command Line Args (https://github.com/sass/node-sass#command-line-interface)
24-
// --ouput : Output directory
25-
// --output-style : CSS output style (nested | expanded | compact | compresed)
26-
// -q : Supress log output except on error
27-
// --follow : Follow symlinked directories
28-
// -r : Recursively watch directories or files
29-
// --watch : Watch a directory or file
30-
var nodeArgs = [sassPath, appDir, '--output', appDir, '--output-style', 'compressed', '-q', '--follow', '--importer', importerPath];
31-
if (options.watch) {
32-
nodeArgs.push('-r', '--watch');
33-
}
34-
35-
logger.trace(process.execPath, nodeArgs.join(' '));
36-
var env = Object.create( process.env );
37-
env.PROJECT_DIR = projectDir;
38-
env.APP_DIR = appDir;
39-
currentSassProcess = spawn(process.execPath, nodeArgs, { env: env });
40-
41-
var isResolved = false;
42-
var watchResolveTimeout;
43-
currentSassProcess.stdout.on('data', function (data) {
44-
var stringData = data.toString();
45-
logger.info(stringData);
46-
});
47-
48-
currentSassProcess.stderr.on('data', function (err) {
49-
var message = '';
50-
var stringData = err.toString();
51-
52-
try {
53-
var parsed = JSON.parse(stringData);
54-
message = parsed.formatted || parsed.message || stringData;
55-
} catch (e) {
56-
renderMsg = true;
57-
message = err.toString();
58-
}
59-
60-
logger.info(message);
61-
});
62-
63-
currentSassProcess.on('error', function (err) {
64-
logger.info(err.message);
65-
if (!isResolved) {
66-
isResolved = true;
67-
reject(err);
68-
}
69-
});
70-
71-
// TODO: Consider using close event instead of exit
72-
currentSassProcess.on('exit', function (code, signal) {
73-
currentSassProcess = null;
74-
if (!isResolved) {
75-
isResolved = true;
76-
if (code === 0) {
77-
resolve();
78-
} else {
79-
reject(Error('SASS compiler failed with exit code ' + code));
80-
}
81-
}
82-
});
83-
84-
// SASS does not recompile on watch, so directly resolve.
85-
if (options.watch && !isResolved) {
86-
isResolved = true;
87-
resolve();
88-
}
89-
});
12+
options = options || {};
13+
var sassPath = getSassPath(logger);
14+
var data = {
15+
sassPath,
16+
projectDir,
17+
appDir,
18+
logger,
19+
options
20+
};
21+
22+
if (options.watch) {
23+
createWatcher(data);
24+
}
25+
26+
return spawnNodeSass(data);
27+
}
28+
29+
function getWatcher() {
30+
return watcher;
31+
}
32+
33+
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+
};
44+
45+
watcher = choki.watch(['**/*.scss', '**/*.sass'], watcherOptions)
46+
.on('all', (event, filePath) => {
47+
watchPromisesChain = watchPromisesChain.then(() => spawnNodeSass(data));
48+
});
9049
}
9150

92-
function getSassProcess() {
93-
return currentSassProcess;
51+
function getSassPath(logger) {
52+
var sassPath = require.resolve('node-sass/bin/node-sass');
53+
if (fs.existsSync(sassPath)) {
54+
logger.info('Found peer node-sass');
55+
} else {
56+
throw new Error('node-sass installation local to project was not found. Install by executing `npm install node-sass`.');
57+
}
58+
59+
return sassPath;
60+
}
61+
62+
function spawnNodeSass(data) {
63+
return new Promise(function (resolve, reject) {
64+
var sassPath = data.sassPath,
65+
projectDir = data.projectDir,
66+
appDir = data.appDir,
67+
logger = data.logger,
68+
options = data.options;
69+
70+
var importerPath = path.join(__dirname, "importer.js");
71+
72+
// Node SASS Command Line Args (https://github.com/sass/node-sass#command-line-interface)
73+
// --ouput : Output directory
74+
// --output-style : CSS output style (nested | expanded | compact | compresed)
75+
// -q : Supress log output except on error
76+
// --follow : Follow symlinked directories
77+
// -r : Recursively watch directories or files
78+
// --watch : Watch a directory or file
79+
var nodeArgs = [sassPath, appDir, '--output', appDir, '--output-style', 'compressed', '-q', '--follow', '--importer', importerPath];
80+
logger.trace(process.execPath, nodeArgs.join(' '));
81+
82+
var env = Object.create( process.env );
83+
env.PROJECT_DIR = projectDir;
84+
env.APP_DIR = appDir;
85+
86+
var currentSassProcess = spawn(process.execPath, nodeArgs, { env: env });
87+
88+
var isResolved = false;
89+
90+
currentSassProcess.stdout.on('data', function (data) {
91+
var stringData = data.toString();
92+
logger.info(stringData);
93+
});
94+
95+
currentSassProcess.stderr.on('data', function (err) {
96+
var message = '';
97+
var stringData = err.toString();
98+
99+
try {
100+
var parsed = JSON.parse(stringData);
101+
message = parsed.formatted || parsed.message || stringData;
102+
} catch (e) {
103+
message = err.toString();
104+
}
105+
106+
logger.info(message);
107+
});
108+
109+
currentSassProcess.on('error', function (err) {
110+
logger.info(err.message);
111+
if (!isResolved) {
112+
isResolved = true;
113+
reject(err);
114+
}
115+
});
116+
117+
// TODO: Consider using close event instead of exit
118+
currentSassProcess.on('exit', function (code, signal) {
119+
currentSassProcess = null;
120+
if (!isResolved) {
121+
isResolved = true;
122+
if (code === 0) {
123+
resolve();
124+
} else {
125+
reject(new Error('SASS compiler failed with exit code ' + code));
126+
}
127+
}
128+
});
129+
});
94130
}

src/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
},
6464
"dependencies": {
6565
"bluebird": "^3.4.6",
66+
"chokidar": "2.0.2",
6667
"node-sass": "^4.7.1",
6768
"glob": "^7.1.2",
6869
"nativescript-hook": "^0.2.0"

0 commit comments

Comments
 (0)