How to fail Grunt build if JSHint fails during watch task? - javascript

This seems like a basic question but I can't figure out how to do it. This is how to do it in gulp.
I want when I save a file with a jshint error to fail the Grunt build. The output states that jshint failed but Grunt still completes successfully.
grunt.initConfig({
watch: {
js: {
files: ['/scripts/{,**}/*.js'],
tasks: ['newer:jshint:all']
}
}
})
I know there is grunt.fail but how would I use it here?

The following gist will report a jshint error via the CLI and fail to execute any subsequent build steps when saving the .js file.
You will need to adapt according to your requirements :
Directory structure:
project
│
├──package.json
│
├───scripts
│ │
│ └───test.js
│
├─── Gruntfile.js
│
└───node_modules
│
└─── ...
package.json
{
"name": "stack40031078",
"version": "0.0.1",
"description": "Answer to stack question 40031078",
"author": "RobC",
"license": "Apache-2.0",
"devDependencies": {
"grunt": "^1.0.1",
"grunt-contrib-jshint": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-newer": "^1.2.0"
}
}
Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
// VALIDATE JS
jshint: {
// Note we're using 'src:' instead of 'all:' below.
files: {
src: './scripts/{,**}/*.js'
},
options: {
// Use your jshint config here or define them in
// a separate .jshintrc file and set the flag to:
//
// jshintrc: true
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
boss: true,
eqnull: true,
browser: true,
smarttabs: true,
globals: {}
}
},
// WATCH THE JS FILES
watch: {
js: {
files: ['./scripts/{,**}/*.js'],
// NOTE: we're not using 'newer:jshint:all' below, just 'newer:jshint'
tasks: ['newer:jshint' /* <-- Add subsequent build tasks here. E.g. ,'concat' - A registered task can also be added. E.g. 'default' */]
}
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-newer');
grunt.registerTask('default', [
]);
};
test.js
console.log('Hello World');
var test = function() {
return 'test';
};
Testing the demo gist
cd to the project directory
run $ npm install
run $ grunt watch
Open and make a simple edit to test.js, (e.g. add a new line to the end of the file), and save the change.
The CLI reports the error as follows:
Running "jshint:files" (jshint) task
./scripts/test.js
1 |console.log('Hello Universe');
^ 'console' is not defined.
>> 1 error in 1 file
Warning: Task "jshint:files" failed. Use --force to continue.
Aborted due to warnings.
Completed in 0.965s at Fri Oct 14 2016 10:22:59 GMT+0100 (BST) - Waiting...
NOTE:
Any subsequent build tasks specified in the tasks array of the watch.js object, (e.g. concat as per commented in the Gruntfile.js), will not be invoked using this gist as the jshint task fails (... and the concat task has not been defined of course!).
However, when the JavaScript file/s successfully pass the jshint task, any subsequent build tasks that are defined in the tasks array of the watch.js object will be invoked.
I hope this helps!

Related

Make a babel 7 config take effect in a sibling directory

