From d988e8a50f13462aff6e4b9e89caf17d68fff8a1 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Sun, 21 May 2017 18:20:01 -0600
Subject: [PATCH 1/3] Test minifier
---
.eslintignore | 1 +
src/meta/minifier.js | 2 +-
test/build.js | 94 ++++++++++++++++++++++++++++++++++++++++++++
test/files/1.css | 1 +
test/files/1.js | 5 +++
test/files/2.js | 3 ++
test/files/2.less | 1 +
7 files changed, 106 insertions(+), 1 deletion(-)
create mode 100644 test/files/1.css
create mode 100644 test/files/1.js
create mode 100644 test/files/2.js
create mode 100644 test/files/2.less
diff --git a/.eslintignore b/.eslintignore
index 3278600389..11b456699f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -17,3 +17,4 @@ logs/
/coverage
/build
.eslintrc
+test/files
diff --git a/src/meta/minifier.js b/src/meta/minifier.js
index da7c570ce7..7c1a83bea4 100644
--- a/src/meta/minifier.js
+++ b/src/meta/minifier.js
@@ -156,7 +156,7 @@ function concat(data, callback) {
return callback(err);
}
- var output = files.join(os.EOL + ';');
+ var output = files.join('\n;');
callback(null, { code: output });
});
diff --git a/test/build.js b/test/build.js
index 3b6890ebe6..20d43033a9 100644
--- a/test/build.js
+++ b/test/build.js
@@ -1,8 +1,102 @@
'use strict';
+var string = require('string');
+var path = require('path');
+var fs = require('fs');
var assert = require('assert');
+var mkdirp = require('mkdirp');
var db = require('./mocks/databasemock');
+var file = require('../src/file');
+
+describe('minifier', function () {
+ before(function (done) {
+ mkdirp(path.join(__dirname, '../build/test'), done);
+ });
+
+ var minifier = require('../src/meta/minifier');
+ var scripts = [
+ path.resolve(__dirname, './files/1.js'),
+ path.resolve(__dirname, './files/2.js'),
+ ];
+ it('.js.bundle() should concat scripts', function (done) {
+ minifier.js.bundle(scripts, false, false, function (err, bundle) {
+ assert.ifError(err);
+ assert.strictEqual(
+ bundle.code,
+ '(function (window, document) {' +
+ '\n\twindow.doStuff = function () {' +
+ '\n\t\tdocument.body.innerHTML = \'Stuff has been done\';' +
+ '\n\t};' +
+ '\n})(window, document);' +
+ '\n' +
+ '\n;function foo(name, age) {' +
+ '\n\treturn \'The person known as "\' + name + \'" is \' + age + \' years old\';' +
+ '\n}' +
+ '\n'
+ );
+ done();
+ });
+ });
+
+ it('.js.bundle() should minify scripts', function (done) {
+ minifier.js.bundle(scripts, true, false, function (err, bundle) {
+ assert.ifError(err);
+ assert.strictEqual(
+ bundle.code,
+ '(function(n,o){n.doStuff=function(){o.body.innerHTML="Stuff has been done"}})(window,document);function foo(n,o){return\'The person known as "\'+n+\'" is \'+o+" years old"}'
+ );
+ done();
+ });
+ });
+
+ it('.js.minifyBatch() should minify each script', function (done) {
+ var s = scripts.map(function (script) {
+ return {
+ srcPath: script,
+ destPath: path.resolve(__dirname, '../build/test', path.basename(script)),
+ };
+ });
+ minifier.js.minifyBatch(s, false, function (err) {
+ assert.ifError(err);
+
+ assert(file.existsSync(s[0].destPath));
+ assert(file.existsSync(s[1].destPath));
+
+ fs.readFile(s[0].destPath, function (err, buffer) {
+ assert.ifError(err);
+ assert.strictEqual(
+ buffer.toString(),
+ '(function(n,o){n.doStuff=function(){o.body.innerHTML="Stuff has been done"}})(window,document);'
+ );
+ done();
+ });
+ });
+ });
+
+ var styles = [
+ '@import (inline) "./1.css";',
+ '@import "./2.less";',
+ ].join('\n');
+ var paths = [
+ path.resolve(__dirname, './files'),
+ ];
+ it('.css.bundle() should concat styles', function (done) {
+ minifier.css.bundle(styles, paths, false, false, function (err, bundle) {
+ assert.ifError(err);
+ assert.strictEqual(bundle.code, '.help { margin: 10px; } .yellow { background: yellow; }\n.help {\n display: block;\n}\n.help .blue {\n background: blue;\n}\n');
+ done();
+ });
+ });
+
+ it('.css.bundle() should minify styles', function (done) {
+ minifier.css.bundle(styles, paths, true, false, function (err, bundle) {
+ assert.ifError(err);
+ assert.strictEqual(bundle.code, '.help{margin:10px;display:block}.yellow{background:#ff0}.help .blue{background:#00f}');
+ done();
+ });
+ });
+});
describe('Build', function () {
it('should build all assets', function (done) {
diff --git a/test/files/1.css b/test/files/1.css
new file mode 100644
index 0000000000..840cf64b36
--- /dev/null
+++ b/test/files/1.css
@@ -0,0 +1 @@
+.help { margin: 10px; } .yellow { background: yellow; }
\ No newline at end of file
diff --git a/test/files/1.js b/test/files/1.js
new file mode 100644
index 0000000000..b20055f8ee
--- /dev/null
+++ b/test/files/1.js
@@ -0,0 +1,5 @@
+(function (window, document) {
+ window.doStuff = function () {
+ document.body.innerHTML = 'Stuff has been done';
+ };
+})(window, document);
diff --git a/test/files/2.js b/test/files/2.js
new file mode 100644
index 0000000000..9369213316
--- /dev/null
+++ b/test/files/2.js
@@ -0,0 +1,3 @@
+function foo(name, age) {
+ return 'The person known as "' + name + '" is ' + age + ' years old';
+}
diff --git a/test/files/2.less b/test/files/2.less
new file mode 100644
index 0000000000..cdd5d5b5f2
--- /dev/null
+++ b/test/files/2.less
@@ -0,0 +1 @@
+.help { display: block; .blue { background: blue; } }
\ No newline at end of file
From 62546bc4fd06210fa9890746f69a6673c3a99ec8 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Sun, 21 May 2017 19:01:41 -0600
Subject: [PATCH 2/3] Build tests
---
test/build.js | 96 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 91 insertions(+), 5 deletions(-)
diff --git a/test/build.js b/test/build.js
index 20d43033a9..215b823ce2 100644
--- a/test/build.js
+++ b/test/build.js
@@ -5,6 +5,7 @@ var path = require('path');
var fs = require('fs');
var assert = require('assert');
var mkdirp = require('mkdirp');
+var rimraf = require('rimraf');
var db = require('./mocks/databasemock');
var file = require('../src/file');
@@ -98,12 +99,97 @@ describe('minifier', function () {
});
});
-describe('Build', function () {
- it('should build all assets', function (done) {
- this.timeout(50000);
- var build = require('../src/meta/build');
- build.buildAll(function (err) {
+describe('Build', function (done) {
+ var build = require('../src/meta/build');
+
+ before(function (done) {
+ rimraf(path.join(__dirname, '../build/public'), done);
+ });
+
+ it('should build plugin static dirs', function (done) {
+ build.build(['plugin static dirs'], function (err) {
+ assert.ifError(err);
+ assert(file.existsSync(path.join(__dirname, '../build/public/plugins/nodebb-plugin-dbsearch/dbsearch')));
+ done();
+ });
+ });
+
+ it('should build requirejs modules', function (done) {
+ build.build(['requirejs modules'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/src/modules/Chart.js');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).toString().startsWith('/*!\n * Chart.js'));
+ done();
+ });
+ });
+
+ it('should build client js bundle', function (done) {
+ build.build(['client js bundle'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/nodebb.min.js');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).length > 1000);
+ done();
+ });
+ });
+
+ it('should build admin js bundle', function (done) {
+ build.build(['admin js bundle'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/acp.min.js');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).length > 1000);
+ done();
+ });
+ });
+
+ it('should build client side styles', function (done) {
+ build.build(['client side styles'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/stylesheet.css');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).toString().startsWith('/*! normalize.css'));
+ done();
+ });
+ });
+
+ it('should build admin control panel styles', function (done) {
+ build.build(['admin control panel styles'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/admin.css');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).toString().startsWith('@charset "UTF-8";'));
+ done();
+ });
+ });
+
+ it('should build templates', function (done) {
+ build.build(['templates'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/templates/admin/header.tpl');
+ assert(file.existsSync(filename));
+ assert(fs.readFileSync(filename).toString().startsWith(''));
+ done();
+ });
+ });
+
+ it('should build languages', function (done) {
+ build.build(['languages'], function (err) {
+ assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/language/en-GB/global.json');
+ assert(file.existsSync(filename));
+ var global = fs.readFileSync(filename).toString();
+ assert.strictEqual(JSON.parse(global).home, 'Home');
+ done();
+ });
+ });
+
+ it('should build sounds', function (done) {
+ build.build(['sounds'], function (err) {
assert.ifError(err);
+ var filename = path.join(__dirname, '../build/public/sounds/fileMap.json');
+ assert(file.existsSync(filename));
done();
});
});
From 2a9cdb7be24f889cc75693f42f4f025d9898860f Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Tue, 23 May 2017 14:00:37 -0600
Subject: [PATCH 3/3] Add `--threads=#` option for setting max threads
Make grunt NODE_ENV development by default
---
Gruntfile.js | 2 ++
src/meta/build.js | 5 +++++
src/meta/minifier.js | 16 ++++++++++++++--
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/Gruntfile.js b/Gruntfile.js
index c97795e743..9a84c15aa0 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -8,6 +8,8 @@ var initWorker;
var incomplete = [];
var running = 0;
+env.NODE_ENV = env.NODE_ENV || 'development';
+
module.exports = function (grunt) {
var args = [];
var initArgs = ['--build'];
diff --git a/src/meta/build.js b/src/meta/build.js
index cc3321923f..290957512a 100644
--- a/src/meta/build.js
+++ b/src/meta/build.js
@@ -180,6 +180,11 @@ function build(targets, callback) {
async.series([
beforeBuild,
function (next) {
+ var threads = parseInt(nconf.get('threads'), 10);
+ if (threads) {
+ require('./minifier').maxThreads = threads - 1;
+ }
+
var parallel = !nconf.get('series');
if (parallel) {
winston.info('[build] Building in parallel mode');
diff --git a/src/meta/minifier.js b/src/meta/minifier.js
index 7c1a83bea4..07f33d8253 100644
--- a/src/meta/minifier.js
+++ b/src/meta/minifier.js
@@ -41,9 +41,21 @@ function setupDebugging() {
var pool = [];
var free = [];
-Minifier.maxThreads = os.cpus().length - 1;
+var maxThreads = 0;
+
+Object.defineProperty(Minifier, 'maxThreads', {
+ get: function () {
+ return maxThreads;
+ },
+ set: function (val) {
+ maxThreads = val;
+ winston.verbose('[minifier] utilizing a maximum of ' + maxThreads + ' additional threads');
+ },
+ configurable: true,
+ enumerable: true,
+});
-winston.verbose('[minifier] utilizing a maximum of ' + Minifier.maxThreads + ' additional threads');
+Minifier.maxThreads = os.cpus().length - 1;
Minifier.killAll = function () {
pool.forEach(function (child) {