Skip to content

Commit f84b615

Browse files
committed
Fix non-working Ctrl+c on windows
1 parent 1f4a9e9 commit f84b615

File tree

7 files changed

+187
-125
lines changed

7 files changed

+187
-125
lines changed

src/lib/after-watch.js

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

33
module.exports = function ($logger) {
4-
var watcher = converter.getWatcher();
5-
if (watcher) {
6-
$logger.info("Stopping nativescript-dev-sass watcher");
7-
watcher.close();
8-
}
9-
}
4+
converter.dispose();
5+
}

src/lib/before-prepare.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ module.exports = function ($logger, $projectData, $usbLiveSyncService) {
99
}
1010

1111
return converter.convert($logger, $projectData.projectDir, $projectData.appDirectoryPath);
12-
}
12+
}

src/lib/compiler.js

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
exports.compile = compile;
2+
3+
var fs = require("fs");
4+
var path = require('path');
5+
var spawn = require("child_process").spawn;
6+
var LogProvider = require('./log-provider');
7+
8+
var currentSassProcess = null;
9+
10+
function compile(data) {
11+
if (currentSassProcess) {
12+
return Promise.resolve();
13+
}
14+
15+
return new Promise((res, rej) => {
16+
var projectDir = data.projectDir,
17+
appDir = data.appDir;
18+
19+
var logger = new LogProvider(data.logger);
20+
21+
var sassPath = require.resolve('node-sass/bin/node-sass');
22+
if (fs.existsSync(sassPath)) {
23+
logger.info("Found peer node-sass");
24+
} else {
25+
throw new Error('node-sass installation local to project was not found. Install by executing `npm install node-sass`.');
26+
}
27+
28+
var isResolved = false;
29+
var resolve = () => {
30+
if (isResolved) {
31+
return;
32+
}
33+
34+
isResolved = true;
35+
res(currentSassProcess);
36+
}
37+
var reject = err => {
38+
if (isResolved) {
39+
return;
40+
}
41+
42+
isResolved = true;
43+
44+
err.errorAsWarning = true;
45+
err.stopExecution = false;
46+
47+
rej(err);
48+
}
49+
50+
// Node SASS Command Line Args (https://github.com/sass/node-sass#command-line-interface)
51+
// --ouput : Output directory
52+
// --output-style : CSS output style (nested | expanded | compact | compresed)
53+
// -q : Supress log output except on error
54+
// --follow : Follow symlinked directories
55+
// -r : Recursively watch directories or files
56+
// --watch : Watch a directory or file
57+
var nodeArgs = [sassPath, appDir, '--output', appDir, '--output-style', 'compressed', '-q', '--follow', '--importer', path.join(__dirname, "importer.js")];
58+
logger.trace(process.execPath, nodeArgs.join(' '));
59+
60+
var env = Object.create(process.env);
61+
env.PROJECT_DIR = projectDir;
62+
env.APP_DIR = appDir;
63+
64+
currentSassProcess = spawn(process.execPath, nodeArgs, { env: env });
65+
66+
currentSassProcess.stdout.on('data', data => {
67+
var stringData = data.toString();
68+
logger.info(stringData);
69+
});
70+
71+
currentSassProcess.stderr.on('data', error => {
72+
var message = '';
73+
var stringData = error.toString();
74+
75+
try {
76+
var parsed = JSON.parse(stringData);
77+
message = parsed.formatted || parsed.message || stringData;
78+
} catch (e) {
79+
message = error.toString();
80+
}
81+
82+
logger.info(message);
83+
});
84+
85+
currentSassProcess.on('error', error => {
86+
logger.info(err.message);
87+
reject(error);
88+
});
89+
90+
currentSassProcess.on('exit', (code, signal) => {
91+
if (code === 0) {
92+
resolve();
93+
} else {
94+
reject(new Error(`SASS compiler failed with exit code ${code}`));
95+
}
96+
97+
currentSassProcess = null;
98+
});
99+
});
100+
}

src/lib/converter.js

+25-117
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,51 @@
11
exports.convert = convert;
2-
exports.getWatcher = getWatcher;
2+
exports.dispose = dispose;
33

