Customize semantic-ui using Bower and Grunt - gruntjs

My project uses Bower to install deps and Grunt to build. My project tree looks like this
|
|-bower_components
| |
| |-jquery
| |-semantic
| |-...
|-Bower.json
|-Gruntfile.js
|-public
| |
| |-css // Compiled, concatenated and minified semantic-ui
| |-js // and other libs should be here
|-...
|-etc..
Is it possible to build custom semantic-ui (ie customize fonts, colors, remove unused components) using Grunt (or maybe using Gulp called from Grunt)?
Where to place semantic theme config and overrides files?

It's not difficulty to use grunt to build semantic-ui. I don't know about bower, but this is how I did it.
Install grunt-contrib-less.
Create a new directory somewhere in your project, e.g. '/less/semantic'. Copy 'site' directory from your semantic packagea, i.e. 'bower_components/semantic/src/site' to the new directory. All your overrides will be done here.
Create a config.json file in '/less/semantic' to configure what components you want to be included in your build. The file content will be something like this:
{
"elements": ["button", "divider"],
"collections": ["form"],
"modules": ["checkbox"]
}
Add following to your gruntFile.js file:
var fs = require('fs');
// Defines files property for less task
var getSemanticFiles = function() {
var files = {};
var config = JSON.parse(fs.readFileSync('less/semantic/config.json'));
var srcDir = 'bower_components/semantic/definitions/';
var outputDir = 'less/semantic/output/';
for (var type in config) {
config[type].forEach(function(ele) {
files[outputDir + type + '.' + ele + '.output'] = [srcDir + type + '/' + ele + '.less'];
});
}
return files;
};
Configure less task as following:
less: {
semantic: {
options: { compile: true }
files: getSemanticFiels()
},
dist: {
options: { compile: true }
files: { 'public/css/semantic.css': ['less/semantic/output/*'] }
}
}
Edit theme.config in 'bower_components/semantic/src', change #siteFoler to '../../../less/site/', and make any additional changes as needed per semantic document.
You run grunt less:semantic to compile all needed components, and then run less:dist to put them into a single css file.
Of course you can configure a watch task to automate the process. Then every time you make a change, the css will be automaticly re-built.

I am sure someone will build a grunt build to semantic one day, but for now, I just use this to call all the gulp commands using grunt. https://github.com/sindresorhus/grunt-shell. Just make sure you are calling the gulp build task and not the default gulp task. It has a watch task that will cause grunt to not finish the shell task.

Related

Grunt relative file path globbing

