Files
NodeBB/src/meta/css.js

193 lines
6.0 KiB
JavaScript
Raw Normal View History

2014-07-04 18:20:40 -04:00
'use strict';
2016-10-04 20:10:59 +03:00
var winston = require('winston');
var nconf = require('nconf');
var fs = require('fs');
var path = require('path');
var less = require('less');
var async = require('async');
var autoprefixer = require('autoprefixer');
var postcss = require('postcss');
var clean = require('postcss-clean');
2014-07-04 18:20:40 -04:00
2016-10-04 20:10:59 +03:00
var plugins = require('../plugins');
var db = require('../database');
var file = require('../file');
var utils = require('../../public/src/utils');
2014-07-04 18:20:40 -04:00
module.exports = function (Meta) {
2014-07-04 18:20:40 -04:00
2014-10-08 16:53:22 -04:00
Meta.css = {};
2014-07-04 18:20:40 -04:00
Meta.css.cache = undefined;
2014-09-24 18:36:30 -04:00
Meta.css.acpCache = undefined;
2014-07-04 18:20:40 -04:00
Meta.css.minify = function (target, callback) {
callback = callback || function () {};
2014-07-04 18:20:40 -04:00
2015-03-20 19:36:18 -04:00
winston.verbose('[meta/css] Minifying LESS/CSS');
db.getObjectFields('config', ['theme:type', 'theme:id'], function (err, themeData) {
2015-03-20 19:36:18 -04:00
if (err) {
return callback(err);
}
var themeId = (themeData['theme:id'] || 'nodebb-theme-persona'),
2015-03-20 19:36:18 -04:00
baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla')),
paths = [
baseThemePath,
path.join(__dirname, '../../node_modules'),
path.join(__dirname, '../../public/vendor/fontawesome/less')
2015-03-20 19:36:18 -04:00
],
2016-04-18 10:06:32 -04:00
source = '@import "font-awesome";';
2015-03-20 19:36:18 -04:00
plugins.lessFiles = filterMissingFiles(plugins.lessFiles);
plugins.cssFiles = filterMissingFiles(plugins.cssFiles);
async.waterfall([
function (next) {
getStyleSource(plugins.cssFiles, '\n@import (inline) ".', '.css', next);
2015-03-20 19:36:18 -04:00
},
function (src, next) {
2015-03-20 19:36:18 -04:00
source += src;
2016-11-01 12:59:51 -04:00
getStyleSource(plugins.lessFiles, '\n@import ".', '.less', next);
2015-03-20 19:36:18 -04:00
},
function (src, next) {
2015-03-20 19:36:18 -04:00
source += src;
next();
}
], function (err) {
2015-03-20 19:36:18 -04:00
if (err) {
return callback(err);
2014-07-15 16:32:51 -04:00
}
2014-09-29 19:31:27 -04:00
2016-04-18 10:06:32 -04:00
var acpSource = source;
if (target !== 'admin.css') {
source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/jquery/css/smoothness/jquery-ui.css";';
source += '\n@import (inline) "..' + path.sep + '..' + path.sep + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";';
source += '\n@import (inline) "..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";';
source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/flags.less";';
source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/blacklist.less";';
source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/generics.less";';
source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/mixins.less";';
source += '\n@import "..' + path.sep + '..' + path.sep + 'public/less/global.less";';
source = '@import "./theme";\n' + source;
minify(source, paths, 'cache', callback);
} else {
acpSource += '\n@import "..' + path.sep + 'public/less/admin/admin";\n';
acpSource += '\n@import "..' + path.sep + 'public/less/generics.less";\n';
acpSource += '\n@import (inline) "..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";\n';
acpSource += '\n@import (inline) "..' + path.sep + 'public/vendor/jquery/css/smoothness/jquery-ui.css";';
2016-12-09 18:53:08 +03:00
acpSource += '\n@import (inline) "..' + path.sep + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";';
minify(acpSource, paths, 'acpCache', callback);
}
2014-09-29 19:31:27 -04:00
});
2015-03-20 19:36:18 -04:00
});
2014-09-24 18:36:30 -04:00
};
2014-07-04 18:20:40 -04:00
2016-11-17 13:05:59 +03:00
Meta.css.getFromFile = function (callback) {
2016-11-16 20:54:57 -05:00
async.series([
async.apply(Meta.css.loadFile, path.join(__dirname, '../../public/stylesheet.css'), 'cache'),
async.apply(Meta.css.loadFile, path.join(__dirname, '../../public/admin.css'), 'acpCache')
], function (err) {
callback(err);
2016-11-16 20:54:57 -05:00
});
};
2015-03-20 19:36:18 -04:00
function getStyleSource(files, prefix, extension, callback) {
var pluginDirectories = [],
source = '';
files.forEach(function (styleFile) {
2015-03-20 19:36:18 -04:00
if (styleFile.endsWith(extension)) {
source += prefix + path.sep + styleFile + '";';
} else {
pluginDirectories.push(styleFile);
}
});
async.each(pluginDirectories, function (directory, next) {
utils.walk(directory, function (err, styleFiles) {
2015-03-20 19:36:18 -04:00
if (err) {
return next(err);
}
styleFiles.forEach(function (styleFile) {
2015-03-20 19:36:18 -04:00
source += prefix + path.sep + styleFile + '";';
});
next();
});
}, function (err) {
2015-03-20 19:36:18 -04:00
callback(err, source);
});
}
Meta.css.commitToFile = function (filename, callback) {
var file = (filename === 'acpCache' ? 'admin' : 'stylesheet') + '.css';
fs.writeFile(path.join(__dirname, '../../public/' + file), Meta.css[filename], function (err) {
if (!err) {
2014-11-17 11:24:46 -05:00
winston.verbose('[meta/css] ' + file + ' committed to disk.');
} else {
winston.error('[meta/css] ' + err.message);
process.exit(0);
}
callback();
});
2014-10-04 18:56:33 -04:00
};
2016-11-16 20:54:57 -05:00
Meta.css.loadFile = function (filePath, filename, callback) {
winston.verbose('[meta/css] Reading stylesheet ' + filePath.split('/').pop() + ' from file');
2015-09-29 18:22:41 -04:00
fs.readFile(filePath, function (err, file) {
2016-08-16 19:46:59 +02:00
if (err) {
return callback(err);
}
2016-03-24 13:29:50 -04:00
Meta.css[filename] = file;
callback();
});
};
function minify(source, paths, destination, callback) {
2016-12-13 15:43:20 +03:00
callback = callback || function () {};
2014-11-17 11:24:46 -05:00
less.render(source, {
paths: paths
}, function (err, lessOutput) {
2014-09-24 18:36:30 -04:00
if (err) {
winston.error('[meta/css] Could not minify LESS/CSS: ' + err.message);
2016-12-13 15:43:20 +03:00
return callback(err);
2014-09-24 18:36:30 -04:00
}
2014-07-04 18:20:40 -04:00
postcss([ autoprefixer, clean() ]).process(lessOutput.css).then(function (result) {
2015-12-31 12:15:31 -05:00
result.warnings().forEach(function (warn) {
winston.verbose(warn.toString());
});
Meta.css[destination] = result.css;
// Save the compiled CSS in public/ so things like nginx can serve it
2016-12-13 15:43:20 +03:00
if (nconf.get('local-assets') === undefined || nconf.get('local-assets') !== false) {
return Meta.css.commitToFile(destination, function () {
2016-12-13 15:43:20 +03:00
callback(null, result.css);
});
2015-12-31 12:15:31 -05:00
}
2016-12-13 15:43:20 +03:00
callback(null, result.css);
2015-12-31 12:15:31 -05:00
});
2014-07-04 18:20:40 -04:00
});
2014-09-24 18:36:30 -04:00
}
2014-07-04 18:20:40 -04:00
function filterMissingFiles(files) {
return files.filter(function (filePath) {
2015-09-29 18:22:41 -04:00
var exists = file.existsSync(path.join(__dirname, '../../node_modules', filePath));
2014-07-04 18:20:40 -04:00
if (!exists) {
2015-09-29 18:22:41 -04:00
winston.warn('[meta/css] File not found! ' + filePath);
2014-07-04 18:20:40 -04:00
}
return exists;
});
}
};