我有一个包含Handlebars.js子模块的Git项目。这里提供一个基本的示例 - 完整的项目更加复杂,包括与Dojo任务和部署步骤相关的内容,但这些内容在此并不相关。
$ mkdir handlebarstest ; cd handlebarstest ; git init
$ mkdir src ; git add src
$ git submodule add https://github.com/wycats/handlebars.js.git src/handlebars.js
我们的 package.json
没有提到 handlebars.js,只有grunt:
{
"name": "handlebarstest",
"version": "1.0.0",
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-clean": "~0.4.1",
"grunt-run-grunt": "latest"
}
}
在这个项目的历史中,我们的安装和构建过程是:$ npm install # install dependencies in package.json
$ grunt init # run the 'init' task which initialises git submodules
$ grunt build # run the 'build' task which compiles dojo etc.
在克隆项目后(例如在构建服务器上),需要初始化git子模块,我们通过grunt来控制这一过程,所以必须先安装grunt,然后运行任务进行子模块的初始化,包括麻烦的 handlebars.js。我们执行 "npm install" 安装grunt,然后运行 "grunt init",其中会获取handlebars.js,并包括它的package.json。因此,问题的根源是在顶层 "npm install" 运行时无法使用 package.json。
我们的Gruntfile.js知道如何调用handlebars.js中的Gruntfile.js:
/*jshint node:true */
module.exports = function (grunt) {
/*jshint camelcase: false */
var path = require('path');
grunt.initConfig({
clean: [ 'dist' ],
run_grunt: {
options: {
},
handlebars_build: {
options: {
log: true
},
src: [ 'src/handlebars.js/Gruntfile.js' ],
task: 'build'
},
handlebars_amd: {
options: {
log: true
},
src: [ 'src/handlebars.js/Gruntfile.js' ],
task: 'amd'
}
}
});
// var handlebarsLink= grunt.registerTask('handlebarsLink', function () {
// var done = this.async(),
// child = grunt.util.spawn({
// cmd: 'npm',
// args: [ 'link', 'src/handlebars.js' ]
// }, function (error) {
// if (error) {
// grunt.warn(error);
// done(false);
// return;
// }
// done();
// });
// child.stdout.on('data', function (data) {
// grunt.log.write(data);
// });
// child.stderr.on('data', function (data) {
// grunt.log.error(data);
// });
// });
var submodules;
if (grunt.file.exists(__dirname, '.git')) {
submodules = grunt.registerTask('submodules', function () {
var done = this.async(),
child = grunt.util.spawn({
cmd: 'git',
args: [ 'submodule', 'update', '--init', '--recursive' ]
}, function (error) {
if (error) {
grunt.warn(error);
done(false);
return;
}
done();
});
child.stdout.on('data', function (data) {
grunt.log.write(data);
});
child.stderr.on('data', function (data) {
grunt.log.error(data);
});
});
}
var init = submodules ? [ 'submodules'/*, 'handlebarsLink'*/ ] : [];
grunt.registerTask('init', init);
grunt.registerTask('default', 'build');
grunt.registerTask('build', init.concat([ 'clean', 'run_grunt:handlebars_build', 'run_grunt:handlebars_amd' ]));
grunt.loadTasks(path.join(__dirname, 'grunt'));
grunt.loadTasks(path.join(__dirname, 'src', 'intern', 'tasks'));
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-run-grunt');
};
运行Grunt失败,因为它递归进入了handlebars.js,但是它的package.json中的模块依赖项没有被安装。
Running "run_grunt:handlebars_build" (run_grunt) task
--> starting "src/handlebars.js/Gruntfile.js"
--> reporting "src/handlebars.js/Gruntfile.js"
| >> Local Npm module "grunt-contrib-clean" not found. Is it installed?
| >> Local Npm module "grunt-contrib-concat" not found. Is it installed?
| >> Local Npm module "grunt-contrib-connect" not found. Is it installed?
| >> Local Npm module "grunt-contrib-copy" not found. Is it installed?
| >> Local Npm module "grunt-contrib-requirejs" not found. Is it installed?
| >> Local Npm module "grunt-contrib-jshint" not found. Is it installed?
| >> Local Npm module "grunt-contrib-uglify" not found. Is it installed?
| >> Local Npm module "grunt-contrib-watch" not found. Is it installed?
| >> Local Npm module "grunt-saucelabs" not found. Is it installed?
| >> Local Npm module "es6-module-packager" not found. Is it installed?
| Loading "metrics.js" tasks...ERROR
| >> Error: Cannot find module 'underscore'
| Loading "publish.js" tasks...ERROR
| >> Error: Cannot find module 'underscore'
| Loading "version.js" tasks...ERROR
| >> Error: Cannot find module 'async'
| Warning: Task "clean" not found. Use --force to continue.
|
| Aborted due to warnings.
|
--> failed "src/handlebars.js/Gruntfile.js" (304ms)
--> failed handlebars_build @ "src/handlebars.js/Gruntfile.js"
Warning: 1 gruntfile failed and completed 0 (308ms)
Use --force to continue.
可能的解决方案:
- 在我们的顶层
package.json
中以某种方式使用npm link
,在npm install
完成后执行脚本钩子。但是这似乎是不可能的,因为handlebars.js/package.json
直到npm install
完成之后才会可用。 - 在
run_grunt:handlebars_build
之前添加手动步骤,进入src/handlebars.js
并在该目录中运行npm install
。但是这比我期望的更加繁琐。 - 在
run_grunt:handlebars_build
之前添加一步骤,将src/handlebars.js/package.json
中的依赖项安装到项目的顶级node_modules
目录中,这样在运行src/handlebars.js
内部的Gruntfile.js时可能会被捕捉到(这可能需要在src/handlebars.js
中没有node_modules
目录-我的npm和node_modules知识不是很好)。 - 放弃尝试将handlebars.js构建为我们项目的构建的一部分,从项目中删除
src/handlebars.js
子模块,并在其位置添加已构建的文件作为普通文件。这会很遗憾,因为您将通过git子模块方法失去跟踪项目版本的优势。
在最佳前进方向上提供一些建议将不胜感激。
package.json
文件来包含它。抱歉,我确定我错过了什么,只是不确定是什么。 - Jordan Kasper