Refactor skins to be built on server-side (#6849)

* WIP

* using bootswatch from npm instead of bootswatch CDN url

* feat: on-demand client css building for skins

* added ability for client-side to select a skin

* updated loading and saving logic of bootstrapSkin on client side user settings

* fix: broken test for #6849
This commit is contained in:
Julian Lam
2018-11-07 13:44:35 -05:00
committed by GitHub
parent 84433f29ab
commit 501b3a79ca
11 changed files with 93 additions and 47 deletions

View File

@@ -5,6 +5,7 @@ var nconf = require('nconf');
var fs = require('fs');
var path = require('path');
var async = require('async');
var rimraf = require('rimraf');
var plugins = require('../plugins');
var db = require('../database');
@@ -13,6 +14,12 @@ var minifier = require('./minifier');
var CSS = module.exports;
CSS.supportedSkins = [
'cerulean', 'cyborg', 'flatly', 'journal', 'lumen', 'paper', 'simplex',
'spacelab', 'united', 'cosmo', 'darkly', 'readable', 'sandstone',
'slate', 'superhero', 'yeti',
];
var buildImports = {
client: function (source) {
return '@import "./theme";\n' + source + '\n' + [
@@ -93,21 +100,34 @@ function getBundleMetadata(target, callback) {
path.join(__dirname, '../../public/vendor/fontawesome/less'),
];
// Skin support
let skin;
if (target.startsWith('client-')) {
skin = target.split('-')[1];
if (CSS.supportedSkins.includes(skin)) {
target = 'client';
}
}
async.waterfall([
function (next) {
if (target !== 'client') {
return next(null, null);
}
db.getObjectFields('config', ['theme:type', 'theme:id'], next);
db.getObjectFields('config', ['theme:type', 'theme:id', 'bootswatchSkin'], next);
},
function (themeData, next) {
if (target === 'client') {
var themeId = (themeData['theme:id'] || 'nodebb-theme-persona');
var baseThemePath = path.join(nconf.get('themes_path'), (themeData['theme:type'] && themeData['theme:type'] === 'local' ? themeId : 'nodebb-theme-vanilla'));
paths.unshift(baseThemePath);
themeData.bootswatchSkin = skin || themeData.bootswatchSkin;
}
async.parallel({
less: function (cb) {
async.waterfall([
@@ -143,14 +163,24 @@ function getBundleMetadata(target, callback) {
},
], cb);
},
skin: function (cb) {
const skinImport = [];
if (themeData && themeData.bootswatchSkin) {
skinImport.push('\n@import "./bootswatch/' + themeData.bootswatchSkin + '/variables.less";');
skinImport.push('\n@import "./bootswatch/' + themeData.bootswatchSkin + '/bootswatch.less";');
}
cb(null, skinImport.join(''));
},
}, next);
},
function (result, next) {
var skinImport = result.skin;
var cssImports = result.css;
var lessImports = result.less;
var acpLessImports = result.acpLess;
var imports = cssImports + '\n' + lessImports + '\n' + acpLessImports;
var imports = skinImport + '\n' + cssImports + '\n' + lessImports + '\n' + acpLessImports;
imports = buildImports[target](imports);
next(null, { paths: paths, imports: imports });
@@ -160,6 +190,13 @@ function getBundleMetadata(target, callback) {
CSS.buildBundle = function (target, fork, callback) {
async.waterfall([
function (next) {
if (target === 'client') {
rimraf(path.join(__dirname, '../../build/public/client*'), next);
} else {
setImmediate(next);
}
},
function (next) {
getBundleMetadata(target, next);
},
@@ -168,7 +205,7 @@ CSS.buildBundle = function (target, fork, callback) {
minifier.css.bundle(data.imports, data.paths, minify, fork, next);
},
function (bundle, next) {
var filename = (target === 'client' ? 'stylesheet' : 'admin') + '.css';
var filename = target + '.css';
fs.writeFile(path.join(__dirname, '../../build/public', filename), bundle.code, next);
},