Использование JSLint/Hint с requirejs

В настоящее время я настраиваю сценарий автоматической сборки (с gruntjs) для require.js запущенный проект. Поэтому я хотел бы запустить jslint/jshint во всех необходимых файлах перед объединением и минимизацией их с помощью r.js . Поскольку папка js содержит много файлов разработки, которые я не хочу анализировать, я не могу просто передать js/**/*.js в JSLint. Моей первой мыслью было запустить r.js с optimizer: 'none', линтинговать конкатенированный файл, а затем минимизировать его, но это не вариант по двум причинам. Во-первых, он будет включать в себя библиотеки поставщиков, которые я не хочу анализировать, а во-вторых, находить строку с ошибкой, находить ее класс, находить соответствующий js-файл в папке dev, исправлять его там, снова запускать r.js и, наконец, проверять его. опять же, это слишком много хлопот для нашего рабочего процесса. Поэтому я ищу возможность подключить линтинг к процессу оптимизатора r.js или, по крайней мере, каким-то образом получить список дерева зависимостей requirejs, который я могу проанализировать и передать в lint. Или любое практическое решение для автоматизированного процесса, которое вы придумаете.


person Marcello di Simone    schedule 17.10.2012    source источник


Ответы (4)


Этот ответ как бы обходит 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 на своих модулях, вы должны получить все непустые URL-адреса JavaScript, зарегистрированные в консоли. Вместо того, чтобы записывать их в консоль, вы можете использовать URL-адреса для проверки файлов.

person Ryan Lynch    schedule 17.10.2012
comment
Думаю, это именно то, что я искал, завтра проверю. - person Marcello di Simone; 18.10.2012

Сначала линтуй, потом компилируй. Просто укажите конкретные файлы, которые вы хотите проверить, и используйте ! префикс для игнорирования определенных файлов:

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']);
person Kyle Robinson Young    schedule 17.10.2012
comment
это определенно хороший подход, но ИМХО очень повторяющийся, поскольку вам нужно поддерживать два файла (main.js и grunt), и это именно то, чего я стараюсь избегать. ... как бы то ни было, спасибо за ваш ответ. - person Marcello di Simone; 18.10.2012

Я предпочитаю не переопределять методы r.js, иначе вы можете создать нежелательную зависимость от конкретной версии (вам нужно будет обновить свой код, если r.js изменится)

Это код, который я использую для той же цели, используя функцию onBuildRead из require и тот факт, что объекты в javascript передаются по ссылке. Я сначала запускаю требуемую сборку, а затем анализирую источники файлов js.

Недостатком является то, что вы будете ворсить после завершения сборки. Для моей установки это не проблема.

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
};
person malukisses    schedule 08.03.2013

Вместо использования задачи 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'
    }
}
person jeffbyrnes    schedule 19.06.2013