It looks like my .eslintrc file is not found my gulp-eslint
I defined a lint task:
gulp.task('lint', function () {
gulp.src(['src/**/*.js', 'src/**/*.jsx'])
.pipe(eslint())
.pipe(eslint.format());
})
It runs but doesn't show any error.
My .eslintrc file is defined in src folder. I tried to move it to the root folder of my project but it didn't change anything.
It's a pretty simple file:
{
"parser": "babel-eslint",
"ecmaFeatures": {
"classes": true,
"jsx": true
},
"plugins": [
"react"
],
"extends": "eslint-config-airbnb"
}
When I run eslint src in the terminal, I get a bunch of eslint errors, which is fine.
Any idea what is not properly working?
According to the docs you need to fail on error in the pipe.
gulp.task('lint', function () {
// ESLint ignores files with "node_modules" paths.
// So, it's best to have gulp ignore the directory as well.
// Also, Be sure to return the stream from the task;
// Otherwise, the task may end before the stream has finished.
return gulp.src(['**/*.js','!node_modules/**'])
// eslint() attaches the lint output to the "eslint" property
// of the file object so it can be used by other modules.
.pipe(eslint())
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).
.pipe(eslint.format())
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
.pipe(eslint.failAfterError());
});
Just a heads-up, the documentation is extremely useful and succinct on using configuration files, their precedence of usage and how they are located. You can also add the path to specify the location of your configuration file for a particular pipe:
gulp.task('lint', function () {
gulp.src(['src/**/*.js', 'src/**/*.jsx'])
.pipe(eslint({ configFile: '.eslintrc'}))
.pipe(eslint.format())
.pipe(eslint.failAfterError())
})
In the gulp-eslint documentation it should be noted that usage of the failOnError() and failAfterError() methods are advisable in that the task/stream is stopped and hence there is no invalid code written to the output.
If you use neither then the error is still caught but displayed only in the console output. So dependent on your task flow and design the destination file may still be written but you can conveniently correct the error immediately and carry on without having to start up your pipe processing/watch task again. An alternative is to look into gulp-plumber or some other means whereby you're not breaking out of a gulp watch task and yet also not writing a file containing code that doesn't pass linting validation.
Related
I've been a long time user of Standard, and now that I'm working on a new project, I've been asked to start writing semicolons.
I'm trying to use both xo, Babel and React, but I keep getting an error when I try to lint my code:
document is not defined. no-undef
I've tried adding an env option to the xo field in my package.json file, but no success.
My xo config:
"xo": {
"esnext": true,
"extends": "xo-react",
"space": true,
"rules": {
"react/jsx-space-before-closing": 0
}
}
It is cumbersome to specify linting options such as /** global document **/ and edit a configuration file every time you use a global.
This error can be suppressed by using --env=browser option:
xo --env=browser [<file|glob> ...]
Note: Same problem comes with Node.js, where the linter will complain that require and friends are not defined. The switch has to change to --env=node in that case.
However, XO defaults the env to node, therefore this will not be a problem in most cases. You will need multiple environments if your project contains both client and server files. in that case, --env switch can be set multiple times:
xo --env=browser --env=node [<file|glob> ...]
You have to define globals in ESLint. There are two ways to accomplish this, firstly as a comment in your code:
/* global document */
Or you can configure in configuration file like so:
{
"globals": {
"var1": true,
"var2": false
}
}
See the ESLint docs for more
I need to execute one JavaScript function before the Webpack starts its building process. The function just takes .scss files and concatenate them into one.
After that Webpack should take the result file. Is there an option to do that?
At the moment I run the function before the module.exports in webpack.config.js, but it seems that its not synchronous operation. Module.exports execute before the concat() function ends and Webpack can't find .scss file.
function concat(opts) {
(...)
}
concat({ src : styles, dest : './css/style.scss' });
module.exports = [
(...)
]
It seems a little bit odd to concat scss files before running Webpack as those kind of operations are usually handled by Webpack itself.
That being said, there's a few way of solving this.
The most obvious way would be to extract the concat parts to a separate file (e.g. prepare.js) and then run start the build process by running something along this line: node prepare.js && webpack. That'll first run prepare and if that exits without error webpack will be run. Usually that'll be added to the scripts part of your package.json, e.g.
"scripts": {
"build": "node prepare.js && webpack"
}
To achieve the same but in a more Webpack integrated way you could do the same thing where you extract the concat part to a separate file and then let Webpack execute that file, before build starts, with the help of Webpack Shell Plugin, e.g.
const WebpackShellPlugin = require('webpack-shell-plugin');
module.exports = {
...
plugins: [
new WebpackShellPlugin({
onBuildStart:['node prepare.js']
})
],
...
}
You can add any code at any phase of the building, using the Compiler Hooks.
The compile hook is called before (and every time) the compilation begins, so you probably want to use that:
config = {
//...
plugins: [
{
apply: (compiler) => {
compiler.hooks.compile.tap("MyPlugin_compile", () => {
console.log("This code is executed before the compilation begins.");
});
},
},
],
//...
};
I'm new to Gulp and the concept of task runners. I am wanting to write some javascript using es6 and have gulp run it through jscs, jshint and finally use babel to convert it to es5.
The part I'm confused about is the order I should have these tasks in my gulp pipeline. If I run jshint first I get warnings about how I can't use let and arrow functions. However, if I convert my code using babel first the babel output then fails validation as well.
What I'm looking for is a correct way of ordering my gulp task so it validates and converts my code to es5.
This is my current gulp task.
gulp.task('js-validation', function() {
$.util.log('**Starting js validation**');
return gulp
.src(config.alljs)
.pipe($.print())
.pipe($.jshint())
.pipe($.jscs())
.pipe($.babel())
.pipe($.jshint.reporter('jshint-stylish', {verbose: true}))
.pipe($.jshint.reporter('fail'))
.pipe(gulp.dest(config.temp));
});
This work for me:
.pipe(jshint({
esnext: true
}))
First, if possible, consider moving to ESLint; I'm not saying that because it's a subjective opinion, I'm saying that because it's modular and supports ES6, and even React+JSX if that's where you want to go with it.
You aren't going to have a lot of luck with JSHint, yet, if ES6 is where you're going.
If/when I'm wrong, please let me know, but I believe they have yet to replace their parser, to support all of ES6, and unless you're going to include the entirety of the browser polyfill+library in the pipeline (just for sake of having no missing methods, for validate to work), you may well be at a loss, here.
With ESLint in place, you could use the following config options (in .eslintrc, in the package.json, et cetera), to get ES6 support:
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"ecmaFeatures": {
"modules": true,
"jsx": true
}
}
Of course, if you don't need node globals, JSX or ES6 modules, feel free to rip those out.
The one other caveat there is that ESLint has no support for ES7 (ES2016), yet (but will, when it's standardized).
So array/generator comprehensions, async/await, trailing commas in function argument lists, et cetera, are not supported and will cause explosions.
There is a babel-eslint version of eslint which will validate these, if that's your requirement.
You can put that in place by installing "babel-eslint" and then in your eslint config, setting { "parser": "babel-eslint" } to the root object, along with all of your other config preferences.
But typically, you would lint the code that you are putting into the system, pre-compile, using ESLint and Babel:
// ...
.pipe( eslint() )
.pipe( babel() )
// ...
To lint the source code (rather then the compiled code) you have to call the linter before babel, so the order is correct.
However, you have to use a linter that really understands ES6. With JSHint, you have to set the esnext option, but I'm not sure whether it supports all ES6 features. I recommend to have a look at eslint with babel-eslint instead.
Instead of JSHint, you can use ESLint, which will have support for numerous ES6 functions:
http://eslint.org/docs/user-guide/configuring
You are correct that you want your linting to occur prior to transpilation, also.
gulp.task('jshint', function () {
gulp.src('js/**/*.js')
.pipe(cache('jshint'))
.pipe(jshint({esnext:true}))
.pipe(jshint.reporter('default'));
});
.pipe(jshint({esnext:true}))
You have the correct order, but as suggested from other answers to use ESLint. You should also have a function to handle errors when linting. Here is my gulpfile.js (not a perfect example, but it's working for me):
const gulp = require("gulp"),
babel = require("gulp-babel"),
eslint = require("gulp-eslint");
gulp.task("babel", () => {
gulp.src("src/*.js")
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.on("error", onError) // handle error for eslint
.pipe(babel())
.on("error", onError) // handle error for babel
.pipe(gulp.dest("dist"));
});
gulp.task("watch", () => {
process.chdir(process.env.INIT_CWD);
gulp.watch("src/*.js", ["babel"]);
});
// ignore if error is from babel, eslint error message is enough
if (err.plugin != "gulp-babel" && err.message) {
console.log("Message: ", err.message);
}
I'm building an app with shared React components in the browser and server-side Node.
Right now, I'm using Marty.js to do this:
function getUser() {
if (Marty.isBrowser) {
/* Get user using some client method */
} else {
/* otherwise, use some secret server code */
}
}
I'm bundling those functions up via Browserify, so they can run on the client as well as the server.
What I'd like to do is remove the else block from the bundle entirely, so I'm not leaking sensitive server-side code.
Is there a way to exclude blocks of code from the bundle?
I would create separate modules, one for the browser and one for the server. Then in your package.json, you tell browserify to use the browser module:
"browser": {
"./path/to/node-module.js": "./path/to/browser-module.js"
}
Now, whereever you call require('path/to/node-module'), browserify will load the other module instead.
More information from the docs:
browser field
There is a special "browser" field you can set in your package.json on a per-module basis to override file resolution for browser-specific versions of files.
For example, if you want to have a browser-specific module entry point for your "main" field you can just set the "browser" field to a string:
"browser": "./browser.js"
or you can have overrides on a per-file basis:
"browser": {
"fs": "level-fs",
"./lib/ops.js": "./browser/opts.js"
}
Note that the browser field only applies to files in the local module, and like transforms, it doesn't apply into node_modules directories.
While I'm not sure if it possible with Browserify, you can do it with Webpack using its DefinePlugin
From the docs (little modified):
Example:
new webpack.DefinePlugin({
DEBUG: false,
PRODUCTION: true,
...
})
...
Example:
if(DEBUG)
console.log('Debug info')
if(PRODUCTION)
console.log('Production log')
After passing through webpack with no minification results in:
if(false)
console.log('Debug info')
if(true)
console.log('Production log')
and then after a minification pass results in:
console.log('Production log')
You can use an environment variable, envify and uglify to do this.
if ('browser' === process.env.ENVIRONMENT) {
...
}
else {
...
}
Set process.env.ENVIRONMENT = 'browser' when doing your browser build, use the envify transform to substitute references to process.env with their current values and uglify will then perform dead code elimination to remove the branches which will never be hit.
Be more explicit about your intent, and put your code in their own files:
function getUser(options, callback) {
var fn;
if (Marty.isBrowser) {
fn = require("./lib/users/get.browser");
} else {
fn = require("./lib/users/get.server");
}
fn(options, callback);
}
and then as a browserify option you can say "replace require("./lib/users/get.server") with this variable instead, when you see it: ..." so that you don't build in that server file when you build for the browser.
However, if getUser can do different things based on where it's running, it feels far more likely that you're doing something wrong here: maybe that getUser should be a REST call to your server from the browser instead, but without more information, that's always hard to determine.
What about putting the code in a module for example UserServer and then exclude that module when you are compiling for the client? Your code becomes:
function getUser() {
if (Marty.isBrowser) {
/* Get user using some client method */
} else {
require('UserServer').getUser();
}
}
Browserify provides the following option to exclude files from the bundle:
--exclude, -u Omit a file from the output bundle. Files can be globs.
I've split out my grunt plugins into their own files and I'm using the load-grunt-config (https://github.com/firstandthird/load-grunt-config) to call them:
module.exports = function (grunt) {
'use strict';
require('load-grunt-config')(grunt);
};
I've got sass, autoprefixer, cssmin and watch tasks working but I'm also using Browsersync and px-to-rem these two plugins return:
Warning: Task "remify" not found. Use --force to continue.
and
Warning: Task "browsersync" not found. Use --force to continue.
when called individually or as part of a bigger task.
I've followed the syntax for the separate.js files for these two plugin so I'm at a loss. For example the remify.js file which is called when running grunt is written like this
module.exports = {
dist: {
options: {
base: 16,
fallback: true,
fallback_existing_rem: true,
ignore: []
},
files: {
'css/style.css': 'css/style.css'
}
}
};
Any ideas where this is going wrong?
I've also set up a gist of the example code, include package.json and a aliases.yml
https://gist.github.com/sturobson/f88258fd010e901e24d9
You have to call the grunt plugin exactly what it is. So where I've got remify I should be using px_to_rem and where I've got browsersync and I should have browserSync.
Silly me.
you can pass a second argument to load-grunt-config to provide some options where you could also define some pattern which can be used by load-grunt-tasks which is used internally.
if you don't pass a second argument, it uses the default-pattern of load-grunt-tasks which is grunt-*.
so if you want to load all devDependencies without defining them seperatly, do it like this:
require('load-grunt-config')(grunt, {
loadGruntTasks: {
pattern: '*',
scope: 'devDependencies'
}
});