以下是来自 Helios Design Labs 的 Dan Sundy 的客座文章。 Dan 将解释如何使用 Bower 以及为何要使用它,并从一开始就抵制这个想法的视角出发。
当我第一次开始使用 Bower 时,我并没有完全理解它的吸引力。“真的吗?”我想。“现在下载和解压缩文件太麻烦了?”我也不是很兴奋要把一堆新的命令塞进一个已经塞满了 Git、Grunt、Gulp、Jekyll、Node 等命令的大脑里。
有两件事我想告诉半年前的自己。首先,Bower 可以做的不仅仅是下载一两个文件。其次,花一个小时学习一个可以消除重复任务的工具是值得的。
首先:Bower 到底是什么?
对于新手来说,Bower 是一个包管理器。它擅长管理包——任何你依赖外部作者提供的包。好的例子包括 Bootstrap 这样的 CSS 框架、jQuery 这样的库、jQuery 插件或 Angular 这样的 JavaScript 框架。Bower 的官方网站 Bower.io 可能说得最好。
网站由很多东西组成——框架、库、资源、实用程序和彩虹。Bower 为你管理所有这些东西。
Bower 通过从各处获取和安装包来工作,负责搜索、查找、下载和保存你正在寻找的东西。
先决条件
在开始使用 Bower 之前,你需要一些东西。
- 命令行。是的,它是一个命令行工具(来吧,它没有那么可怕)。
- Node 和 NPM。Bower 是一个 Node 模块,因此要获取它,你需要 NPM。
- Git。Bower 包是 Git 仓库。Bower 使用 Git 来了解包在哪里,它的版本是多少——诸如此类的事情。
- 全局安装。从技术上讲,你可以在每个项目中安装它,但你可能希望在任何地方都拥有它。
要全局安装 Bower,请执行以下操作
$ npm install -g bower
注意:根据你的设置,你可能需要使用 `sudo npm install -g bower` 来全局安装它。
基础知识
首先,想象一下新网站的目录结构。我的通常如下所示
|-.git/
|-dist/
|-node_modules/
|-src/
| |-assets/
| |-css/
| |-fonts/
| |-js/
| | |-lib/
| | |-main.js
| |
| |-sass/
| | |-style.sass
| |
| |-index.html
|
|-.gitignore
|-gulpfile.js
|-package.json
|-README.md
有一个 `src` 文件夹,其中包含大部分开发工作。Gulp 构建任务最终将准备所有内容并将我们优化的代码编译到一个生产就绪的 `dist` 文件夹中。
假设你想在这个项目中包含 jQuery。通常,你会去 jquery.com,找到并点击正确的下载链接,然后解压缩并将文件放到正确的目录中。
使用 Bower,只需运行以下命令
$ bower install jquery
现在,一个包含 `jquery` 文件夹的 `bower_components` 目录出现了。
|-.git/
|-bower_components/
| |-jquery/
|
|-dist/
|-node_modules/
|-src/
| |-assets/
| |-css/
| |-fonts/
| |-js/
| | |-lib/
| | |-main.js
| |
| |-sass/
| | |-style.sass
| |
| |-index.html
|
|-.gitignore
|-gulpfile.js
|-package.json
|-README.md
jQuery 通过为 Bower 创建和注册一个包,使获取其代码变得容易。大多数流行的库和框架都做了同样的事情。如果你想检查你想要的资源是否是一个 Bower 包,你可以进行搜索
$ bower search <package-name>
如果它没有注册,仍然可以使用像这样的 git 端点来获取仓库
$ bower install git://github.com/example-user/example-package.git
高级:如果你想变得花哨,你甚至可以安装你有权访问的私有仓库。查看 Rob Dodson 的 此视频教程。
以下是一些其他基本命令,你可以使用它们来查看和管理已安装的资源。
列出所有包
$ bower list
获取有关已安装的任何包的信息
$ bower info <package-name>
使用以下命令检查更新
$ bower check-new
然后,如果有更新,更新一个包
$ bower update <package-name>
但也许更新到最新版本破坏了一些东西。
使用以下命令安装任何特定版本——旧的或新的
$ bower install <package-name>#<version>
这绝对不是一个详尽的列表。如果你有兴趣入门,我建议你创建一个测试项目并完成在线上可以找到的众多教程之一。Treehouse 的这个教程很棒:Bower 入门。然后,你可以通过查看 Bower 的 API 来深入了解所有命令。
等等,还有更多!
我工作的这个小型开发团队在过去一年左右的时间里一直在使用 Bower。虽然通过命令行进行包管理很棒,但我直到我们开始使用 `bower.json` 和 `.bowerrc` 文件时才真正信服。
.bowerrc
`.bowerrc` 文件可以做很多事情,但我主要看到它用于更改 `bower_components` 目录的名称和位置。(这让我很高兴,因为我讨厌在项目根目录中到处都是那个随机的 `bower_components` 文件夹)。
以下是一个 `.bowerrc` 文件的示例
{
"directory": "src/components"
}
directory 选项将包发送到最合理的位置——在本例中,是 `src/` 目录。看看新的项目结构
|-.git/
|-dist/
|-node_modules/
|-src/
| |-assets/
| |-components/
| | |-jquery/
| |
| |-css/
| |-fonts/
| |-js/
| | |-lib/
| | |-main.js
| |
| |-sass/
| | |-style.sass
| |
| |-index.html
|
|-.gitignore
|-.bowerrc
|-gulpfile.js
|-package.json
|-README.md
请注意,`bower_components/` 文件夹不见了,并且在 `src/` 目录中有一个 `components/` 文件夹。
高级:最好使用类似 gulp-usemin 或 grunt-usemin 的工具来处理所有额外样式和脚本的连接和缩小。
那么 `bower.json` 文件如何帮助我们呢?
bower.json
`bower.json` 文件看起来很像 Node 的 `package.json`。它是一个清单文件,允许你指定选项。让我们看一个示例(可以通过运行 `bower init` 生成)
{
"name": "bower-example",
"version": "0.0.0",
"authors": [
"author <[email protected]>"
],
"description": "An example project using bower.",
"main": "index.html",
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"devDependencies": {
"jquery": "~2.1.1"
}
}
如果你正在将此仓库注册为 Bower 包,则其中许多选项都存在。但请查看最底部的 `devDependencies` 对象?如果你将 `--save-dev` 附加到 Bower 命令(如下所示),该对象将自动更新
$ bower install jquery --save-dev
现在,如果同事运行 `bower install`,计算机将安装 `.bowerrc` 中指定文件夹中 `devDependencies` 列表中的所有内容。类似地,如果一个开发者使用 `--save-dev` 添加了一个包或更新了一个包版本,整个团队可以通过 `bower install`(在拉取最新版本的 `bower.json` 文件后)同步他们的资源。
由于 `bower.json` 文件消除了所有搜索和收集工作,因此不再需要对任何这些资源进行版本控制。可以将 `components/` 文件夹添加到 `.gitignore` 文件中,以保持你的仓库**精简**和**高效**。
*.DS_Store
.sass-cache
node_modules/
dist/
src/components/
结语
我正在听我最喜欢的 web 开发播客(眨眼,眨眼)的 一期节目,主持人正在讨论 Bower 是否真的有用,或者只是一个昙花一现。他们想知道它的目的是简化下载还是用于更新库的版本,就像 ruby gems 一样。他们谈到它是一个“前端 NPM”(我正在转述)。
美妙之处在于,它确实可以完成所有这些事情。你可以用它来下载和保持代码更新,但你可以更进一步。Bower 可以帮助你保持项目库和框架的同步,或者将其与其他工具(如 Yeoman)集成,以节省更多开发设置时间。此外,你可以创建和注册你自己的 Bower 包,以便你可以在所有项目中快速(安全地)安装和更新它们。
哦,关于 引发讨论的问题:你不会使用 Bower 来安装 WordPress,并且 WordPress 不应该放在你的 `bower_components` 文件夹中。但是你可以在你的 WordPress 主题中使用 Bower 来管理外部资源(只是不要加载 WordPress 核心已经包含的库,比如 jQuery)。
我知道有很多Sublime Text爱好者(包括我)。我的朋友Ben Schwarz做了一个用于Bower的Sublime Text插件,所以你可以直接在Sublime中搜索并安装Bower包,就像通过Package Control安装Sublime包一样。
在一些项目中使用过Bower之后,现在我更经常地将我的
script
标签链接到CDN托管的库——Google的CDN,BootstrapCDN用于Bootstrap,以及CDNJS用于几乎所有其他库。这种方法与Bower相比如何?我认为CDN最初的吸引力主要来自三方面:1.轻松引入第三方资源。2.用户很可能已经缓存了[该版本的jQuery或其他库],因为他们可能访问过使用相同CDN的其他网站。3.分布式CDN,实现快速下载。
不过,CDN也有一些不足之处;例如,偶尔会发生ISP意外阻止热门CDN IP地址的情况,需要离线工作等。上面第2点的好处通常会被jQuery存在于许多不同的CDN上且版本众多这一事实所抵消,从而降低了从缓存中获益的可能性。此外,现在CSS/JS中有很多第三方工具。因此,您的项目使用的工具组合很可能需要几个HTTP请求,在我看来,这也抵消了CDN带来的好处。
Bower很棒,因为它[对于喜欢命令行的人来说]与引入CDN一样简单,我可以离线工作,我不必担心ISP。我最喜欢的理由是:由于文件是本地的,我可以将JS连接并压缩到一个文件中——如果这一点不清楚,我的jQuery、Handlebars、Backbone、Underscore和我的应用程序特定JS都在一个文件中,因此永远不会超过1个HTTP请求。它会在用户的计算机上被缓存。Gulp/Grunt允许在设置完成后轻松完成此过程。最后,我可以将该文件托管在我自己的分布式CDN上以提高速度。
将所有资产存储在本地与使用CDN相比,主要优势在于可以连接和预/后处理它们。连接可以减少HTTP请求数量,这通常是一件好事,可以提高性能。至于预/后处理,如果您不需要Bootstrap这样的框架的全部内容,可以获取它的Less源代码,注释掉不需要的部分,并在您的端进行编译,从而获得更小的代码库。此外,您可以使用Autoprefixer等工具,确保只为支持的浏览器添加必要的属性前缀。
当然,CDN通常更容错且更稳定,而且您可以在全球范围内更快地获取资产,但是如果您真的重视网站的性能,没有什么可以阻止您自己使用CDN来托管自己的资产。
Brad和Alex,虽然我完全意识到jQuery托管在多个CDN上,但我认为有人会使用除Google之外的任何其他CDN。哎呀,我们上次看到微软托管的jQuery是什么时候?
现在,我并不是特别喜欢将所有脚本连接到一个大文件中。虽然它可以节省多个HTTP请求,但用户必须从一个网站到另一个网站反复下载库(jQuery、Backbone、Handlebars等)。恕我直言,这对互联网的健康发展不利。那些最大的公司并不是无缘无故提供免费CDN的。
此外,这不仅仅是HTTP请求的数量问题。速度(Brad的第3点)也很重要。由于CDN从最靠近用户的服务器提供文件,并且它们的服务器往往比我们的服务器具有更好的连接,因此我认为在速度测试中CDN胜出。更不用说带宽了,我亲眼看到每个页面加载节省几KB如何帮助节省账单。
也就是说,在某些情况下,使用CDN并非明智之举。例如,中国的一些ISP阻止(过)CDNJS。我吃过这个亏。
@Alex jsDelivr OSS CDN可以连接JS和CSS。我认为您关于Bootstrap之类的库的说法是正确的;最好构建特定于网站的CSS。
@Phan:我同意不连接较大和流行的库(如jQuery、D3)是一个好主意,我认为将较小的库与其依赖项连接起来是明智的。除了减少一个HTTP请求外,请记住,单个文件的GZip可能比多个单独的文件加在一起略小。
在我看来,“Bower的理由”归结为
然后,针对这些观点的反驳理由归结为
bower install
才能确保一切正常。我还没有完全信服,对我个人和我自己的项目而言,但我确实有了更深入的了解,并且可以想象在哪些团队/工作流程中Bower会受到喜爱。感谢Dan!
归根结底,工作流程都取决于个人喜好。有些人喜欢PC,有些人喜欢Mac;有些人喜欢Sublime Text,其他人喜欢Coda;有些人坐着工作,有些人站着工作。
我认为底线是:使用感觉舒适的工具(这些工具最终会加快项目进度)。
但如果有一些东西可以在
git pull
时通知您bower.json
文件的更改,并提示您运行bower install
(而无需阅读文件更改输出),那就很酷了。嗯……有人知道吗?谢谢,Chris!
我最大的问题是Bower会下载整个存储库,有些库将其代码放在根目录中,有些放在src中,有些有压缩/未压缩文件夹等等。因此,在我能够运行minify任务之前,我必须为打算使用的每个脚本配置其路径(如果以后添加新的依赖项,我还会再次进行配置)。
但对于有多个供应商脚本的项目来说,它绝对很有用,并且如果使用整个npm/grunt/gulp/yeoman/自动化所有事物的设置,使用它会感觉很自然。
Dan,
只需执行
即可。这应该不会花费太长时间:)
作者似乎在使用
devDependencies
而不是dependencies
(以及--save-dev
而不是--save
)时犯了一个错误。前者用于单元测试和其他构建工具,而后者用于生产中使用的依赖项(本文应使用后者)。有关差异的更多信息,请参阅此StackOverflow!感谢您指出这一点,wooorm。您说得对,像jQuery和Bootstrap这样的东西应该放在dependencies中,这表示开发时也需要它们。
当然:)
我与一个小型团队合作,其中一些人比前端开发人员更偏向于后端开发。对于某些人来说,命令行是一个可怕的地方,因此为了简化操作,我在我们的
package.json
文件中添加了一个scripts部分,用于更新ruby sass、node_modules和我们的bower组件。他们现在的工作流程非常简单
npm run update
我使用CodeKit进行Bower操作。我猜它的功能不如命令行强大,但对我来说已经足够了。目前我需要学习的东西太多,没有时间学习新的命令行指令。
而且CodeKit也充当任务管理器,使用起来非常简单。所以我很满意。
我是Bower的粉丝,在与团队合作时遇到了一些问题……主要是“不同步”问题。
场景:(/bower_components未检入存储库,…但bower.json已检入)
开发人员A通过Bower添加mustache.js
在构建过程中,开发人员A的mustache.js文件被压缩并连接到主脚本文件中。
开发人员A将更改推送到存储库
开发人员B拉取并获取最新文件,在构建过程中,grunt/gulp由于缺少依赖项而出现错误。(第1步中的/bower_components/mustache.js)
开发人员B必须停止操作并手动运行bower install,然后构建。
就像/node_modules一样,我喜欢将这些东西保留在存储库之外,因此团队沟通是这里的解决方法:“嘿,开发人员B,…我刚刚通过Bower添加了mustache.js,…请确保运行bower install”(感觉很传统,但有效)
Git Hook解决方法
另一种选择是在拉取后运行Git Hook。我使用Sindre Sorhus编写的这个很棒的post-merge git hook取得了成功,该hook可以通过命令行使用。
你可以将合并后的文件放入
.git/hooks
目录中,然后在拉取代码后,它会自动运行bower install
或npm install
(如果需要)。非常酷!Git Tower用户
我个人使用Git Tower进行.git操作,但还没有找到可靠的解决方法。上面提到的钩子在拉取/合并后不会触发。我甚至幸运地直接与Git Tower团队合作,试图找到一个可用的钩子,但没有成功。(非常感谢Git Tower抽出时间帮忙!!)
问题归结为需要在钩子中正确设置shell环境,而我的bash脚本技能为0。 Git Tower钩子
另一个问题 - 修改后的Bower组件文件
我遇到的另一个小问题是,当需要修改/bower_components文件夹内的文件时。例如,Sass Bootstrap(它非常棒,允许你将整个框架精简到每个组件中仅需要的部分,并使用方便的导入.scss文件)可能会被修改,并且由于/bower_components不在仓库中,其他团队成员无法保持同步。
对于你认为组件将要被修改的这些情况,我喜欢将它们从/bower_components移到项目文件夹中。
/bower_components中的文件通常不会被修改,因此这通常不是问题。
NPM vs. Bower
有些人可能会争辩说,你可以在NPM中完成Bower的所有操作,但我喜欢将我的“前端”类型的东西放在Bower中,将我的“node”类型的东西放在NPM中。
你的“修改后的Bower组件文件”问题也困扰着我。在我的案例中,我可以接受Bootstrap的默认文件并将所有内容添加到项目中,但我的问题是我使用Sass并将所有内容包含在main.css中,许多Bower组件只带有.css文件,据我所知,不能像在main.css中那样包含。
好吧,我不想成为一个唱反调的人,但你可以用命令行完成所有这些操作。我使用powershell(或bash)来编写网站模板、npm和git。只是不明白Bower的意义,或者我弄错了吗?
我大约一年前开始使用Bower,主要是因为我感兴趣的许多开源项目都在使用它。像其他所有东西一样,它也存在学习曲线。
尽管令人沮丧,但我喜欢Bower(以及Yeoman、Grunt、NPM)的一点是,它的文档非常完善,并且有及时的内容(通常是博客文章)用简单的英语解释几乎所有内容。
模糊依赖匹配也非常好。
能够指定
common-library.js ~3.2
(是的,这确实是NPM
的一个特性),并让Bower安装一个可用的版本,而无需过于具体,这很棒。最初更新/升级给我带来了很多头痛(“如果它没有坏,就不要更新它”),但安装不同工具/库的便捷性以及它广泛的采用和支持说服了我。
我对命令行不太熟悉,而且我通常不尝试“调试”事物,因此拥有一个强大的社区使用、编写和支持Bower对我来说意义重大。
如果你使用Bower,你可能也希望使用“wiredep”:一个有用的功能是它可以聚合来自Bower模块的文件,因此你可以拥有一个gulp任务,将所有js文件连接到一个依赖项包中(或所有css等)。
如果Bower模块在其“main”属性中没有指向正确的文件,
你可以在bower.json中每个模块覆盖它。
示例: https://medium.com/@mattdesl/gulp-and-browserify-shim-f1c587cb56b9#038f
Cecile,我非常喜欢你的图标……太棒了
我将回应这里其他评论者之一,并说我真的很不喜欢Bower获取的所有文件。作为测试,我使用Bower获取了jQuery。它下载了111个项目/1.1兆字节。然后我获取了jQuery Mobile。它是3.3兆字节,包含380个项目。我知道jQM,我甚至无法弄清楚如何实际指向资产以便在我的项目中使用它。我假设这是我可以解决的事情,但我不知道为什么所有这些额外的资产都被获取了。也许如果我打算手动构建JQM,但我会争辩说这是一种罕见的情况(大多数人使用库X,只有少数人实际在库X上工作)。
至少对我而言,如果我必须在Bower中查找实际的库文件在哪里,而不是仅仅获取一个更精简的zip文件,那么它实际上会增加我的开发时间。
例如,以及免责声明,我编写了这个(微笑),我为Brackets编写了一个扩展,它获取库并仅获取实际使用库所需的最小内容: https://github.com/cfjedimaster/brackets-jsdownloader
package.json中有一个“files”区域。也许这会有用?
https://docs.npmjs.net.cn/files/package.json#files
我将Bower与Gulp一起使用。我运行bower install来获取我需要的Bower包,然后我有一个任务可以将实际文件(也许只是.js文件或.scss文件)从bower_components/移动到我实际需要的位置。
现在我已经编写了这个任务一次,我不需要再次执行它,除非更新该任务以包含我需要的任何其他包。
我已将Bower用于一些个人项目(诚然,已经有一段时间了),我还没有被说服。除非我遗漏了什么,否则Bower只是下载git仓库。它没有消除使用第三方前端库的实际痛点,即深入挖掘这些仓库并找到你关心的那一个或两个文件。
将其与npm+Browserify进行比较。使用npm,第三方项目的结构无关紧要。你只需
npm install
和require()
,就可以开始了。此外,Browserify鼓励你使用CommonJS模块来组织你的代码,从而消除了对IIFE的需求。现在npm将尝试变得更友好地支持前端包,Bower的理由可能看起来略有不同。
我想对我来说,使用npm进行前端包的理由是将它们与browserify(用于JS资产)一起使用——类似于Michael上面所说的。
对于这篇文章,如果能有一个深入的后续文章来解释Bower和npm在前端包方面区别,将会很有趣。我认为最大的区别在于Bower更扁平的结构。
我很少使用Bower。我的工作流程的问题在于,有时我最终会想要/需要修改Bower组件中的文件,因为个人偏好或必要性。有时你需要自定义不同的组件以使它们在你的项目中很好地协同工作。如果组件被修改,那么我以后无法使用Bower自动更新它。此外,在开始一个新的网站项目时,我更有可能再次重用修改后的组件,而不是安装未修改的最新版本。这可能取决于项目的重要性。它是否值得更新到可用的最新代码库。
我也同意有些组件安装了太多文件。我个人有一个“vendors”文件夹,我在其中手动安装组件(来自github的zip文件)到它们自己的文件夹中,以及我认为有益的其他文件(许可证、文档、示例)。但总的来说,我通常会删除很多包含的文件。
精彩的文章。有些人喜欢探索Grunt(JS任务运行器),它与Bower配合得非常好。
不错的文章,但为什么不能只使用npm来获取你需要的依赖项呢?当已经有了npm时,为什么要下载第二个javascript包管理器Bower呢?
正在进行使NPM更友好地支持前端的工作。
http://blog.npmjs.org/post/101775448305/npm-and-front-end-packaging
许多人正在转向NPM来缓解其他需求。
http://blog.kewah.com/2014/npm-as-a-front-end-package-manager/
我很喜欢Bower和NPM团队(看似)在紧密合作这件事。
https://github.com/bower/bower/issues/1520
如果你想在每次拉取后检查Bower包更新,可以使用git钩子。在http://www.git-scm.com/book/en/v2/Customizing-Git-Git-Hooks了解更多信息。
Bower的精彩介绍。但是,我不同意你选择的目录结构。我不会将通过Bower安装的第三方脚本放在
src/components
中,因为这些脚本在技术上不是应用程序源代码的一部分。它们是供应商脚本,我更希望看到它们与node_modules
目录在层次结构中处于相同的位置。当然,将名称从bower_components
更改为任何其他名称都是完全可以接受的。抱歉做了“那个家伙”。