Is it possible to use Globbing partially on a directory in a file path?
I have a grunt-contrib-less task set up, the file path for my task looks something like this:
files: {
"../../application/user/themes/some-theme-5.1.1.5830/css/main.css": "less/base.less",
}
However the version number in the relative path may sometime change, such as:
files: {
"../../application/user/themes/some-theme-5.1.1.5831/css/main.css": "less/base.less",
}
Ideally I'd like to something like this:
files: {
"../../application/user/themes/some-theme-*/css/main.css": "less/base.less",
}
Is there a way of doing this? With the above syntax it stops searching after the asterisk.
One potential solution to achieve this is to utilize grunts --options feature.
When running a grunt task via the command line it is possible to specify an additional options value.
In your scenario you could pass in the version number of the folder name that is going to change. (I.e. In your case the part that you tried to specify using the asterisk character (*) E.g. '5.1.1.5830'
Caveat: For this solution to be of any use it does require knowing what that value, (the version number), of the destination folder is upfront prior to running the task via the command line.
Example Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
themesFolder: {
namePart: '0.0.0.0' // <-- If no option is passed via the CLI this name will be used.
},
less: {
production: {
options: {
// ...
},
files: {
// The destination path below utilizes a grunt template for the part
// of the folder name that will change. E.g. '5.1.1.0'
'../../application/user/themes/some-theme-<%= themesFolder.name %>/css/main.css': 'less/base.less'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('saveFolderNameFromOption', 'Uses the option provided to configure name part.', function(n) {
var themesFolder = grunt.option('themesFolder');
if (themesFolder) {
// Store the option value so it can be referenced in the less task.
grunt.config('themesFolder.namePart', themesFolder);
}
});
grunt.registerTask('processLess', ['saveFolderNameFromOption', 'less:production']);
};
Running the ProcessLess task
Run the task via the command line as follows:
$ grunt processLess --themesFolder=5.1.1.5830
Note: The additional option that is specified. Namely: --themesFolder=5.1.1.5830
When using the above command the .css output will be directed to the following path:
'../../application/user/themes/some-theme-5.1.1.5830/css/main.css': 'less/base.less'
Now, each time you run the task you modify the options accordingly.
Benefits: By providing the version number as an option via the CLI will avoid having to reconfigure your Gruntfile.js each time it is run.

where do i put config for plugin when using gruntfile-gtx

So, I have installed single page app based on npm/bower/grunt/angular.js
In the root I have gruntfile.js with this code
module.exports = function(grunt) {
var gtx = require('gruntfile-gtx').wrap(grunt);
gtx.loadAuto();
var gruntConfig = require('./grunt');
gruntConfig.package = require('./package.json');
gtx.config(gruntConfig);
// We need our bower components in order to develop
gtx.alias('build:standardversion', [
'compass:standardversion',
...
]);
gtx.finalise();
So now I have to install grunt-cache-bust plugin from here https://github.com/hollandben/grunt-cache-bust
I installed it with npm and now I don't know where to write a task for this.
Please tell me or give me a link to understand it properly
In the directory containing GruntFile.js, create a "grunt" folder if it doesn't exist.
In the "grunt" folder, create a file "cacheBust.js"
sample cacheBust.js:
module.exports = {
assets: {
files: {
src: ['index.html', 'contact.html']
}
}
}
To run cacheBust from the command line: "grunt cacheBust"

proper way of copying files to destination with gulp

I'm toying around with ASP.NET 5 and am using gulp. I added angularjs and angular-route to my package.json file which stored the files at Dependencies->NPM. I added this to my gulpfile.js thinking that it would copy over the the correct JS files. It did copy over the files, however, it also crashed the project. I had to manually go into the lib folder and remove everything that gulp added. What's the proper way to copy files from the NPM folder a destination folder. I'd like to be able to just run the task from Task Runner.
I'm assuming this is incorrect: (which is what I ran)
gulp.task("copyJs", function () {
return gulp.src('./node_modules/**/*.js')
.pipe(gulp.dest('./wwwroot/lib/'))
});
*I think the trailing '/' in gulp.dest('./wwwroot/lib/') might be the cause of the problem, try gulp.dest('./wwwroot/lib') instead.
This is the gulp workflow I use for Angular 2 with Asp.Net 5.
var gulp = require("gulp"),
merge = require("merge-stream"),
rimraf = require("rimraf");
var paths = {
webroot: "./wwwroot/",
node_modules: "./node_modules/"
};
paths.libDest = paths.webroot + "lib/";
gulp.task("clean:libs", function (cb) {
rimraf(paths.libDest, cb);
});
gulp.task("copy:libs", ["clean:libs"], function () {
var angular2 = gulp.src(paths.node_modules + "angular2/bundles/**/*.js")
.pipe(gulp.dest(paths.libDest + "angular2"));
var es6_shim = gulp.src([
paths.node_modules + "es6-shim/*.js",
"!**/Gruntfile.js"])
.pipe(gulp.dest(paths.libDest + "es6-shim"));
var systemjs = gulp.src(paths.node_modules + "systemjs/dist/*.js")
.pipe(gulp.dest(paths.libDest + "systemjs"));
var rxjs = gulp.src(paths.node_modules + "rxjs/bundles/**/*.js")
.pipe(gulp.dest(paths.libDest + "rxjs"));
return merge(angular2, es6_shim, systemjs, rxjs);
});
There are many ways to do it but one of the good simple ways I found was this: http://www.hanselman.com/blog/ControlHowYourBowerPackagesAreInstalledWithAGulpfileInASPNET5.aspx
Which do an update to the bowerrc file and everything after this update makes more sense.
UPDATE YOUR .BOWERRC AND PROJECT.JSON
In the root of your project is a .bowerrc file. It looks like this:
> { "directory": "wwwroot/lib" } Change it to something like this, and
> delete your actual wwwroot/lib folder.
>
> { "directory": "bower_components" } EXCLUDE YOUR SOURCE BOWER FOLDER
> FROM YOUR PROJECT.JSON
You'll also want to go into your project.json file for ASP.NET 5 and
make sure that your source bower_components folder is excluded from
the project and any packing and publishing process.
> "exclude": [
> "wwwroot",
> "node_modules",
> "bower_components" ],
UPDATE YOUR GULPFILE.JS
In your gulpfile, make sure that path is present in paths. There are
totally other ways to do this, including having gulp install bower and
figure out the path. It's up to you how sophisticated you want your
gulpfile to get as long as the result is that production ready .js
ends up in your wwwroot ready to be served to the customer. Also
include a lib or destination for where your resulting JavaScript gets
copied. Could be scripts, could be js, could be lib as in my case.
var paths = {
webroot: "./" + project.webroot + "/",
bower: "./bower_components/",
lib: "./" + project.webroot + "/lib/" }; ADD A COPY TASK TO YOUR GULPFILE
Now open your Gulpfile and note all the tasks. You're going to add a
copy task to copy in just the files you want for deployment with your
web app.
Here is an example copy task:
> gulp.task("copy", ["clean"], function () {
> var bower = {
> "bootstrap": "bootstrap/dist/**/*.{js,map,css,ttf,svg,woff,eot}",
> "bootstrap-touch-carousel": "bootstrap-touch-carousel/dist/**/*.{js,css}",
> "hammer.js": "hammer.js/hammer*.{js,map}",
> "jquery": "jquery/jquery*.{js,map}",
> "jquery-validation": "jquery-validation/jquery.validate.js",
> "jquery-validation-unobtrusive": "jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"
> }
>
> for (var destinationDir in bower) {
> gulp.src(paths.bower + bower[destinationDir])
> .pipe(gulp.dest(paths.lib + destinationDir));
> } });
Do note this is a very simple and very explicit copy tasks. Others
might just copy more or less, or even use a globbing wildcard.
It's up to you. The point is, if you don't like a behavior in ASP.NET
5 or in the general build flow of your web application you have more
power than ever before.
Right click the Bower node in the Solution Explorer and "Restore
Packages." You can also do this in the command line or just let it
happen at build time.
Looking in this simplified screenshot, you can see the bower
dependencies that come down into the ~/bower_components folder. Just
the parts I want are moved into the ~/wwwroot/lib/** folder when the
gulpfile runs the copy task.
I manage very complex monorepos, I don't like hardcoded file paths and prefer to mirror my source code for transparency. I explored a LOT of solutions for doing a lot of files at once and find them all opaque and bloated. I recommend a factory that ultimately does this with source-like file module references:
gulp.parallel(
() =>
gulp
.src(require.resolve('#bootstrap/core/dist/bootstrap.all.min.js'))
.pipe(gulp.dest(DIST)),
() =>
gulp
.src(require.resolve('foobar/dist/foobar.all.min.js'))
.pipe(gulp.dest(DIST))
You can make them named functions for visibility as well.

Pass in param to 'Grunt watch' for directory

I use grunt to less>css, minification, and concatenation of my CSS and JS. I am wondering if it's possible to pass in a param when you type in "grunt watch" which would be the directory to watch. That way I can have multiple versions of a site running off the same gruntfile.
http://pastebin.com/b2FJ74SC
You can use node's process.argv to get the command line arguments.
The code below can be called with: grunt watch --dir myfolder
grunt.registerTask('watch', function() {
var args = process.argv;
var folder = args[args.indexOf('--dir') + 1];
console.log('watch folder: ', folder); // "watch folder: myfolder"
});

How to import lesshat into every compiled .less file

In grunt-contrib-stylus there is a import option:
import
Type: Array
Import given stylus packages into every compiled .styl file, as if you wrote '#import '...' in every single one of said files.
options: {
compress: false,
use: [ require('kouto-swiss') ],
import: [ 'kouto-swiss' ]
},
How can I do the same thing with lesshat in grunt-contrib-less ?
Thanks
Since release 2 you can create plugins for Less easily. Thanks to Implementing preprocessing plugins you can create preprocess plugins too.
The preprocess plugin enable you to inject Less code before processing:
LesshatProcessor.prototype = {
process : function (src, extra) {
var injected = '#import "' + path.resolve(__dirname, '../') + '/node_modules/lesshat/build/lesshat.less";\n';
var ignored = extra.imports.contentsIgnoredChars;
var fileInfo = extra.fileInfo;
ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0;
ignored[fileInfo.filename] += injected.length;
return injected + src;
}
};
I have created a Lesshat plugin already: https://github.com/bassjobsen/less-plugin-lesshat. After installing this plugin by running npm install less-plugin-lesshat and then your are able to run: lessc file.less --lesshat.
You can also use this plugin together with grunt-contrib-less:
grunt.initConfig({
less: {
options: {
plugins: [
new (require('less-plugin-lesshat'))()
]
},
files: {'css/test.css' : 'less/test.less'}
}
)};
Notice that you should install the latest version of Less with grunt-contrib-less until Less has updated the version number (and grunt-contrib-less uses that version).
To use the plugin now:
run npm install grunt-contrib-less
Navigate to node_modules/grunt-contrib-less/
Remove node_modules/less
Download and unzip the latest version of Less at https://github.com/less/less.js/archive/master.zip
run npm install ./less.js

Resources