将 JSLint/Hint 与 requirejs 一起使用

Posted

技术标签:

【中文标题】将 JSLint/Hint 与 requirejs 一起使用【英文标题】:Using JSLint/Hint with requirejs 【发布时间】:2012-10-07 20:59:32 【问题描述】:

我目前正在为 require.js 驱动的项目设置自动构建脚本(使用 gruntjs)。因此,我想在所有需要的文件上运行jslint/jshint,然后用 r.js 连接和缩小它。由于 js 文件夹包含很多我不想 lint 的开发文件,我不能只将 js/**/*.js 传递给 JSLint。我的第一个想法是使用optimizer: 'none' 运行 r.js,对连接的文件进行 lint,然后将其缩小,但这不是一个选项,原因有两个。首先它将包含我不想 lint 的供应商库,然后找到有错误的行,找到它的类,在 dev 文件夹中找到适当的 js 文件,在那里修复它,再次运行 r.js,最后 lint再次,这对我们的工作流程来说非常麻烦。因此,我正在寻找一种将 linting 连接到 r.js 优化器进程的可能性,或者至少以某种方式获取 requirejs 依赖树的列表,我可以对其进行解析并将其传递给 lint。或者任何适用于自动化流程的解决方案,您都会想出。

【问题讨论】:

类似github.com/jshint/jshint#ignoring-files-and-directories? 【参考方案1】:

首先 Lint,稍后编译。只需具体说明您要 lint 的文件并使用 !忽略特定文件的前缀:

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']);

【讨论】:

这绝对是一个好方法,但恕我直言,非常重复,因为您必须维护两个文件(main.js 和 grunt),而这正是我试图避免的。 ...不过感谢您的回答。【参考方案2】:

我不喜欢覆盖 r.js 的方法,否则您可能会在特定版本上创建不需要的依赖项(如果 r.js 发生更改,您需要更新代码)

这是我用于相同目的的代码,利用了 require 的 onBuildRead 函数以及 javascript 中的对象通过引用传递的事实。我确保首先运行 require 构建,然后 lint js 文件源。

缺点是你会在构建完成后进行 lint。对于我的设置来说这不是问题。

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
;

【讨论】:

【参考方案3】:

这个答案有点绕过 Grunt,但它应该适用于你想做的事情。我这样做的方法是查看 r.js 并尝试覆盖一个函数,该函数接收正在加载的各种模块的路径,截取模块名称,并在 r.js 加载和编译模块时检查文件。我已经这样做了:

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)

然后,当您在模块上运行 requirejs.optimize 时,您应该将所有非空 JavaScript url 记录到控制台。您可以使用 url 对文件进行 lint,而不是将它们记录到控制台。

【讨论】:

我想这正是我想要的,明天去测试。【参考方案4】:

不使用lint 任务,而是安装、加载和设置grunt-contrib-jshint。它有一个ignores 选项来忽略特定文件或文件路径模式。

这是我的任务:

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'
    

【讨论】:

以上是关于将 JSLint/Hint 与 requirejs 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

requirejs 与cuba 冲突文件解决

优化 RequireJS 项目(合并与压缩) 已翻译100%

RequireJS 模块的定义与加载

RequireJS:如何将变量从一个文件传递到另一个文件?

Ember.js 和 RequireJS

收藏文章 写的很好 可惜有些还是看看不懂额。。。RequireJS进阶:模块的定义与加载