Skip to content

add watch capability #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/before-prepare.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
var converter = require('./converter');

module.exports = function ($logger, $projectData, $usbLiveSyncService) {
var liveSync = $usbLiveSyncService.isInitialized;
var bundle = $projectData.$options.bundle;
if (liveSync || bundle) {
return;
}

return converter.convert($logger, $projectData.projectDir);
}
139 changes: 64 additions & 75 deletions lib/converter.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,77 @@
exports.convert = convert;

var spawn = require('child_process').spawn;
var fs = require('fs');
var path = require('path');
var sass = require('node-sass');
var glob = require('glob');


function convert(logger, projectDir, options) {
return new Promise(function (resolve, reject) {
options = options || {};

var sassFilesPath = path.join(projectDir, 'app/**/*.scss');
var sassImportPaths = [
path.join(projectDir, 'app/'),
path.join(projectDir, 'node_modules/')
];
//console.log("SASS Import Path", sassImportPaths);

var sassFiles = glob.sync(sassFilesPath, { follow: true }).filter(function(filePath){
var path = filePath;
var parts = path.split('/');
var filename = parts[parts.length - 1];
return path.indexOf("App_Resources") === -1 && filename.indexOf("_") !== 0;
});

if(sassFiles.length === 0){
//No sass files in project; skip parsing
resolve();
} else {
var i = 0;
var loopSassFilesAsync = function(sassFiles){
parseSass(sassFiles[i], sassImportPaths, function(e){
if(e !== undefined){
//Error in the LESS parser; Reject promise
reject(Error(sassFiles[i] + ' SASS CSS pre-processing failed. Error: ' + e));
}

i++; //Increment loop counter

if(i < sassFiles.length){
loopSassFilesAsync(sassFiles);
} else {
//All files have been processed; Resolve promise
resolve();
}
return new Promise(function (resolve, reject) {
options = options || {};

var peerSassPath = path.join(__dirname, '../../node-sass');
var sassPath = path.join(peerSassPath, 'bin/node-sass');
var appDir = path.join(projectDir, "app");

if (fs.existsSync(sassPath)) {
try {
logger.info('Found peer node-sass');
} catch (err) { }
} else {
throw Error('node-sass installation local to project was not found. Install by executing `npm install node-sass`.');
}

var nodeArgs = [sassPath, appDir, '--output', appDir, '--output-style', 'compressed'];
if (options.watch) {
nodeArgs.push('-r', '--watch');
}

logger.trace(process.execPath, nodeArgs.join(' '));
var sass = spawn(process.execPath, nodeArgs);

var isResolved = false;
var watchResolveTimeout;
sass.stdout.on('data', function (data) {
var stringData = data.toString();
logger.info(stringData);
});
}

loopSassFilesAsync(sassFiles);
}
});
}

function parseSass(filePath, importPaths, callback){
var sassFileContent = fs.readFileSync(filePath, { encoding: 'utf8'});
var cssFilePath = filePath.replace('.scss', '.css');
sass.stderr.on('data', function (err) {
var message = '';
var stringData = err.toString();
try {
var parsed = JSON.parse(stringData);
message = parsed.formatted || parsed.message || stringData;
} catch (e) {
message = err.toString();
}
logger.info(message);
});

if(sassFileContent.trim().length === 0) {
// No SASS content write an empty file
fs.writeFile(cssFilePath, '', 'utf8', function(){
callback();
});
return;
}
sass.on('error', function (err) {
logger.info(err.message);
if (!isResolved) {
isResolved = true;
reject(err);
}
});

sass.render({
data: sassFileContent,
includePaths: importPaths,
outFile: cssFilePath,
outputStyle: 'compressed'
}, function (e, output) {
if(e) {
//Callback with error
callback(e);
}

if(output && output.css){
output = output.css;
} else {
output = '';
}
// TODO: Consider using close event instead of exit
sass.on('exit', function (code, signal) {
if (!isResolved) {
isResolved = true;
if (code === 0) {
resolve();
} else {
reject(Error('SASS compiler failed with exit code ' + code));
}
}
});

fs.writeFile(cssFilePath, output, 'utf8', function(){
//File done writing
callback();
// SASS does not recompile on watch, so directly resolve.
if (options.watch && !isResolved) {
isResolved = true;
resolve();
}
});
});
}
5 changes: 5 additions & 0 deletions lib/watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
var converter = require('./converter');

module.exports = function ($logger, $projectData, $usbLiveSyncService) {
return converter.convert($logger, $projectData.projectDir, { watch: true });
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nativescript-dev-sass",
"version": "0.4.2",
"version": "0.5.0",
"description": "SASS CSS pre-processor for NativeScript projects.",
"scripts": {
"test": "exit 0",
Expand All @@ -18,6 +18,11 @@
"type": "after-prepare",
"script": "lib/after-prepare.js",
"inject": true
},
{
"type": "before-watch",
"script": "lib/watch.js",
"inject": true
}
]
},
Expand Down