One of the great things about NativeScript is you can use the JavaScript tools you already know to help build your native iOS and Android apps. In my case I recently added two tools I was already familiar with—JSHint and JSCS—to my NativeScript apps to automate linting. In this article I’ll show you how to do it too.
Setting up Gulp
There are a number of tools you can use to automate tasks in NativeScript apps—including Gulp, Grunt, and even npm—but I’m a fan of Gulp so that’s what I’ll be using in this article. First, if you don’t have Gulp installed globally you’ll need to grab it from npm:
npm install -g gulp
Next, to start using Gulp in your NativeScript projects you need to make sure each project has a package.json
file in its root:
.
├── app
│ └── ...
├── package.json ────────────── here
└── platforms
└── ...
If your project doesn’t already have a package.json
file, run npm init
in the project’s root and npm will help you build one.
After that, install Gulp locally along with its JSHint and JSCS packages:
npm install gulp gulp-jshint gulp-jscs --save-dev
The --save-dev
flag tells npm to remember these dependencies in your newly created package.json
file. If you open your project’s package.json
you should now see a "devDependencies"
key at the bottom that looks something like this:
{
...
"devDependencies": {
"gulp": "^3.8.11",
"gulp-jscs": "^1.6.0",
"gulp-jshint": "^1.10.0"
}
}
With the installation out the way, now it’s time to write the code that uses these tools.
Writing the task
To write a Gulp task that runs JSHint and JSCS you’ll need to create a gulpfile.js
file in your project’s root:
.
├── app
│ └── ...
├── gulpfile.js ────────────── here
├── package.json
└── platforms
└── ...
Paste the following code into your newly created gulpfile.js
:
var gulp = require("gulp");
var jscs = require("gulp-jscs");
var jshint = require("gulp-jshint");
var filesToLint = [
"app/**/*.js",
// Exclude node modules from linting
"!app/node_modules/**/*.js",
// Exclude NativeScript modules from linting
"!app/tns_modules/**/*.js"
];
gulp.task("jscs", function() {
gulp.src(filesToLint)
.pipe(jscs());
});
gulp.task("jshint", function() {
return gulp.src(filesToLint)
.pipe(jshint())
.pipe(jshint.reporter());
});
gulp.task("lint", ["jshint", "jscs"]);
This code defines three Gulp tasks: jscs
, jshint
, and lint
. As you might expect, gulp jscs
runs JSCS, gulp jshint
runs JSHint, and gulp lint
runs both.
The filesToLint
array specifies which files the linters should hit. By default this is set to lint all JavaScript files in the app
directory—excluding any npm modules you have in the node_modules
folder, and any NativeScript modules in tns_modules
folder—but you may wish to customize this depending on how you’ve structured your app.
With the gulpfile.js
file in place the last thing you need to do is add a few configuration files.
Configuring JSHint and JSCS
JSHint and JSCS each have comprehensive sets of options for specifying exactly how they should lint your code. To specify these options, head back to the root of your project and create two files: .jshintrc
and .jscsrc
:
.
├── app
│ └── ...
├── gulpfile.js
├── package.json
├── platforms
│ └── ...
├── .jshintrc ────────────── here
└── .jscsrc ────────────── here
The contents of these configuration files will depend on your personal coding preferences. I’ll share my preferences if you’d like to use them as a starting point, and you can look over JSHint’s option docs and JSCS’s option docs to configure them to your liking.
Here’s my .jshintrc
:
{
"boss": true,
"curly": true,
"esnext": true,
"eqeqeq": true,
"eqnull": true,
"expr": true,
"immed": true,
"noarg": true,
"quotmark": "double",
"smarttabs": true,
"trailing": true,
"unused": true
}
And here’s my .jscsrc
:
{
"disallowMixedSpacesAndTabs": true,
"disallowMultipleLineBreaks": true,
"disallowMultipleSpaces": true,
"disallowMultipleVarDecl": true,
"disallowNamedUnassignedFunctions": true,
"disallowNewlineBeforeBlockStatements": true,
"disallowSpacesInCallExpression": true,
"disallowSpacesInFunctionDeclaration": {
"beforeOpeningRoundBrace": true
},
"disallowTrailingWhitespace": true,
"esnext": true,
"requireCommaBeforeLineBreak": true,
"requireCurlyBraces": ["if", "else", "for", "while", "try", "catch"],
"requireSemicolons": true,
"requireSpaceBetweenArguments": true,
"requireSpacesInConditionalExpression": true,
"requireSpacesInForStatement": true,
"requireSpacesInsideObjectBrackets": "all",
"validateIndentation": "\t",
"validateQuoteMarks": "\""
}
After you have these files in place head back to your terminal and run gulp lint
. If all went well you should see something like this:
$ gulp lint
[12:06:49] Using gulpfile /path/to/my-project/gulpfile.js
[12:06:49] Starting 'jshint'...
[12:06:49] Starting 'jscs'...
[12:06:49] Finished 'jscs' after 84 ms
[12:06:49] Finished 'jshint' after 305 ms
[12:06:49] Starting 'lint'...
[12:06:49] Finished 'lint' after 13 μs
If you head back into your app and create a problem, such as changing var
to vax
, gulp lint
should now point out the error:
$ gulp lint
[12:09:24] Using gulpfile /path/to/my-project/gulpfile.js
[12:09:24] Starting 'jshint'...
[12:09:24] Starting 'jscs'...
[12:09:24] Finished 'jscs' after 70 ms
[12:09:24] Finished 'jshint' after 255 ms
[12:09:24] Starting 'lint'...
[12:09:24] Finished 'lint' after 6.09 μs
events.js:72
throw er; // Unhandled 'error' event
^
Error: Unexpected identifier at my-file.js :
2 |
3 |exports.loaded = function(args) {
4 | vax page = args.object;
--------------^
5 | page.bindingContext = viewModel;
6 |};
Wrapping up
That’s it! If you have any other questions about this setup let me know in the comments. If you’re looking for an example of this setup in a real app, check out JustMeme, which is available on GitHub as well as the iOS app store.