I am working on a project consisting of three parts: a Client, a Server and a Common directory which contains things I want to import from both the Client and the Server. Everything can use both JS and TS. (Thanks to the babel-typescript preset)
Directory structure
Here is how it looks like:
root/
├── babel.config.js
├── Common/
│ ├── helper1.ts
│ ├── helper2.ts
│ ├── helper3.js
├── Client/
│ ├── src/
│ │ └── file1.js
│ └── .babelrc.js
└── Server/
├── src/
│ └── file1.js
└── .babelrc.js
Babel config files
Here is what my root/babel.config.js looks like:
module.exports = {
presets: ["#babel/preset-typescript"],
plugins: [
["#babel/plugin-transform-for-of", { assumeArray: true }],
"#babel/plugin-syntax-dynamic-import",
"#babel/plugin-syntax-import-meta",
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-json-strings",
["#babel/plugin-proposal-decorators", { legacy: true }],
"#babel/plugin-proposal-function-sent",
"#babel/plugin-proposal-export-namespace-from",
"#babel/plugin-proposal-numeric-separator",
"#babel/plugin-proposal-throw-expressions",
"#babel/plugin-proposal-export-default-from",
"#babel/plugin-proposal-logical-assignment-operators",
"#babel/plugin-proposal-optional-chaining",
["#babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }],
"#babel/plugin-proposal-nullish-coalescing-operator",
"#babel/plugin-proposal-do-expressions",
"#babel/plugin-proposal-function-bind",
],
};
And here is what my Server/.babelrc.js looks like:
const moduleAlias = require("./tools/module-alias");
const rootConfig = require("../babel.config");
module.exports = {
presets: [
...rootConfig.presets,
[
"#babel/preset-env",
{
targets: {
node: "current",
},
exclude: ["transform-for-of"],
},
],
],
plugins: [
...rootConfig.plugins,
[
"babel-plugin-module-resolver",
{
root: ["."],
alias: moduleAlias.relativeAliases,
extensions: [".js", ".ts"],
},
],
],
};
I will omit the Client/.babelrc.js since it's very similar to the Server one.
Basic test files
Here is an example Common/helper3.js file:
function doubleSay(str) {
return `${str}, ${str}`;
}
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1);
}
function exclaim(str) {
return `${str}!`;
}
const result = "hello" |> doubleSay |> capitalize |> exclaim;
console.log(result);
And inside Server/src/index.js I just import the file Common/helper3.js.
The error
Then, inside the Server directory, I do this:
npx babel-node src/index.js -x .ts,.js
Which prints the following error:
const result = "hello" |> doubleSay |> capitalize |> exclaim;
^
SyntaxError: Unexpected token >
I am definitely sure this error is related to my "strange" directory structure since it's fine when I put this exact file under Server/src.
The question
How can I keep this directory structure and tell Babel to use a config when it processes files within the Common directory?
I don't use Lerna or anything. I have setup special aliases that resolve $common to ../Common where needed. I know there is no issue with this since the file is properly found by Babel (otherwise I would get a "File not found" error)
Note
This babel structure is one of my attempt to fix the issue above. Originally I only had one babel.config.js inside Server and another inside Client. I thought having one at the root would solve this problem but it didn't change anything.
Edit after searching a lot more:
After taking a look at the babel code to find the config parsing, I noticed that this line : https://github.com/babel/babel/blob/8ca99b9f0938daa6a7d91df81e612a1a24b09d98/packages/babel-core/src/config/config-chain.js#L456 is called (null is returned).
I printed everything in this scope and noticed that babel automatically generates an only parameter containing the cwd. (Effectively saying that my babel.config.js doesn't affect my common directory despite being "above" is in the directory hierarchy).
I decided to try overloading it in the command line and arrived at this command:
npx babel-node src/index.js --root-mode upward -x .ts,.js --only .,../Common/ --ignore node_modules
(Added --only and --ignore)
This made me progress a bit: instead of failing to parse advanced syntax (pipeline operator) in js files, it failed on a ts failing, saying
export const accountStatus = Object.freeze({
^^^^^^
SyntaxError: Unexpected token export
What I don't understand is how it can parse the pipeline operator but not the typescript file even though both the pipeline plugin and the typescript are inside the same babel.config.js
Edit after solving this last issue:
Adding --only and --ignore made it work. The other issue was because I forgot to add the #babel/plugin-transform-modules-commonjs plugin and it was not able to resolve the import.
The slight change I did was adding ignore: ["**/node_modules"], to my root babel.config.js file and change my command to use those arguments: --root-mode upward -x .ts,.js --ignore __fake__.
Adding a random --ignore is enough to prevent babel from guessing by itself.
This is the solution I use and it works fine even though it's not very elegant.

Error when typing cmd grunt jshint.

I am currently going to the Learn how to Program with Steve Foote. I am using ubuntu as the operating system.I have installed Node.js, installed the grunt command-line, and installed the npm install to the correct folder.
I noticed a problem that when I ran node on the specified folder it wouldn't run the js files I have. I even went to the folder with the js files and it didn't work. I then tried node values.js but nothing came up.
This is my code for the package.json file:
{
"name": "kittenbook",
"version": "0.0.1",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-jshint": "~0.6.3"
}
}
And this is the Gruntfile.js
module.exports = function(grunt) {
//Project Configuiration
grunt.initConfig({
/*
* We will configuire our tasks here
*/
concat: {
release: {
src:['js/values.js', 'js/prompt.js'],
dest: 'release/main.js'
}
},
copy: {
release{
src: 'manifest.json',
dest: 'release/manifest.json'
}
},
jshint: {
files: ['js/values.js', 'js/prompt.js']
}
});
//We will load our plugins here
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-jshint');
//We will register our tasks here
grunt.registerTask('default', ['jshint', 'concat', 'copy']);
};
Sorry if the formatting is bad here it genuinely is all lined up on the text file.
When I type grunt jshint a warning comes up saying:
Loading "Gruntfile.js" tasks...ERROR
>> SyntaxError: Unexpected token {
Warning: Task "jshint" not found. Use --force to continue.
Aborted due to warnings.
You are missing a colon (:) in your grunt.initConfig object.
copy: {
release{ /*<--Missing colon in between "release" and the opening bracket {*/
src: 'manifest.json',
dest: 'release/manifest.json'
}
},

new to grunt - warning: task "concat, uglify" not found

As the title says I'm new to Grunt. I am following a tutorial located at: http://24ways.org/2013/grunt-is-not-weird-and-hard/. It is an older tutorial but most seems to work the same. I have installed "grunt-contrib-concat" and "grunt-contrib-uglify" and can run both individually. But when I run grunt, I get the following error: Warning: Task "concat, uglify" not found. Use --force to continue. Aborted due to errors. I've been looking around and can't seem to figure it out. My files are as follows:
Gruntfile.js:
module.exports = function(grunt) {
// 1. All configuration goes here
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
dist: {
src: [
'js/libs/*.js', // All JS in the libs folder
'js/controls.js', // This specific file
],
dest: 'dist/built.js',
}
},
uglify: {
build: {
src: 'js/build/production.js',
dest: 'js/build/production.min.js',
}
},
});
// 3. Where we tell Grunt we plan to use this plug-in.
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
// 4. Where we tell Grunt what to do when we type 'grunt' into the terminal.
grunt.registerTask('default', ['concat, uglify']);
};
package.json:
{
"name": "grunt_libsass_example-project",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-uglify": "^0.9.1"
}
}
Your passing in only one string for the registerTask task list. It should be a array with a list of strings like:
grunt.registerTask('default', ['concat', 'uglify']);
You're getting that error because it's looking for a task named 'concat, uglify'.
I had to run:
npm install grunt-contrib-uglify --save-dev

