问题
我目前正在开展一个项目,其中我们有一个父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'
这个方法可以正常工作。现在父进程不需要监视太多文件,只需由子进程执行自己的监视并通知父进程即可。
缺点是每个子进程都必须意识到这一点,并以相同的方式实现。
其他可能的解决方案...
其他人是如何处理这个问题的?是否有一种被广泛接受和使用的模式来处理这个问题?