Build pipeline improvements

- Refactor meta/css
- `fs.link` usage consolidated to `file.link`
- rimraf built modules directory to fix error
- Remove `local-assets` flag
v1.18.x
Peter Jaszkowiak 8 years ago
parent 05b68391dd
commit 8c86b2e32c

@ -46,7 +46,11 @@ exports.buildTargets = function (targets, callback) {
var meta = require('./src/meta');
buildStart = buildStart || Date.now();
var step = function (startTime, target, next) {
var step = function (startTime, target, next, err) {
if (err) {
winston.error('Build failed: ' + err.message);
process.exit(1);
}
winston.info('[build] ' + target + ' => Completed in ' + ((Date.now() - startTime) / 1000) + 's');
next();
};
@ -75,13 +79,13 @@ exports.buildTargets = function (targets, callback) {
case 'clientCSS':
winston.info('[build] Building client-side CSS');
startTime = Date.now();
meta.css.minify('stylesheet.css', step.bind(this, startTime, target, next));
meta.css.minify('client', step.bind(this, startTime, target, next));
break;
case 'acpCSS':
winston.info('[build] Building admin control panel CSS');
startTime = Date.now();
meta.css.minify('admin.css', step.bind(this, startTime, target, next));
meta.css.minify('admin', step.bind(this, startTime, target, next));
break;
case 'tpl':

@ -108,11 +108,7 @@ uploadsController.uploadSound = function (req, res, next) {
var soundsPath = path.join(__dirname, '../../../build/public/sounds'),
filePath = path.join(__dirname, '../../../public/uploads/sounds', uploadedFile.name);
if (process.platform === 'win32') {
fs.link(filePath, path.join(soundsPath, path.basename(filePath)));
} else {
fs.symlink(filePath, path.join(soundsPath, path.basename(filePath)), 'file');
}
file.link(filePath, path.join(soundsPath, path.basename(filePath)));
fs.unlink(uploadedFile.path, function (err) {
if (err) {

@ -102,4 +102,12 @@ file.existsSync = function (path) {
return !!exists;
};
file.link = function link(filePath, destPath, cb) {
if (process.platform === 'win32') {
fs.link(filePath, destPath, cb);
} else {
fs.symlink(filePath, destPath, 'file', cb);
}
};
module.exports = file;

@ -18,8 +18,32 @@ var utils = require('../../public/src/utils');
module.exports = function (Meta) {
Meta.css = {};
Meta.css.cache = undefined;
Meta.css.acpCache = undefined;
var buildImports = {
client: function (source) {
return '@import "./theme";\n' + source + '\n' + [
'@import "font-awesome";',
'@import (inline) "../../public/vendor/jquery/css/smoothness/jquery-ui.css";',
'@import (inline) "../../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
'@import (inline) "..' + path.sep + 'public/vendor/colorpicker/colorpicker.css";',
'@import "../../public/less/flags.less";',
'@import "../../public/less/blacklist.less";',
'@import "../../public/less/generics.less";',
'@import "../../public/less/mixins.less";',
'@import "../../public/less/global.less";',
].map(function (str) { return str.replace(/\//g, path.sep); }).join('\n');
},
admin: function (source) {
return source + '\n' + [
'@import "font-awesome";',
'@import "../public/less/admin/admin";',
'@import "../public/less/generics.less";',
'@import (inline) "../public/vendor/colorpicker/colorpicker.css";',
'@import (inline) "../public/vendor/jquery/css/smoothness/jquery-ui.css";',
'@import (inline) "../public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";',
].map(function (str) { return str.replace(/\//g, path.sep); }).join('\n');
},
};
Meta.css.minify = function (target, callback) {
callback = callback || function () {};
@ -30,25 +54,25 @@ module.exports = function (Meta) {
return callback(err);
}
var themeId = (themeData['theme:id'] || 'nodebb-theme-persona'),
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')
],
source = '@import "font-awesome";';
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'));
var paths = [
baseThemePath,
path.join(__dirname, '../../node_modules'),
path.join(__dirname, '../../public/vendor/fontawesome/less')
];
var source = '';
plugins.lessFiles = filterMissingFiles(plugins.lessFiles);
plugins.cssFiles = filterMissingFiles(plugins.cssFiles);
var lessFiles = filterMissingFiles(plugins.lessFiles);
var cssFiles = filterMissingFiles(plugins.cssFiles);
async.waterfall([
function (next) {
getStyleSource(plugins.cssFiles, '\n@import (inline) ".', '.css', next);
getStyleSource(cssFiles, '\n@import (inline) ".', '.css', next);
},
function (src, next) {
source += src;
getStyleSource(plugins.lessFiles, '\n@import ".', '.less', next);
getStyleSource(lessFiles, '\n@import ".', '.less', next);
},
function (src, next) {
source += src;
@ -59,29 +83,7 @@ module.exports = function (Meta) {
return callback(err);
}
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";';
acpSource += '\n@import (inline) "..' + path.sep + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css";';
minify(acpSource, paths, 'acpCache', callback);
}
minify(buildImports[target](source), paths, target, callback);
});
});
};
@ -115,22 +117,22 @@ module.exports = function (Meta) {
});
}
Meta.css.commitToFile = function (filename, callback) {
var file = (filename === 'acpCache' ? 'admin' : 'stylesheet') + '.css';
Meta.css.commitToFile = function (target, source, callback) {
var filename = (target === 'client' ? 'stylesheet' : 'admin') + '.css';
fs.writeFile(path.join(__dirname, '../../build/public/' + file), Meta.css[filename], function (err) {
fs.writeFile(path.join(__dirname, '../../build/public/' + filename), source, function (err) {
if (!err) {
winston.verbose('[meta/css] ' + file + ' committed to disk.');
winston.verbose('[meta/css] ' + target + ' CSS committed to disk.');
} else {
winston.error('[meta/css] ' + err.message);
process.exit(0);
process.exit(1);
}
callback();
});
};
function minify(source, paths, destination, callback) {
function minify(source, paths, target, callback) {
callback = callback || function () {};
less.render(source, {
paths: paths
@ -140,20 +142,14 @@ module.exports = function (Meta) {
return callback(err);
}
postcss([ autoprefixer, clean() ]).process(lessOutput.css).then(function (result) {
postcss(global.env === 'development' ? [ autoprefixer ] : [ autoprefixer, clean() ]).process(lessOutput.css).then(function (result) {
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
if (nconf.get('local-assets') === undefined || nconf.get('local-assets') !== false) {
return Meta.css.commitToFile(destination, function () {
callback(null, result.css);
});
}
callback(null, result.css);
return Meta.css.commitToFile(target, result.css, function () {
callback(null, result.css);
});
});
});
}

@ -4,9 +4,11 @@ var winston = require('winston');
var fork = require('child_process').fork;
var path = require('path');
var async = require('async');
var nconf = require('nconf');
var fs = require('fs');
var mkdirp = require('mkdirp');
var rimraf = require('rimraf');
var file = require('../file');
var plugins = require('../plugins');
var utils = require('../../public/src/utils');
@ -88,19 +90,10 @@ module.exports = function (Meta) {
};
Meta.js.linkModules = function (callback) {
function link(filePath, destPath, cb) {
if (process.platform === 'win32') {
fs.link(filePath, destPath, cb);
} else {
fs.symlink(filePath, destPath, 'file', cb);
}
}
plugins.reload(function (err) {
rimraf(path.join(__dirname, '../../build/public/src/modules'), function (err) {
if (err) {
return callback(err);
}
async.each(Object.keys(Meta.js.scripts.modules), function (relPath, next) {
var filePath = path.join(__dirname, '../../', Meta.js.scripts.modules[relPath]);
var destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
@ -110,7 +103,7 @@ module.exports = function (Meta) {
return next(err);
}
link(filePath, destPath, next);
file.link(filePath, destPath, next);
});
}, callback);
});
@ -143,12 +136,7 @@ module.exports = function (Meta) {
winston.verbose('[meta/js] ' + target + ' minification complete');
minifier.kill();
if (nconf.get('local-assets') === undefined || nconf.get('local-assets') !== false) {
return Meta.js.commitToFile(target, callback);
} else {
return callback();
}
Meta.js.commitToFile(target, callback);
break;
case 'error':
winston.error('[meta/js] Could not compile ' + target + ': ' + message.message);

@ -8,6 +8,7 @@ var rimraf = require('rimraf');
var mkdirp = require('mkdirp');
var async = require('async');
var file = require('../file');
var plugins = require('../plugins');
var db = require('../database');
@ -107,21 +108,6 @@ module.exports = function (Meta) {
return;
}
if (nconf.get('local-assets') === false) {
// Don't regenerate the public/sounds/ directory. Instead, create a mapping for the router to use
Meta.sounds._filePathHash = filePaths.reduce(function (hash, filePath) {
hash[path.basename(filePath)] = filePath;
return hash;
}, {});
winston.verbose('[sounds] Sounds OK');
if (typeof next === 'function') {
return next();
} else {
return;
}
}
// Clear the sounds directory
async.series([
function (next) {
@ -138,11 +124,7 @@ module.exports = function (Meta) {
// Link paths
async.each(filePaths, function (filePath, next) {
if (process.platform === 'win32') {
fs.link(filePath, path.join(soundsPath, path.basename(filePath)), next);
} else {
fs.symlink(filePath, path.join(soundsPath, path.basename(filePath)), 'file', next);
}
file.link(filePath, path.join(soundsPath, path.basename(filePath)), next);
}, function (err) {
if (!err) {
winston.verbose('[sounds] Sounds OK');

@ -54,7 +54,8 @@ module.exports = function (Plugins) {
async.parallel([
async.apply(mapFiles, pluginData, 'css', 'cssFiles'),
async.apply(mapFiles, pluginData, 'less', 'lessFiles'),
async.apply(mapClientSideScripts, pluginData)
async.apply(mapClientSideScripts, pluginData),
async.apply(mapClientModules, pluginData),
], next);
}, next);
}

@ -167,7 +167,8 @@ module.exports = function (app, middleware, hotswapIds) {
'/templates/',
'/src/',
'/images/',
// '/sounds/',
'/language/',
'/sounds/',
];
app.use(relativePath, function (req, res, next) {
if (deprecatedPaths.some(function (path) { return req.path.startsWith(path); })) {

@ -1,20 +1,5 @@
"use strict";
var path = require('path');
var nconf = require('nconf');
var meta = require('../meta');
function sendSoundFile(req, res, next) {
var resolved = meta.sounds._filePathHash[path.basename(req.path)];
if (resolved) {
res.status(200).sendFile(resolved);
} else {
next();
}
}
module.exports = function (app, middleware, controllers) {
app.get('/sitemap.xml', controllers.sitemap.render);
app.get('/sitemap/pages.xml', controllers.sitemap.getPages);
@ -23,8 +8,4 @@ module.exports = function (app, middleware, controllers) {
app.get('/robots.txt', controllers.robots);
app.get('/manifest.json', controllers.manifest);
app.get('/css/previews/:theme', controllers.admin.themes.get);
if (nconf.get('local-assets') === false) {
app.get('/sounds/*', middleware.addExpiresHeaders, sendSoundFile);
}
};

@ -45,7 +45,7 @@ server.on('error', function (err) {
winston.error(err);
if (err.code === 'EADDRINUSE') {
winston.error('NodeBB address in use, exiting...');
process.exit(0);
process.exit(1);
} else {
throw err;
}

Loading…
Cancel
Save