I am trying to add a new grunt task in a sails.js application.
To keep my test case simple i have copied the copy task to a new file copy-tests.js, which is also in the tasks/config folder.
I have modified copy-tests.js to update the first param of the set method to 'copy-tests', so it now reads
module.exports = function(grunt) {
grunt.config.set('copy-tests', {
dev: {
files: [{
expand: true,
cwd: './assets',
src: ['**/*.!(coffee|less)'],
dest: '.tmp/public'
}]
},
build: {
files: [{
expand: true,
cwd: '.tmp/public',
src: ['**/*'],
dest: 'www'
}]
}
});
grunt.loadNpmTasks('grunt-contrib-copy');
};
I have updated compileAssets.js to add my new tasks, so it now reads
module.exports = function (grunt) {
grunt.registerTask('compileAssets', [
'clean:dev',
'jst:dev',
'less:dev',
'copy:dev',
'copy-tests:dev',
'coffee:dev',
'jade:dev'
]);
};
When i try to lift the sails app i get 'Task "copy-tests:dev" not found'
I know that grunt can see my file as i have added a log statement to Gruntfile.js as follows
var taskConfigurations = loadTasks('./tasks/config'),
registerDefinitions = loadTasks('./tasks/register');
console.log(taskConfigurations);
I can see copy-tests in among the other tasks when this statement logs
Can anyone help with why grunt claims it can't find copy-tests:dev ?
Alternatively maybe i am going about this the wrong way. What i am trying to achieve is having two copy tasks, one to copy my main build content to the .tmp folder, and a second one to copy my client side tests to the .tmp folder. Later i will make sure that only my dev builds run both copy tasks, my prod one will only run the first one. I thought the best way to do this would be with two grunt tasks in the config folder, but maybe there is another way...
Rather than define a second task to have an alternative copy, i needed to add to the Copy task as follows
module.exports = function(grunt) {
grunt.config.set('copy', {
dev: {
files: [{
expand: true,
cwd: './assets',
src: ['**/*.!(coffee|less)'],
dest: '.tmp/public'
}]
},
devTests: {
files: [{
expand: true,
cwd: './tests',
src: ['**/*.*'],
dest: '.tmp/public/tests'
}]
},
build: {
files: [{
expand: true,
cwd: '.tmp/public',
src: ['**/*'],
dest: 'www'
}]
}
});
grunt.loadNpmTasks('grunt-contrib-copy');
};
My compileAssets then looks like
module.exports = function (grunt) {
grunt.registerTask('compileAssets', [
'clean:dev',
'jst:dev',
'less:dev',
'copy:dev',
'copy:devTests',
'coffee:dev',
'jade:dev'
]);
};
I realised this when i looked at the sails-linker.js task and saw how many targets there were in that. I had been thinking of the targets as build targets and assuming they would have values like dev, test, prod etc, but it appears that they are a broader concept and every type of copy i might want to do should be a target in the copy.js task.
Related
I am trying to use javascript Const with Grunt Uglify but receive the error:
Unexpected token: keyword «const».
I have done a little googling and tried
npm install terser-webpack-plugin --save-dev
However that did not work.
It was stated I needed to add the following to my Plugins array...
const TerserPlugin = require('terser-webpack-plugin')
new TerserPlugin({
parallel: true,
terserOptions: {
ecma: 6,
},
}),
I wasn't sure exactly where to add this though? Does it go in my grunt file.js?
Additionally I also saw that a fix might be to use the harmony branch of grunt-contrib-uglify. But I fear this method is out of date?
Ultimately I am attempting to code a cookie consent pop up. Does anyone know how to get Const to work with grunt uglify?
Or does anyone have a better recommendation for coding cookie consent pop ups?
Many thanks.
Edit: Adding grunt file as requested
// Load Grunt
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Tasks
sass: { // Begin Sass Plugin (this takes all your scss files and compiles them into style.css)
dist: {
files: [{
expand: true,
cwd: 'assets/scss/my-theme',
src: ['**/*.scss'],
dest: 'dist/css',
ext: '.css'
}]
}
},
postcss: { // Begin Post CSS Plugin (this applies browser prefixes to your compiled style.css in 'dist' folder)
options: {
map: false,
processors: [
require('autoprefixer')({
overrideBrowserslist: ['last 2 versions']
})
]
},
dist: {
src: 'dist/css/style.css'
}
},
cssmin: { // Begin CSS Minify Plugin (this takes your style.css file from 'dist', minifies it and creates style.min.css)
target: {
files: [{
expand: true,
cwd: 'dist/css',
src: ['style.css', '!*.min.css'],
dest: 'dist/css',
ext: '.min.css'
}]
}
},
uglify: { // Begin JS Uglify Plugin (this takes your my-theme js files in 'assets', minifies them and creates script.min.js in 'dist' folder)
build: {
src: ['assets/js/my-theme/*.js'],
dest: 'dist/js/script.min.js'
}
},
watch: { // Compile everything into one task with Watch Plugin (this watches for any changes to scss and js files, so make sure it is pointing to your 'my-theme' CSS and JS folders in 'assets')
css: {
files: 'assets/scss/my-theme/**/*.scss',
tasks: ['sass', 'postcss', 'cssmin']
},
js: {
files: 'assets/js/my-theme/**/*.js',
tasks: ['uglify']
}
}
});
// Load Grunt plugins
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-terser');
// Register Grunt tasks
grunt.registerTask('default', ['watch']);
};
I'm working on a grunt script to copy some files from 'dev' into 'dist' and modify the folder structure slightly. There are html files present inside dev/html/eas1/ and dev/html/eas2. The script uses grunt.config.set in order to change the src and dest locations of the copy and the script is running without errors, but nothing is being copied over. Can anyone help?
module.exports = function(grunt) {
grunt.initConfig({
projectCodes: {
eas: ['eas1', 'eas2', 'eas3', 'eas4', 'eas5', 'eas6']
},
copy: {
main: {
files: [{
expand: true,
src: 'dev/eas/html/eas1/*',
dest: 'dist/eas/eas1/html/',
filter: 'isFile'
}]
}
}
});
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('dev', function(p) {
var projectCodes = grunt.config.get('projectCodes');
for(code in projectCodes[p]) {
grunt.config.set('copy.main.files.0.src', 'dev/'+p+'/html/'+projectCodes[p][code]+'/*');
grunt.config.set('copy.main.files.0.dest', 'dist/'+p+'/'+projectCodes[p][code]+'/html/');
grunt.task.run('copy:main');
}
});
};
I've done a fair bit of searching but can't seem to come up with a full answer to this.
I'm using grunt to manage my sass flow and I've been trying to find a way to output multiple css styles from grunt.
For example:
base.scss should have two outputs the first being style.css which has the expanded css style.
The second should be style.min.css which has the compressed css style.
How can I configure my gruntfile to do this for me?
You can do this by having two configurations, one outputting expanded CSS and the other compressed. Then register your task to run both. Your grunt file should look something like this:
Example
module.exports = function(grunt) {
'use strict';
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// Sass
sass: {
dev: { // This outputs the expanded css file
files: {
'style.css': 'base.scss'
}
},
prod: { // This outputs the compressed css file
options: {
outputStyle: 'compressed' // Minify output
},
files: {
'style.min.css': 'base.scss'
}
}
}
});
grunt.registerTask('default', ['sass:dev', 'sass:prod']); // Task runs both
}
Here is a more complete solution of what belongs in gruntfile.js, improving upon what Colin Bacon has already posted. By default grunt's pkg is already set to read package.json in the current directory, so no need to write that. You just need to install the jit-grunt plugin (besides the watch and sass plugins of course) to get my answer working.
module.exports = function(grunt) {
require('jit-grunt')(grunt);
grunt.initConfig({
sass: {
expanded: { // Target
options: { // Target options
style: 'expanded'
},
files: { // Dictionary of files
'style.css': 'style.scss' // 'destination': 'source'
}
},
compressed: { // Target
options: { // Target options
style: 'compressed'
},
files: { // Dictionary of files
'style.min.css': 'style.scss' // 'destination': 'source'
}
}
},
watch: {
styles: {
files: ['**/*.scss'], // which files to watch
tasks: ['sass'],
options: {
spawn: false // speeds up watch reaction
}
}
}
});
grunt.registerTask('default', ['sass', 'watch']);
};
Just add a new manifest file in your styles folder. For example, you have normally main.scss, if you create main2.scss and import some files in there. It will create a file for each manifest file you have.
If your sass task looks something like this (default yeoman webapp generator):
sass: {
options: {
sourceMap: true,
includePaths: ['bower_components']
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.{scss,sass}'],
dest: '.tmp/styles',
ext: '.css'
}]
},
server: {
files: [{
expand: true,
cwd: '<%= config.app %>/styles',
src: ['*.{scss,sass}'],
dest: '.tmp/styles',
ext: '.css'
}]
}
}
The file section sass read all .scss/.sass files and copy those to .tmp/styles. Later, copy task move those to dist/styles.
I've built Gruntfiles in the past, but mostly to compile Less and Jade, so this steps a bit out of my comfort zone and I'm struggling to figure out what to do.
I'd like to use the Gruntfile to:
Compile Jade to html
Compile Less to css
Build and show website at localhost:9000
Refresh localhost:9000 upon save of file (this uses grunt watch I'm assuming?)
Basically, I'd like to keep it light and easy, so that once I learn I can use it to teach others that I know. :)
Here's what my Gruntfile looks like so far. I have grunt-serve in there, but nothing loads to the page when I run it, so I'm really confused. Thanks for the help!
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-jade');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.initConfig({
jade: {
compile: {
options: {
client: false,
pretty: true
},
files: [ {
cwd: "assets/views",
src: "**/*.jade",
dest: "public",
expand: true,
ext: ".html"
} ]
}
},
less: {
development: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: {
// target.css file: source.less file
'public/css/main.css': 'assets/less/main.less',
}
}
},
watch: {
styles: {
files: [
'less/main.less',
],
tasks: ['less'],
options: {
nospawn: true
}
}
},
serve: {
options: {
port: 9000
}
}
});
grunt.registerTask('default', ['jade','less']);
grunt.loadNpmTasks('grunt-serve');
};
I think your build task is running jade and less, but not serve. Instead of
grunt.registerTask('default', ['jade','less']);
try
grunt.registerTask('default', ['jade','less','serve']);
my task is the following:
htmlmin : {
dist : {
options : {
removeComments : true,
collapseWhitespace : true
},
files : {
'index.html' : 'index-src.html'
}
}
},
this works fine when i have just one html file on my site, so this processes index-src.html into minified index.html.
what if i have 100 other html files to process? i don't want to manually list them in my gruntfile.
how can i abstract the file name and tell grunt to minify my src file to the corresponding production file? in my case they are:
source file is [name]-src.html
production file is [name].html
i'm guessing it's just a matter of syntax, but i don't know what to write.
thanks! :)
See the Globbing Patterns section of the Grunt Documentation.
I believe you'll just have to change your param files object to:
'index.html' : '*-src.html'
Update
Re-reading your question, I realized you needed a 1-1 file conversion for dynamic source and destination file names.
For that see Building the files object dynamically
I have yet to use this in my project but the syntax looks straight forward. You may need to change your src vs production naming convention to a folder based convention.
/source/name.html (source folder)
/build/name.html (destination folder)
Example
files: [
{
expand: true, // Enable dynamic expansion.
cwd: 'source/', // Src matches are relative to this path.
src: ['*-src.html'], // Actual pattern(s) to match.
dest: 'build/', // Destination path prefix.
ext: '.html', // Dest filepaths will have this extension.
extDot: 'first' // Extensions in filenames begin after the first dot
}
]
module.exports = function (grunt) {
// 1. All configuration goes here
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
controlCss: {
src: ['UI.controls/assets/css/*.css'],
dest: 'UI.controls/assets/css/min/production.css'
},
controlJs: {
src: ['UI.controls/assets/js/*.js'],
dest: 'UI.controls/assets/js/min/production.js'
},
coreJs: {
src: ['UI.core/assets/js/*.js'],
dest: 'UI.core/assets/js/min/production.js'
},
dist: {
src: ['UI.controls/assets/templates/*.htm'],
dest: 'UI.controls/assets/templates/min/production.min.htm'
}
},
cssmin: {
controlCss: {
src: 'UI.controls/assets/css/min/production.css',
dest: 'UI.controls/assets/css/min/production.min.css'
}
},
uglify: {
controlJs: {
src: 'UI.controls/assets/js/min/production.js',
dest: 'UI.controls/assets/js/min/production.min.js'
},
coreJs: {
src: 'UI.core/assets/js/min/production.js',
dest: 'UI.core/assets/js/min/production.min.js'
}
},
htmlmin: {
dist: {
options: {
removeComments: true,
collapseWhitespace: true
},
expand: true,
cwd: 'build',
src: ['UI.controls/assets/templates/*.htm'],
dest: 'UI.controls/assets/templates/min/production.min.htm'
}
}
});
// 2. Where we tell Grunt we plan to use this plug-in.
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-htmlmin');
// 3. Where we tell Grunt what to do when we type "grunt" into the terminal.
grunt.registerTask('default', ['concat', 'cssmin', 'uglify', 'htmlmin']);
};