Run grunt plugin outside of initConfig - gruntjs

Does anyone know what is the minimal pattern that I need to use a value that was set as variable with grunt.config.set from result of a plugin ran in grunt.initConfig?
Being new to both grunt and javascript, I am unclear as to how I can use this value to run another plugin,
for example, I can run a plugin within grunt.initConfig to get the value I want to set but how can I now run another set of plugin?
Here's an example of what I want to run:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-template');
grunt.initConfig({
shell: {
pwd: {
command: 'pwd'
}
}
});
grunt.registerTask('default', 'shell', function() {
grunt.config.set('pwd');
'template': {
'test': {
'options': {
'data': {
"name": "data",
"description": "",
"environment": <%=pwd%>
}
},
'files': {
'project.json': ['test.tpl']
}
}
}
});
};
But it doesn't work as I cannot simply run the plugin template in registerTask section like I do in initConfig.

Related

Create matching file names in Grunt

I've got several projects that each use an identical Gruntfile to run tasks and put the output in their own dist folder. Folder setup:
MyProjects
- Project1
- src
- dist
- Project2
- src
- dist
.....
I can't figure out how to run Grunt at the top level (MyProjects) and still have the output generated in the correct dist folder dynamically.
Is there a way I can have Grunt put the output in the correct dist folder without having to hard code it into the Gruntfile? Something like:
dist: {
files: {
// destination : source js
'<% ProjectName %>/dist/app.js': '<% ProjectName %>/src/app.js'
},
Thanks
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['src/**/*.js'],
tasks: ['browserify', 'file_append', 'concat'],
options: {
spawn: false
}
},
sass: {
files: "src/scss/*.scss",
tasks: ['sass', 'file_append', 'concat']
}
},
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"format/css/styles.css": "src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
},
file_append: {
default_options: {
files: [
// Development build
{
append: "",
prepend: "",
input: "format/app.js",
output: "format/dev.app.js"
},
{
append: "</style>`)",
prepend: "document.body.insertAdjacentHTML('afterbegin', `\n<style>\n",
input: "format/css/styles.css",
output: "format/css/dev.styles.html"
},
// Production build
{
append: "</script>",
prepend: "<script>\n",
input: "format/app.js",
output: "format/prod.app.html"
},
{
append: "</style>",
prepend: "<style>\n",
input: "format/css/styles.css",
output: "format/css/prod.styles.html"
}
]
}
},
concat: {
options: {
seperator: '\n'
},
// Development build
dev: {
src: ['format/dev.app.js', 'format/css/dev.styles.html'],
dest: 'dev/dev.app.js'
},
// Production build
prod: {
src: ['format/prod.app.html', 'format/css/prod.styles.html'],
dest: 'dist/prod.app.html'
}
},
browserify: {
dist: {
files: {
// destination for transpiled js : source js
'format/app.js': 'src/app.js'
},
options: {
transform: [
[
'babelify', {
presets: "es2015",
comments: false,
plugins: "transform-object-rest-spread"
}
]
],
browserifyOptions: {
debug: false
}
}
}
}
});
grunt.registerTask('default', [
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
};
There's a couple ways you can tackle this.
One option is to overload the arguments you pass to the task & include the folder name you wish to target.
grunt sass:dist:Project1
The additional argument is accessible via lodash templates which are a part of the GruntJS framework, and allows the configuration to be set at the time the task is ran:
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"MyProjects/<%= grunt.task.current.args[0] %>/format/css/styles.css": "MyProjects/<%= grunt.task.current.args[0] %>/src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
}
This approach works in the context of the function that's executing, but it wouldn't continue to pass the args to the next task. To do that, we need to add a custom task which will set a configuration object before executing the task list:
grunt.registerTask("build", (project) => {
const buildConfig = { project };
grunt.config.set("build", buildConfig);
grunt.task.run([
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
});
Now when we run grunt build:Project1, your custom task build will run and set the property we passed in the grunt config object. We can then reference that value in our other grunt config objects using lodash like we did for the first option. To access config values with lodash templates, we just have to provide the config pointer in json notation:
files: {
"MyProjects/<%= build.project %>/format/css/styles.css": "MyProjects/<%= build.project %>/src/scss/styles.scss"
}
Grunt compiles the configs required for a task at the time they're run & will process the lodash templates then, allowing you to inject your project name into a task. Since we stored the value in the config object, the value will persist through until grunt completes and exits.

Is this the right way to get lite-server to recognize the "server.index" override in bs-config.js?

lite-server seems to be ignoring my attempt to override the default index.
I have bs-config.json:
{
"server": {
"baseDir": "src",
"index": "/index.3.html",
"routes": {
"/node_modules": "node_modules"
}
}
}
I am using lite-server version 2.3.0, like this:
> lite-server -c=bs-config.json
browser-sync config **
{ injectChanges: false,
files: [ './**/*.{html,htm,css,js}' ],
watchOptions: { ignored: 'node_modules' },
server:
{ baseDir: 'src',
middleware: [ [Function], [Function] ],
directory: true,
index: '/index.3.html',
routes: { '/node_modules': 'node_modules'
}
}
}
In the console log output above, it recognizes the bs-config.json index default of "index.3.html", however, when the browser requests "GET http://localhost", the console shows it is trying to serve index.html instead of index.3.html.
[Browsersync] Serving files from: src
[Browsersync] Watching files...
17.09.04 22:35:51 404 GET /index.html
I have also tried supplying bs-config.js:
"use strict";
module.exports = {
"server": {
"baseDir": "src",
index: "i/index.3.html",
"directory":true,
"routes": {
"/node_modules": "node_modules"
}
// middleware,: {
// // overrides the second middleware default with new settings
// 1: require('connect-history-api-fallback')({index: '/index.3.html', verbose: true})
// }
}
}
and running lite-server with:
> lite-server -c=bs-config.js
but the behavior is the same.
Question: how do I override bs-config's server.index for lite-server?
lite-server's config-default.js sets index in it's 2nd middleware "fallback" function. This seems to be overring bs-config setting.
So the solution seems to be, override the middleware to set index as desired.
bs-config.js:
module.exports = {
"server": {
"baseDir": "src",
"routes": {
"/node_modules": "node_modules"
},
middleware: {
// overrides the second middleware default with new settings
1: require('connect-history-api-fallback')({
index: '/index.3.html',
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] // systemjs workaround})
}
}
}
Notes:
1. If a future version of lite-server changes it's default-config's middleware to put the index fallback in a different index position of the middleware function array, or to set different response headers, then this bs-config solution will need to be changed accordingly.
references:
Browserync Docs: https://browsersync.io/docs/options
lite-server: https://github.com/johnpapa/lite-server

Pass the name of watched file that changed as argument to a shell command

I have a collection of .svg files.
When I modify one of them, I would like grunt to re-run a command on each svg file that was modified
inkscape --file=FILENAME.svg --export-pdf=FILENAME.pdf
So far, I have this grunt script
module.exports = function (grunt) {
'use strict';
grunt.initConfig({
shell: {
figures: {
command: 'inkscape --file=FILENAME.svg --export-pdf=FILENAME.pdf'
}
},
watch: {
figs: {
files: '**/*.svg',
tasks: ['shell:figures']
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-shell');
grunt.registerTask('default', [watch']);
};
But I have no idea how to configure grunt in order to replace FILENAME by the name of each file that was modified.
I solved the issue using a config variable that is modified on the watch event before shell:figs runs
module.exports = function (grunt) {
'use strict';
// Project configuration
grunt.initConfig({
shell: {
figs: {
command: function() {
return 'inkscape --file="' + grunt.config('shell.figs.src') + '" --export-pdf="' + grunt.config('shell.figs.src').replace('.svg', '.pdf') + '"';
},
src: '**/*.svg'
}
},
watch: {
svgs: {
files: '**/*.svg',
tasks: ['shell:figs'],
options: {
spawn: false,
}
}
}
});
grunt.event.on('watch', function(action, filepath) {
grunt.config('shell.figs.src', filepath);
});
// These plugins provide necessary tasks
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-shell');
// Default task
grunt.registerTask('default', ['connect', 'watch']);
};
The only downside is that shell:figs cannot be called manually, it only works when running the watch task, or simply grunt.

Config for external (eg. bower) plugins

How can I use an configuration file (config.json) for easier grunt setup
I want to add/setup all needed plugins in my config.json and I want a seperated file for all Plugins or seperate FOlder for images
config.json
{
"images": {
"pluginA": [
"./faces/*.jpg"
],
"pluginB": [
"./corpes/*.jpg"
]
},
"javascript": {
"pluginA": [
"./faces/*.js"
],
"pluginB": [
"./corpes/*.js"
]
}
}
Gruntfile.js
plugins: grunt.file.readJSON('plugins_config.json')
jshint: {
development: {
files: {
**plugins.javascript**
}
}
}
desired output
dist/
images
pluginA
faces1.jpg
faces2.jpg
pluginB
corpes1.jpg
corpes2.jpg
javascript
pluginA.js
pluginB.js
styles
pluginA.css
pluginB.css
The way you usually access a grunt config is through the method grunt.config(key), so your json file is accessible through grunt.config('plugins').
Unfortunately the config object is initialized by grunt.initConfig, so you can't use it in the call to initConfig itself, which is what you need to do.
Your solution is to use a separate local variable outside initConfig, instead of a config:
module.exports = function(grunt) {
var plugins = grunt.file.readJSON('plugins_config.json');
// ...
grunt.initConfig({
jshint: {
development: {
files: {
src: plugins.javascript.pluginA,
}
}
},
// ...
});
};

Grunt task run one by one

Please help me.. I am new to grunt. I have to run grunt task one by one. When i execute the Grunt file i am trying to execute one by one ['clean', 'writefile','concat','requirejs'] since write file helps to create a dynamic json for requier.
When ever i execute first time grunt gives me error and at the second time it runs without error since the json file is created in the path. I tried grunt.task.run() but i couldn't get it
module.exports = function (grunt) {
'use strict';
grunt.initConfig({
// Before generating any new files, remove any previously-created files.
clean: {
tests: ['rjs/build.json','frontend-built']
},
writefile: {
json_value: {
options: {
data: 'frontend/config.json'
},
src: 'rjs/value.hbs',
dest: 'rjs/build.json'
}
},
requirejs: {
compile: {
options:grunt.file.readJSON('rjs/build.json')
}
},
concat: {
dist: {
files: {
'frontend/theme/css/theameA.css': ['frontend/theme/css/common/**/*.css','frontend/theme/css/lib/**/*.css','frontend/theme/css/theme_a/**/*.css'],
'frontend/theme/css/theameB.css': ['frontend/theme/css/common/**/*.css','frontend/theme/css/lib/**/*.css','frontend/theme/css/theme_b/**/*.css']
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-writefile');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['clean', 'writefile','concat','requirejs']);
};
Ok the problem is that the config code is processed before the tasks run so even if it didn't error out, it wouldn't be the correct behavior.
Try this to set the requirejs config dynamically via another custom task:
module.exports = function (grunt) {
'use strict';
grunt.initConfig({
// Before generating any new files, remove any previously-created files.
clean: {
tests: ['rjs/build.json','frontend-built']
},
writefile: {
json_value: {
options: {
data: 'frontend/config.json'
},
src: 'rjs/value.hbs',
dest: 'rjs/build.json'
}
},
concat: {
dist: {
files: {
'frontend/theme/css/theameA.css': ['frontend/theme/css/common/**/*.css','frontend/theme/css/lib/**/*.css','frontend/theme/css/theme_a/**/*.css'],
'frontend/theme/css/theameB.css': ['frontend/theme/css/common/**/*.css','frontend/theme/css/lib/**/*.css','frontend/theme/css/theme_b/**/*.css']
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-writefile');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('setRjsConfig', function() {
grunt.config('requirejs.options.compile', grunt.file.readJSON('rjs/build.json'));
});
grunt.registerTask('default', ['clean', 'writefile','concat', 'setRjsConfig', 'requirejs']);
};

Resources