Grunt tasks stuck in endless loop

Working on putting together a base Gruntfile.js for some upcoming projects. Starting in on a new computer so everything has been a fresh build. Installed Node and NPM using Homebrew, and then installed Grunt globally, as well as in my local directory.
Here is my package.json:
{
"name": "timespent-prototype",
"version": "0.1.0",
"devDependencies": {
"assemble": "0.4.37",
"bower": "^1.4.1",
"grunt": "^0.4.5",
"grunt-contrib-concat": "^0.5.1",
"grunt-contrib-sass": "^0.9.2",
"grunt-contrib-watch": "^0.6.1",
"grunt-newer": "^1.1.0",
"grunt-wiredep": "^2.0.0"
}
}
And here is my Gruntfile.js:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
vendor: {
src: ['vendor/**/*.min.js'],
dest: 'build/javascripts/library.js',
}
},
// Takes your scss files and compiles them to css
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
'build/stylesheets/application.css': 'app/stylesheets/application/index.scss'
}
}
},
// Assembles your templates into HTML files
assemble: {
options: {
layoutdir: 'app/views/layouts/',
partials: ['app/views/partials/*.hbs'],
flatten: true,
expand: true
},
pages: {
src: ['app/views/**/*.hbs','!app/views/layouts/*.hbs','!app/views/partials/*.hbs'],
dest: 'build/'
}
},
wiredep: {
task: {
src: ['app/views/layouts/*.hbs']
}
},
// Watches for file changes, runs the default task
watch: {
files: ['app/**/*'],
tasks: ['default'],
options: {
// Start another live reload server on port 1337
livereload: 1337,
}
}
});
// Load the plugins
grunt.loadNpmTasks('assemble');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-newer');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-wiredep');
// Register the tasks
grunt.registerTask('default', ['sass','assemble']);
grunt.registerTask('watch', ['watch']);
grunt.registerTask('concat', ['concat']);
grunt.registerTask('wiredep', ['wiredep']);
};
The problem that I am seeing is that with multiple tasks, here specifically with wiredep and concat, the task gets stuck in a loop and never ends. Running grunt concat with verbose outputs like this:
Registering "grunt-contrib-concat" local Npm module tasks.
Reading /Users/jacksonlynch/projects/timespent-prototype/node_modules/grunt-contrib-concat/package.json...OK
Parsing /Users/jacksonlynch/projects/timespent-prototype/node_modules/grunt-contrib-concat/package.json...OK
Loading "concat.js" tasks...OK
+ concat
Running tasks: concat
Running "concat" task
Running "concat" task
Running "concat" task
Running "concat" task
Running "concat" task
Running "concat" task
Where Running "concat" task will continue to print until I stop it. As I am seeing this with multiple plugins and tasks this might be a problem with my installation of NPM or Grunt, but I'm having a very hard time debugging this. If anyone has run into this before, please let me know what helped!
Thanks!
Edit: in response to Alireza Ahmadi's comment, here is my file structure:
.
|
|_ app/
|_ assets/
|_ javascript/
|_ stylesheets/
|_ views/
|
|_ build/
|_stylesheets/
|_javascripts/
|
|_ vendor/
|_ bower.json
|_ Gruntfile.js
|_ package.json
In the last 2 lines of your Gruntfile.js you have redeclared the concat and wiredep tasks and when grunt tries to run your code, It stuck in an endless loop because concat refers to an undefined concat task, So you should remove these lines:
grunt.registerTask('concat', ['concat']);
grunt.registerTask('wiredep', ['wiredep']);
In general, When you define a task named foobar with grunt.initConfig, It's defined and does not need to registered using registerTask and it can be accessible by grunt foobar command.

