Grunt watch/Bower link:在开发Bower组件时,如何最恰当地使用Grunt watch和Bower link?

4

问题

我目前正在开展一个项目,其中我们有一个父Web应用程序(恰好是一个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任务,或执行“livereload”以刷新用于查看应用程序的浏览器。

下面是一个简化的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 watch中

因此,我可以修改Gruntfile,还要监视bower_components文件夹中的.js文件,如下所示:

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 watch

我们可以在每个子模块中添加一个包含观察其自身文件的watch的Gruntfile.js。

当子模块中的文件发生更改时,我们可以更新特定的“livereload”文件,然后在父模块中只监听这些特定的文件。

下面是child-module-1中的示例'Gruntfile.js'

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'


这个方法可以正常工作。现在父进程不需要监视太多文件,只需由子进程执行自己的监视并通知父进程即可。

缺点是每个子进程都必须意识到这一点,并以相同的方式实现。


其他可能的解决方案...

其他人是如何处理这个问题的?是否有一种被广泛接受和使用的模式来处理这个问题?

1个回答

0

我们处理这个问题的方式非常类似于你提出的第二种解决方案。

  1. 当开发人员在一个子组件上工作时,他会从子组件设置一个 bower link 到父级 Angular 应用程序。

  2. 他打开两个终端窗口。一个窗口运行着子组件的 grunt watch 任务,另一个窗口运行着父级组件的 grunt watch 任务。

  3. 当他更改子组件时,它会触发 grunt 任务将文件的连接版本构建到组件的 /dist 文件夹中。

  4. 父级组件正在监视 /dist 文件夹中的更改,当子组件中的构建任务完成时,它会触发其在父应用程序中的构建任务。

为了最小化父级应用程序监视的文件数量,我们在所有的 bower 组件中使用了一个前缀,因此监视配置看起来像这样:

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

我不知道这是否是被广泛接受的“最佳实践”,但它确实有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接