4+
var sassCompiler = require('./compiler');
45
var spawn = require('child_process').spawn;
5-
var fs = require('fs');
66
var path = require('path');
7-
var choki = require('chokidar');
8-
var watcher = null;
9-
var watchPromisesChain = Promise.resolve();
7+
8+
var watcherProcess = null;
109

1110
function convert(logger, projectDir, appDir, options) {
1211
options = options || {};
13-
var sassPath = getSassPath(logger);
1412
var data = {
15-
sassPath,
1613
projectDir,
1714
appDir,
18-
logger,
19-
options
15+
logger
2016
};
2117

2218
if (options.watch) {
2319
createWatcher(data);
20+
return;
2421
}
2522

26-
return spawnNodeSass(data);
27-
}
28-
29-
function getWatcher() {
30-
return watcher;
23+
return sassCompiler.compile(data);
3124
}
3225

3326
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-
};
27+
if (watcherProcess) {
28+
return;
29+
}
30+
31+
watcherProcess = spawn(process.execPath, [ path.join(__dirname, "./watcher.js"), JSON.stringify({appDir: data.appDir, projectDir: data.projectDir })], { stdio: ["ignore", "ignore", "ignore", "ipc"] });
4432

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-
});
33+
watcherProcess.on('error', error => {
34+
throw new Error(error);
35+
});
36+
37+
watcherProcess.on('message', message => {
38+
if (message && message.logLevel) {
39+
data.logger[message.logLevel](message.message);
40+
}
41+
});
5742
}
5843

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`.');
44+
function dispose() {
45+
if (watcherProcess) {
46+
watcherProcess.disconnect();
47+
watcherProcess = null;
6548
}
66-
67-
return sassPath;
6849
}
6950

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");
7951

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-
}

src/lib/log-provider.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const INFO_LOG_LEVEL = "info";
2+
const TRACE_LOG_LEVEL = "trace";
3+
const WARN_LOG_LEVEL = "warn";
4+
5+
module.exports = function(logger) {
6+
this.info = (message) => {
7+
this.logData({logLevel: INFO_LOG_LEVEL, message});
8+
}
9+
10+
this.trace = (message) => {
11+
this.logData({logLevel: TRACE_LOG_LEVEL, message});
12+
}
13+
14+
this.warn = (message) => {
15+
this.logData({logLevel: WARN_LOG_LEVEL, message});
16+
}
17+
18+
this.logData = (data) => {
19+
if (logger) {
20+
return logger[data.logLevel](data.message);
21+
}
22+
23+
process.send(JSON.stringify(data));
24+
}
25+
}

src/lib/watch.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ module.exports = function (logger, projectData, usbLiveSyncService, hookArgs) {
1010
}
1111

1212
return converter.convert(logger, projectData.projectDir, projectData.appDirectoryPath, { watch: true });
13-
}
13+
}

src/lib/watcher.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
var choki = require('chokidar');
2+
var path = require('path');
3+
var compiler = require('./compiler');
4+
var LogProvider = require('./log-provider');
5+
6+
var args = JSON.parse(process.argv[2]);
7+
var appDir = args.appDir;
8+
var projectDir = args.projectDir;
9+
var watchPromisesChain = Promise.resolve();
10+
11+
var watcherOptions = {
12+
ignoreInitial: true,
13+
cwd: appDir,
14+
awaitWriteFinish: {
15+
pollInterval: 100,
16+
stabilityThreshold: 300
17+
},
18+
ignored: ['**/.*', '.*', path.join(appDir, "App_Resources")] // hidden files and App_Resources folder
19+
};
20+
21+
watcher = choki.watch('**/*.s[ac]ss', watcherOptions)
22+
.on('all', (event, filePath) => {
23+
watchPromisesChain = watchPromisesChain
24+
.then(() => compiler.compile({appDir, projectDir}))
25+
.catch(err => {
26+
if (!err.stopExecution && err.errorAsWarning) {
27+
var logger = new LogProvider(null);
28+
logger.warn(err.message);
29+
} else {
30+
throw err;
31+
}
32+
});
33+
});

0 commit comments

Comments
 (0)