简体   繁体   中英

Using JSLint/Hint with requirejs

I'm currently setting up a automated build script (with ) for a driven project . Therefor I would like to run / on all required files before concatenating and minifying it with r.js. Since the js folder contains a lot of development files I don't want to lint, I can't just pass js/**/*.js to JSLint. My first thought was to run r.js with optimizer: 'none' , lint the concatenated file and then minify it, but this is not an options for two reasons. First it will include vendor libs I don't want to lint and second finding the line with the error, find it's class, find the appropriate js-file in the dev folder, fix it there, run r.js again and finally lint it again, is way to much hassle for our workflow. So I'm looking for a possibility to hook up the linting into the r.js optimizer process or at least get a list of the requirejs dependency tree in some way, that I can parse and pass it to lint. Or any solution practicable for an automated process, you'll come up with.

Lint first, compile later. Just be specific about the files you want to lint and use the ! prefix to ignore specific files:

grunt.initConfig({
  lint: {
    // Specify which files to lint and which to ignore
    all: ['js/src/*.js', '!js/src/notthisfile.js']
  },
  requirejs: {
    compile: {
      options: {
        baseUrl: 'js/src',
        name: 'project',
        out: 'js/scripts.js'
      }
    }
  }
});

// Load the grunt-contrib-requirejs module.
// Do `npm install grunt-contrib-requirejs` first
grunt.loadNpmTasks('grunt-contrib-requirejs');

// Our default task (just running grunt) will
// lint first then compile
grunt.registerTask('default', ['lint', 'requirejs']);

I prefer not overriding r.js's methods, or you might create an unwanted dependency on a specific version (you'll need to update your code should r.js change)

This is the code I use for the same purpose, making use of require's onBuildRead function and the fact that objects in javascript are passed by reference. I make sure I run the require build first, then lint the js file sources.

The downside is that you'll lint after build complete. For my setup that is not a problem.

module.exports = function(grunt) {



var jsHintOptions = {
        options: {
            curly: true,
            eqeqeq: true,
            eqnull: true,
            browser: true,
            globals: {
                jQuery: true
            }
        },
        all: []  // <--- note this is empty! We'll fill it up as we read require dependencies
    };

var requirejsOptions = {
        compile: {
            options: {
                paths: {
                    "jquery": "empty:"
                },
                baseUrl: "./",
                name: "src/mypackage/main",
                mainConfigFile: "src/mypackage/main.js",
                out: 'build/mypackage/main.js',
                onBuildRead: function (moduleName, path, contents) {
                    jsHintOptions.all.push(path);   // <-- here we populate the jshint path array
                    return contents;
                }
            }
        }
    };

grunt.initConfig({
    pkg: grunt.file.readJSON('packages/mypackage.package.json'),
    requirejs: requirejsOptions,
    jshint: jsHintOptions
});

// load plugin that enabled requirejs
grunt.loadNpmTasks('grunt-contrib-requirejs');

// load code quality tool
grunt.loadNpmTasks('grunt-contrib-jshint');


grunt.registerTask('default', ['requirejs', 'jshint']);   // <-- make sure your run jshint AFTER require
};

This answer sort of bypasses Grunt, but it should work for what you want to do. The way I would do it is look at r.js and try to override a function that receives the path to the various modules being loaded, intercept the module name, and lint the files while r.js is loading and compiling the modules. I've done it like so:

var requirejs = require('requirejs');
var options = {/*r.js options as JSON*/};
var oldNewContext = requirejs.s.newContext;
requirejs.s.newContext = function(){
    var context = oldNewContext.apply(this, arguments);
    var oldLoad = context.Module.prototype.load;
    context.Module.prototype.load = function(){
        var module = oldLoad.apply(this, arguments);

        if(/\.js$/.test(this.map.url) && !/^empty:/.test(this.map.url))
            console.log(this.map.url);

        return module;
    }
    return context;
}
requirejs.optimize(options)

Then when you run requirejs.optimize on your modules, you should get all the non-empty JavaScript urls logged to the console. Instead of logging them to the console, you could use the urls to lint the files.

Instead of using the lint task, install, load, and set up grunt-contrib-jshint . It has an ignores option to ignore specific files or file path patterns.

Here's my task:

jshint: {
    options: {
        // options here to override JSHint defaults
        boss    : true,  // Suppress warnings about assignments where comparisons are expected
        browser : true,  // Define globals exposed by modern browsers (`document`, `navigator`)
        curly   : false, // Require curly braces around blocks
        devel   : false, // Define `console`, `alert`, etc. (poor-man's debugging)
        eqeqeq  : false, // Prohibit the use of `==` and `!=` in favor of `===` and `!==`
        "-W041" : false, // Prohibit use of `== ''` comparisons
        eqnull  : true,  // Suppress warnings about `== null` comparisons
        immed   : true,  // Prohibit the use of immediate function invocations w/o wrapping in parentheses
        latedef : true,  // Prohibit the use of a var before it's defined
        laxbreak: true,  // Suppress warnings about possibly unsafe line breaks
        newcap  : true,  // Require you to capitalize names of constructor functions
        noarg   : true,  // Prohibit the use of `arguments.caller` and `arguments.callee`
        shadow  : true,  // Suppress warnings about var shadowing (declaring a var that's declared somewhere in outer scope)
        sub     : true,  // Suppress warnings about using `[]` notation, e.g. `person['name']` vs. `person.name`
        trailing: true,  // Trailing whitespace = error
        undef   : false, // Prohibit the use of explicitly undeclared variables
        unused  : false, // Warn when you define and never use your variables
        white   : false, // Check JS against Douglas Crawford's coding style
        jquery  : true,  // Define globals exposed by jQuery
        // Define global functions/libraries/etc.
        globals : {
            amplify : true
        },
        ignores: [
            'src/app/templates/template.js',
            'src/scripts/plugins/text.min.js'
        ]
    },
    gruntfile: {
        src: 'Gruntfile.js'
    },
    app: {
        src: 'src/app/**/*.js'
    },
    scripts: {
        src: 'src/scripts/**/*.js'
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM