我怎样才能得到凉亭和咕噜咕噜添加angular-bootstrap用户界面依赖?

我正在学习node.js,并尝试使用自动化工具来pipe理AngularJS应用程序。 为此,我在centos 7 devbox中安装了nodejs,grunt,yeoman和bower,并正在试验我在新环境中创build的AngularJS应用程序。 我怎样才能得到凉亭添加angular-bootstrap ui依赖于我在这个环境中构build的AngularJS应用程序?

在我的应用程序中的bower.jsonGruntfile.js都是自动生成的,所以我毫不犹豫地编辑它们,没有一些指导。


我曾经试过的是什么:

到目前为止,我浏览到/path/to/workspace/client并键入bower install angular-bootstrap 。 该命令成功运行。

但是,在应用程序的index.html ,bower生成的依赖关系列表不包含angular-bootstrap ui依赖关系,即使在编辑器中closures了index.html之后,键入Ctrl-C来停止服务器,然后键入grunt serve来启动服务器再次在编辑器中重新加载index.html

index.html的bower生成的依赖项列表如下所示:

 <!doctype html> <html> <head> <meta charset="utf-8"> <title></title> <base href="/" /> <meta name="description" content=""> <meta name="viewport" content="width=device-width"> <!-- Place favicon.ico and apple-touch-icon.png in the root directory --> <!-- build:css(.) styles/vendor.css --> <!-- bower:css --> <!-- endbower --> <!-- endbuild --> <!-- build:css(.tmp) styles/main.css --> <link rel="stylesheet" href="styles/main.css"> <!-- endbuild --><!-- note the real file extension is scss. not sure if this matters. --> <style type="text/css"> [ng\:cloak], [ng-cloak], .ng-cloak { display: none !important; } </style> </head> <body ng-app="hello" ng-cloak class="ng-cloak"> <!--[if lte IE 8]> <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p> <![endif]--> <!-- Add your site or application content here --> //HTML and AngularJS code omitted because it is not relevant to OP <!-- build:js(.) scripts/vendor.js --> <!-- bower:js --> <script src="bower_components/jquery/dist/jquery.js"></script> <script src="bower_components/angular/angular.js"></script> <script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js"></script> <script src="bower_components/angular-animate/angular-animate.js"></script> <script src="bower_components/angular-aria/angular-aria.js"></script> <script src="bower_components/angular-cookies/angular-cookies.js"></script> <script src="bower_components/angular-messages/angular-messages.js"></script> <script src="bower_components/angular-resource/angular-resource.js"></script> <script src="bower_components/angular-route/angular-route.js"></script> <script src="bower_components/angular-sanitize/angular-sanitize.js"></script> <script src="bower_components/angular-touch/angular-touch.js"></script> <!-- endbower --> <!-- endbuild --> <!-- build:js({.tmp,app}) scripts/scripts.js --> <script src="scripts/app.js"></script> <script src="scripts/controllers/main.js"></script> <script src="scripts/controllers/about.js"></script> <script src="scripts/controllers/mytimer.js"></script> <script src="scripts/controllers/auth.js"></script> <script src="scripts/controllers/home.js"></script> <script src="scripts/controllers/secure.js"></script> <script src="scripts/controllers/public1.js"></script> <script src="scripts/controllers/navigation.js"></script> <!-- endbuild --> </body> </html> 

我也包括bower.json如下,但由于它看起来自动生成,我bower.json手动改变它:

 { "name": "client", "version": "0.0.0", "dependencies": { "angular": "^1.4.0", "bootstrap-sass-official": "^3.2.0", "angular-animate": "^1.4.0", "angular-aria": "^1.4.0", "angular-cookies": "^1.4.0", "angular-messages": "^1.4.0", "angular-resource": "^1.4.0", "angular-route": "^1.4.0", "angular-sanitize": "^1.4.0", "angular-touch": "^1.4.0" }, "devDependencies": { "angular-mocks": "^1.4.0" }, "appPath": "app", "moduleName": "clientApp", "overrides": { "bootstrap": { "main": [ "less/bootstrap.less", "dist/css/bootstrap.css", "dist/js/bootstrap.js" ] } } } 

我还包括Gruntfile.js ,如下所示,这似乎表明它会自动使用bower.json参数来更新index.html的依赖项。 但是您可以看到Gruntfile.js以自动生成的语句开始,如下所示:

 // Generated on 2016-02-24 using generator-angular 0.15.1 'use strict'; // # Globbing // for performance reasons we're only matching one level down: // 'test/spec/{,*/}*.js' // use this if you want to recursively match all subfolders: // 'test/spec/**/*.js' module.exports = function (grunt) { // Time how long tasks take. Can help when optimizing build times require('time-grunt')(grunt); // Automatically load required Grunt tasks require('jit-grunt')(grunt, { useminPrepare: 'grunt-usemin', ngtemplates: 'grunt-angular-templates', cdnify: 'grunt-google-cdn' }); // Configurable paths for the application var appConfig = { app: require('./bower.json').appPath || 'app', dist: '../server/dist' }; // Define the configuration for all the tasks grunt.initConfig({ // Project settings yeoman: appConfig, // Watches files for changes and runs tasks based on the changed files watch: { bower: { files: ['bower.json'], tasks: ['wiredep'] }, js: { files: ['<%= yeoman.app %>/scripts/{,*/}*.js'], tasks: ['newer:jshint:all', 'newer:jscs:all'], options: { livereload: '<%= connect.options.livereload %>' } }, jsTest: { files: ['test/spec/{,*/}*.js'], tasks: ['newer:jshint:test', 'newer:jscs:test', 'karma'] }, compass: { files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], tasks: ['compass:server', 'postcss:server'] }, gruntfile: { files: ['Gruntfile.js'] }, livereload: { options: { livereload: '<%= connect.options.livereload %>' }, files: [ '<%= yeoman.app %>/{,*/}*.html', '.tmp/styles/{,*/}*.css', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' ] } }, // The actual grunt server settings connect: { options: { port: 9000, // Change this to '0.0.0.0' to access the server from outside. hostname: 'localhost', livereload: 35729 }, livereload: { options: { open: true, middleware: function (connect) { return [ connect.static('.tmp'), connect().use( '/bower_components', connect.static('./bower_components') ), connect().use( '/app/styles', connect.static('./app/styles') ), connect.static(appConfig.app) ]; } } }, test: { options: { port: 9001, middleware: function (connect) { return [ connect.static('.tmp'), connect.static('test'), connect().use( '/bower_components', connect.static('./bower_components') ), connect.static(appConfig.app) ]; } } }, dist: { options: { open: true, base: '<%= yeoman.dist %>' } } }, // Make sure there are no obvious mistakes jshint: { options: { jshintrc: '.jshintrc', reporter: require('jshint-stylish') }, all: { src: [ 'Gruntfile.js', '<%= yeoman.app %>/scripts/{,*/}*.js' ] }, test: { options: { jshintrc: 'test/.jshintrc' }, src: ['test/spec/{,*/}*.js'] } }, // Make sure code styles are up to par jscs: { options: { config: '.jscsrc', verbose: true }, all: { src: [ 'Gruntfile.js', '<%= yeoman.app %>/scripts/{,*/}*.js' ] }, test: { src: ['test/spec/{,*/}*.js'] } }, // Empties folders to start fresh clean: { dist: { files: [{ dot: true, src: [ '.tmp', '<%= yeoman.dist %>/{,*/}*', '!<%= yeoman.dist %>/.git{,*/}*' ] }] }, server: '.tmp' }, // Add vendor prefixed styles postcss: { options: { processors: [ require('autoprefixer-core')({browsers: ['last 1 version']}) ] }, server: { options: { map: true }, files: [{ expand: true, cwd: '.tmp/styles/', src: '{,*/}*.css', dest: '.tmp/styles/' }] }, dist: { files: [{ expand: true, cwd: '.tmp/styles/', src: '{,*/}*.css', dest: '.tmp/styles/' }] } }, // Automatically inject Bower components into the app wiredep: { app: { src: ['<%= yeoman.app %>/index.html'], ignorePath: /\.\.\// }, test: { devDependencies: true, src: '<%= karma.unit.configFile %>', ignorePath: /\.\.\//, fileTypes:{ js: { block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi, detect: { js: /'(.*\.js)'/gi }, replace: { js: '\'{{filePath}}\',' } } } }, sass: { src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'], ignorePath: /(\.\.\/){1,2}bower_components\// } }, // Compiles Sass to CSS and generates necessary files if requested compass: { options: { sassDir: '<%= yeoman.app %>/styles', cssDir: '.tmp/styles', generatedImagesDir: '.tmp/images/generated', imagesDir: '<%= yeoman.app %>/images', javascriptsDir: '<%= yeoman.app %>/scripts', fontsDir: '<%= yeoman.app %>/styles/fonts', importPath: './bower_components', httpImagesPath: '/images', httpGeneratedImagesPath: '/images/generated', httpFontsPath: '/styles/fonts', relativeAssets: false, assetCacheBuster: false, raw: 'Sass::Script::Number.precision = 10\n' }, dist: { options: { generatedImagesDir: '<%= yeoman.dist %>/images/generated' } }, server: { options: { sourcemap: true } } }, // Renames files for browser caching purposes filerev: { dist: { src: [ '<%= yeoman.dist %>/scripts/{,*/}*.js', '<%= yeoman.dist %>/styles/{,*/}*.css', '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', '<%= yeoman.dist %>/styles/fonts/*' ] } }, // Reads HTML for usemin blocks to enable smart builds that automatically // concat, minify and revision files. Creates configurations in memory so // additional tasks can operate on them useminPrepare: { html: '<%= yeoman.app %>/index.html', options: { dest: '<%= yeoman.dist %>', flow: { html: { steps: { js: ['concat', 'uglifyjs'], css: ['cssmin'] }, post: {} } } } }, // Performs rewrites based on filerev and the useminPrepare configuration usemin: { html: ['<%= yeoman.dist %>/{,*/}*.html'], css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'], options: { assetsDirs: [ '<%= yeoman.dist %>', '<%= yeoman.dist %>/images', '<%= yeoman.dist %>/styles' ], patterns: { js: [[/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']] } } }, // The following *-min tasks will produce minified files in the dist folder // By default, your `index.html`'s <!-- Usemin block --> will take care of // minification. These next options are pre-configured if you do not wish // to use the Usemin blocks. // cssmin: { // dist: { // files: { // '<%= yeoman.dist %>/styles/main.css': [ // '.tmp/styles/{,*/}*.css' // ] // } // } // }, // uglify: { // dist: { // files: { // '<%= yeoman.dist %>/scripts/scripts.js': [ // '<%= yeoman.dist %>/scripts/scripts.js' // ] // } // } // }, // concat: { // dist: {} // }, imagemin: { dist: { files: [{ expand: true, cwd: '<%= yeoman.app %>/images', src: '{,*/}*.{png,jpg,jpeg,gif}', dest: '<%= yeoman.dist %>/images' }] } }, svgmin: { dist: { files: [{ expand: true, cwd: '<%= yeoman.app %>/images', src: '{,*/}*.svg', dest: '<%= yeoman.dist %>/images' }] } }, htmlmin: { dist: { options: { collapseWhitespace: true, conservativeCollapse: true, collapseBooleanAttributes: true, removeCommentsFromCDATA: true }, files: [{ expand: true, cwd: '<%= yeoman.dist %>', src: ['*.html'], dest: '<%= yeoman.dist %>' }] } }, ngtemplates: { dist: { options: { module: 'clientApp', htmlmin: '<%= htmlmin.dist.options %>', usemin: 'scripts/scripts.js' }, cwd: '<%= yeoman.app %>', src: 'views/{,*/}*.html', dest: '.tmp/templateCache.js' } }, // ng-annotate tries to make the code safe for minification automatically // by using the Angular long form for dependency injection. ngAnnotate: { dist: { files: [{ expand: true, cwd: '.tmp/concat/scripts', src: '*.js', dest: '.tmp/concat/scripts' }] } }, // Replace Google CDN references cdnify: { dist: { html: ['<%= yeoman.dist %>/*.html'] } }, // Copies remaining files to places other tasks can use copy: { dist: { files: [{ expand: true, dot: true, cwd: '<%= yeoman.app %>', dest: '<%= yeoman.dist %>', src: [ '*.{ico,png,txt}', '*.html', 'images/{,*/}*.{webp}', 'styles/fonts/{,*/}*.*' ] }, { expand: true, cwd: '.tmp/images', dest: '<%= yeoman.dist %>/images', src: ['generated/*'] }, { expand: true, cwd: '.', src: 'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*', dest: '<%= yeoman.dist %>' }] }, styles: { expand: true, cwd: '<%= yeoman.app %>/styles', dest: '.tmp/styles/', src: '{,*/}*.css' } }, // Run some tasks in parallel to speed up the build process concurrent: { server: [ 'compass:server' ], test: [ 'compass' ], dist: [ 'compass:dist', 'imagemin', 'svgmin' ] }, // Test settings karma: { unit: { configFile: 'test/karma.conf.js', singleRun: true } } }); grunt.registerTask('serve', 'Compile then start a connect web server', function (target) { if (target === 'dist') { return grunt.task.run(['build', 'connect:dist:keepalive']); } grunt.task.run([ 'clean:server', 'wiredep', 'concurrent:server', 'postcss:server', 'connect:livereload', 'watch' ]); }); grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) { grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); grunt.task.run(['serve:' + target]); }); grunt.registerTask('test', [ 'clean:server', 'wiredep', 'concurrent:test', 'postcss', 'connect:test', 'karma' ]); grunt.registerTask('build', [ 'clean:dist', 'wiredep', 'useminPrepare', 'concurrent:dist', 'postcss', 'ngtemplates', 'concat', 'ngAnnotate', 'copy:dist', 'cdnify', 'cssmin', 'uglify', 'filerev', 'usemin', 'htmlmin' ]); grunt.registerTask('default', [ 'newer:jshint', 'newer:jscs', 'test', 'build' ]); }; 

你忘记了save标志。

再次运行它为:

 bower install angular-bootstrap --save 

然后看看bower.json ,它应该有增加的依赖

注意 :这个答案使用了Gulp ,我知道你害怕wiredep github仓库中提到的UNMAINTAINED。 但是这是给你一个出发点,我相信你可以在Gruntfind等价的:

您可以使用wiredep (与Gulp一起使用):

 npm -i --save-dev wiredep gulp 

将其添加到.bowerrc文件中:

 { "scripts": { "postinstall":"gulp wiredep" } } 

并在你的Gulpfile.js

 gulp.task('wiredep', function() { // see wiredep website for the full options list var options = { bowerJson : require('./bower.json'), directory : './bower_components/', }, wiredep = require('wiredep').stream; console.log('Wiring bower dependencies'); gulp.src('./index.html') .pipe(wiredep(options)) .pipe($.inject(gulp.src('./app/**/*.js', { read: false }))) .pipe(gulp.dest('./')); }); 

和你的index.html文件:

 <html> <head> <!-- bower:css --> <!-- endbower --> </head> <body> <!-- bower:js --> <!-- endbower --> </body> </html> 

在terminal中运行gulp wiredep会将./bower_components文件夹中的每个库注入到bower:jsbower:css标记之间的index.html文件中。