Ссылка на часы Grunt / Bower: как лучше всего использовать часы Grunt со ссылкой Bower при разработке компонента Bower?

Проблема

В настоящее время я работаю над проектом, в котором у нас есть родительское веб-приложение (оказывается, приложение AngularJS) и несколько дочерних модулей Bower (содержащих Javascript, SASS, изображения и т. д.), которые включены в родитель с помощью Bower.

Например, родительский файл bower.json выглядит так:

{
    "name": "parent-app",
    "version": "1.0.0",
    "dependencies": {
        "child-1-module": "1.0.0",
        "child-2-module": "1.0.0"
    }
}

При выполнении «bower install» на родительском объекте дочерние модули будут установлены в:

bower_components/child-1-module
bower_components/child-2-module



Затем мы используем 'bower link' для каждого из дочерних модулей.

Затем «bower link child-1-module» и «bower link child-2-module» на родительском элементе для создания локальных программных ссылок, таких как:

bower_components/child-1-module -> /some/where/else/child-1-module
bower_components/child-2-module -> /some/where/else/child-2-module

Это позволяет нам локально вносить изменения в отдельные дочерние модули и видеть результаты в родительском приложении.


Затем мы также используем Grunt с grunt-contrib-watch в родительском приложении, чтобы отслеживать изменения в родительском приложении, а затем выполнять другие задачи Grunt или выполнять «живую перезагрузку» для обновления браузера, используемого для просмотра приложения.

Урезанный пример Gruntfile.js, который просматривает файлы .js, а затем выполняет задачу «jshint» и «livereload», приведен ниже:

grunt.initConfig({

    // Watches files for changes and runs tasks based on the changed files
    watch: {
        js: {
            files: [
                'scripts/{,*/}*.js', 
            ],
            tasks: ['newer:jshint:all'],
            options: {
                livereload: true
            }
        }
    }
}


Это хорошо работает для наблюдения за изменениями в родительском приложении, но мы также хотели бы знать, когда изменяются файлы в дочерних модулях. В настоящее время есть ряд решений, о которых я подумал/исследовал со смешанными результатами.


Потенциальное решение 1. Добавьте Bower_components для просмотра grunt в родительском

Поэтому я мог бы просто изменить файл Grunt, чтобы дополнительно просматривать файлы .js в папке Bower_components, например:

grunt.initConfig({

    // Watches files for changes and runs tasks based on the changed files
    watch: {
        js: {
            files: [
                'scripts/**/*.js', 
                'bower_components/**/*.js'
            ],
            tasks: ['newer:jshint:all'],
            options: {
                livereload: true
            }
        }
    }
}


Однако может быть много дочерних модулей (содержащих много файлов .js), поэтому производительность резко снижается и часто даже не запускается из-за проблемы "EMFILE: слишком много открытых файлов" (см. здесь).

Кроме того, дочерние модули добавляются динамически, поэтому мы не можем заранее указать в Gruntfile только конкретные, например:

'bower_components/child-1-module/**/*.js'


Потенциальное решение 2. Добавьте часы grunt в дочерние и родительские модули.

Вместо этого мы могли бы добавить Gruntfile.js в каждый дочерний модуль, содержащий часы для просмотра собственных файлов.

Когда файл изменяется в дочернем модуле, мы можем обновить определенный файл «livereload», а затем в родительском модуле мы можем отслеживать только эти конкретные файлы.

Пример «Gruntfile.js» в дочернем модуле-1

grunt.initConfig({
    watch: {
        js: {
            files: ['scripts/**/*.js'],
            tasks: ['livereloadEvent:js', 'newer:jshint:all']
        }
    }
}
grunt.registerTask('livereloadEvent', function() {
    // create a 'livereload/livereload.{arg}' file for the event specified
    grunt.file.mkdir('livereload');
    for(var i = 0; i < this.args.length; i++) {
        // contents of the file is the current timestamp
        grunt.file.write('livereload/livereload.'+ this.args[i], new Date());
    }
});


Затем в родительском элементе мы можем добавить к нашим часам следующую папку:

'bower_components/**/livereload/livereload.js'


Это работает нормально. Родителю теперь не нужно просматривать слишком много файлов, теперь дочерний процесс может осуществлять собственное наблюдение и в основном уведомлять родителя.

Недостаток в том, что каждый ребенок должен осознавать это и реализовывать это одинаково.


Другие возможные решения...

Как еще другие справились с этим? Существует ли общепринятый и широко используемый шаблон для обработки этого?


person dabs    schedule 30.01.2015    source источник


Ответы (1)


То, как мы справляемся с этим, очень похоже на предложенное вами решение 2.

  1. Когда разработчик работает над дочерним компонентом, он устанавливает связь между дочерним компонентом и родительским приложением Angular.

  2. Он открывает два терминальных окна. Один с задачей grunt watch выполняется на дочернем элементе, а другой — с задачей grunt watch на родительском.

  3. Когда он вносит изменения в дочерний компонент, он запускает задачу grunt для создания конкатенированной версии файла в папке /dist компонента.

  4. Родитель следит за изменениями в папке /dist, и когда задача сборки в дочернем компоненте выполнена, он запускает свою задачу для сборки в родительском приложении.

Чтобы свести к минимуму количество файлов, которые просматривает родительское приложение, мы используем префикс во всех наших компонентах Bower, поэтому конфиг просмотра выглядит так:

watch: {
    bower_components: {
        files: ['./bower_components/orgname-*/dist/*.js'],
        tasks: ['newer:copy']
    }
}

Я не знаю, является ли это общепринятой «лучшей практикой», но она работает.

person karllhughes    schedule 02.03.2016