CSSLint : How to config tasks just print error not warning

I'm new with Grunt - csslint plugin, after I run and cssLint task complete, there are many and many errors and warnings that I can't follow. So how to config task just print out the errors, not warning??
If you use grunt-contrib-csslint you can specify the options in a .csslintrc file.
From the grunt-contrib-csslint Readme:
Options
Any specified option will be passed through directly to csslint, thus
you can specify any option that csslint supports. The csslint API is a
bit awkward: For each rule, a value of false ignores the rule, a value
of 2 will set it to become an error. Otherwise all rules are
considered warnings.
Assuming you have a structure like this:
├── .csslintrc
├── Gruntfile.js
├── css
│   └── foo.css
├── node_modules
└── package.json
.csslintrc
{
"ignore": [
"adjoining-classes",
"box-model",
"box-sizing",
"bulletproof-font-face",
"compatible-vendor-prefixes",
"display-property-grouping",
"duplicate-background-images",
"duplicate-properties",
"empty-rules",
"fallback-colors",
"floats",
"font-faces",
"font-sizes",
"gradients",
"ids",
"import",
"import-ie-limit",
"important",
"known-properties",
"non-link-hover",
"order-alphabetical",
"outline-none",
"overqualified-elements",
"qualified-headings",
"regex-selectors",
"rules-count",
"selector-max",
"selector-max-approaching",
"selector-newline",
"shorthand",
"star-property-hack",
"text-indent",
"underscore-property-hack",
"unique-headings",
"universal-selector",
"unqualified-attributes",
"vendor-prefix",
"zero-units"
]
}
reference: https://github.com/CSSLint/csslint/wiki/Command-line-interface
Gruntfile
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
csslint: {
strict: {
src: ['css/*.css']
},
lax: {
options: {
csslintrc: '.csslintrc'
},
src: ['css/*.css']
}
}
});
grunt.loadNpmTasks('grunt-contrib-csslint');
grunt.registerTask('default', ['csslint:lax']);
};
Then grunt will report only errors and grunt csslint:strict will report warnings and errors.

Categories

Resources