build: faster build for less/css & without grunt
this slices our first build step out of the monolithic grunt build.
improvements:
- faster less build
- no useless css files for modules in debug folder, just one
`index.css`
- multiple targets possible (so we don't need to build from
`dist/debug` in the future
performance for less build & concat:
```
old:
- 762ms -- 757ms + 5ms (separate concat)
new:
- 597ms
```
why is it faster?
1. previous buildstep wrote css files on the disk to read & concat
it later
2. grunt.readfile / grunt.readjson are slow compared to the native
require function which also supports caching
needs node 4.x like our travis builds
PR: #586
PR-URL: https://github.com/apache/couchdb-fauxton/pull/586
Reviewed-By: Benjamin Keen <ben.keen@gmail.com>
diff --git a/.eslintrc b/.eslintrc
index 04e9936..6974475 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -38,6 +38,7 @@
"amd": true,
"mocha": true,
"phantomjs": true,
+ "es6": true
},
"globals": {
diff --git a/Gruntfile.js b/Gruntfile.js
index 8fa4743..4b7574a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -61,31 +61,12 @@
var assets = function () {
// Base assets
var theAssets = {
- less:{
- paths: ["assets/less"],
- files: {
- "dist/debug/css/fauxton.css": "assets/less/fauxton.less"
- }
- },
fonts: ["assets/fonts/*.eot", "assets/fonts/*.svg", "assets/fonts/*.ttf", "assets/fonts/*.woff"],
- img: ["assets/img/**"],
- // used in concat:index_css to keep file ordering intact
- // fauxton.css should load first
- css: ["assets/css/*.css", "dist/debug/css/fauxton.css"]
+ img: ["assets/img/**"]
};
initHelper.processAddons(function (addon) {
- // Less files from addons
- var root = addon.path || "app/addons/" + addon.name;
- var lessPath = root + "/assets/less";
- if (fs.existsSync(lessPath)) {
- // .less files exist for this addon
- theAssets.less.paths.push(lessPath);
- theAssets.less.files["dist/debug/css/" + addon.name + ".css"] =
- lessPath + "/" + addon.name + ".less";
- theAssets.css.push("dist/debug/css/" + addon.name + ".css");
- }
// Images
- root = addon.path || "app/addons/" + addon.name;
+ var root = addon.path || "app/addons/" + addon.name;
var imgPath = root + "/assets/img";
if (fs.existsSync(imgPath)) {
theAssets.img.push(imgPath + "/**");
@@ -156,15 +137,6 @@
watch: cleanableAddons
},
- less: {
- compile: {
- options: {
- paths: assets.less.paths
- },
- files: assets.less.files
- }
- },
-
// The jst task compiles all application templates into JavaScript
// functions with the underscore.js template function from 1.2.4. You can
// change the namespace and the template options, by reading this:
@@ -200,11 +172,6 @@
dest: "dist/debug/js/require.js"
},
- index_css: {
- src: assets.css,
- dest: 'dist/debug/css/index.css'
- },
-
test_config_js: {
src: ["dist/debug/templates.js", "test/test.config.js"],
dest: 'test/test.config.js'
@@ -250,7 +217,7 @@
},
style: {
files: initHelper.watchFiles(['.less', '.css'], ["./app/**/*.css", "./app/**/*.less", "./assets/**/*.css", "./assets/**/*.less"]),
- tasks: ['clean:watch', 'dependencies', 'less', 'concat:index_css']
+ tasks: ['clean:watch', 'dependencies', 'shell:build-less']
},
html: {
// the index.html is added in as a dummy file incase there is no
@@ -390,6 +357,10 @@
command: 'npm run stylecheck'
},
+ 'build-less': {
+ command: 'npm run build:less'
+ },
+
stylecheckSingleFile: {
command: '' // populated dynamically
},
@@ -515,7 +486,6 @@
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-jst');
- grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
@@ -543,7 +513,7 @@
// minify code and css, ready for release.
grunt.registerTask('minify', ['uglify', 'cssmin:compress']);
grunt.registerTask('jsx', ['shell:build-jsx']);
- grunt.registerTask('build', ['less', 'concat:index_css', 'jst', 'requirejs', 'concat:requirejs', 'uglify',
+ grunt.registerTask('build', ['shell:build-less', 'jst', 'requirejs', 'concat:requirejs', 'uglify',
'cssmin:compress', 'md5:requireJS', 'md5:css', 'template:release']);
/*
@@ -553,11 +523,11 @@
grunt.registerTask('dev', ['debugDev', 'couchserver']);
// build a debug release
- grunt.registerTask('debug', ['lint', 'dependencies', "gen_initialize:development", 'jsx', 'concat:requirejs', 'less',
- 'concat:index_css', 'template:development', 'copy:debug']);
+ grunt.registerTask('debug', ['lint', 'dependencies', "gen_initialize:development", 'jsx', 'concat:requirejs', 'shell:build-less',
+ 'template:development', 'copy:debug']);
grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development", 'jsx', 'shell:stylecheck',
- 'less', 'concat:index_css', 'template:development', 'copy:debug']);
+ 'shell:build-less', 'template:development', 'copy:debug']);
grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'shell:stylecheck']);
diff --git a/build-helper/less.js b/build-helper/less.js
new file mode 100644
index 0000000..5cf7733
--- /dev/null
+++ b/build-helper/less.js
@@ -0,0 +1,69 @@
+'use strict';
+
+const root = __dirname + '/../';
+const target = root + 'dist/debug/css/index.css';
+
+const fs = require('fs');
+const async = require('async');
+const less = require('less');
+
+let settings;
+if (fs.existsSync(root + 'settings.json')) {
+ settings = require(root + 'settings.json');
+} else if (fs.existsSync(root + 'settings.json.default.json')) {
+ settings = require(root + 'settings.json.default.json');
+} else {
+ throw new Error('no settings.json or settings.json.default found');
+}
+
+const srcAndTarget = settings.deps.map(addonName => {
+ addonName = addonName.name;
+
+ return 'app/addons/' + addonName + '/assets/less/' + addonName + '.less';
+});
+
+const paths = settings.deps.map(addonName => {
+ addonName = addonName.name;
+ return 'app/addons/' + addonName + '/assets/less/';
+});
+
+srcAndTarget.unshift('assets/less/fauxton.less');
+paths.unshift('assets/less');
+
+// --- end setup ---
+
+const options = {
+ paths: paths
+};
+
+const parser = new less.Parser(options);
+
+
+function writeCSS (files) {
+ function concatCSS (src, cb) {
+ fs.readFile(root + src, 'utf8', (err, data) => {
+ if (err) {
+ return cb(null, []);
+ }
+
+ parser.parse(data, (err, tree) => {
+ if (err) {
+ throw err;
+ }
+ return cb(null, [tree.toCSS()]);
+ });
+ });
+ };
+
+ async.concatSeries(files, concatCSS, (err, data) => {
+ fs.writeFile(target, data.join('\n'), (err) => {
+ if (err) {
+ throw err;
+ }
+
+ process.exit(0);
+ });
+ });
+}
+
+writeCSS(srcAndTarget);
diff --git a/package.json b/package.json
index e80131a..8db3dea 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,6 @@
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-cssmin": "~0.5.0",
"grunt-contrib-jst": "~0.5.0",
- "grunt-contrib-less": "~0.11.0",
"grunt-contrib-requirejs": "~0.4.1",
"grunt-contrib-uglify": "~0.2.0",
"grunt-couchapp": "~0.2.1",
@@ -36,7 +35,9 @@
"grunt-md5": "^0.1.11",
"grunt-shell": "^1.1.1",
"http-proxy": "~1.10.1",
+ "less": "^1.7.5",
"lodash": "^3.6.0",
+ "mkdirp": "^0.5.1",
"nano": "~5.12.0",
"optimist": "^0.6.1",
"react-tools": "^0.12.0",
@@ -48,6 +49,7 @@
},
"scripts": {
"stylecheck": "eslint --ext=js,jsx .",
+ "build:less": "mkdirp ./dist/debug/css && node ./build-helper/less.js",
"test": "grunt test",
"couchdebug": "grunt couchdebug",
"couchdb": "grunt couchdb",