Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[译] NPM 与前端包管理 #57

Open
cssmagic opened this issue Feb 7, 2016 · 11 comments
Open

[译] NPM 与前端包管理 #57

cssmagic opened this issue Feb 7, 2016 · 11 comments

Comments

@cssmagic
Copy link
Owner

cssmagic commented Feb 7, 2016

[译] NPM 与前端包管理

We've known for a while that front-end asset and dependency management is a huge use-case for npm and a big driver of Node.js adoption in general. But how big, exactly? It's a hard question to answer. The list of most-downloaded packages on npm is not very helpful: packages like async, minimist and request are the bread-and-butter packages that are depended upon by thousands of other packages, so of course they get installed and downloaded all the time as part of the installations of those packages.

我们很清楚,前端资源及其依赖管理一直是 npm 的重度使用场景,同时这也一直是 Node.js 普及的重要推动力。但这类应用场景到底有多重度?这是一个很难回答的问题。这份 “npm 最常下载的包的清单” 并不能提供有效的证据:因为像 async、minimist 和 request 这样的包就像是 “生活必需品”,它们会被数以千计的其它包所 依赖,这样一来它们当然会随着那些依赖它们的包一起被不停地下载。

A more interesting and revealing question is: what packages do people explicitly install? By which we mean, how many times did somebody (or some robot) actually run the command npm install thispackage? We recently started plugging our log data into Jut, which has made it easy and quick to answer these questions for the first time. The resulting list of the top 50 explicitly-installed npm packages is very different and very interesting. 32% of the packages in the top 50 (and 50% of the actual downloads) are front-end tools or frameworks, with Grunt, Bower and Gulp leading the pack (mobile is also a huge use-case, and we'll be talking about it in a later blog post). Plus, usage of all these packages is growing steadily:

更有意义也更接近真相的问题是:哪些包是人们主动安装的?所谓 “主动安装”,就是指某个人(或某个机器人)以实际运行 npm install thispackage 命令的方式来安装一个包。不久前,我们开始把日志数据加入到 Jut 中,随后我们终于可以方便而快速地给出这个问题的答案了。最终,我们得到了 “最常主动安装的 npm 包五十强榜单”,这份榜单画风突变,很有意思。在五十强中有 32% 的包(它们产生了 50% 的实际下载量)都是前端的工具或框架,携 Grunt、Bower 和 Gulp 一起遥遥领先(当然移动端也是一大重度应用,这里暂且不表)。此外,这些包的使用量也在稳步增长:

Client-side tools growth, Jan-October 2014

(客户端工具的增长,2014 年 1 月~10 月)

The other way we know front-end is a huge use-case is that we get a lot of questions (and issue reports) from users of npm and web developers about how best to use npm to manage client-side dependencies. These questions often have some incorrect assumptions that are strange to us, so let's be big and bold about refuting them:

另一个渠道也佐证了前端是重度使用场景的这一事实——我们从 npm 用户和 web 开发者那里收到了大量关于如何用 npm 来管理好客户端依赖的提问(和故障反馈)。这些问题通常都伴有极其主观的偏见,令我们感到相当诧异。好吧,那就让我们严肃认真地来澄清一下:

1. "npm is only for CommonJS!"

1. “npm 只是为 CommonJS 服务的!”

Not true. npm would like to be the package manager for JavaScript, so if it's JavaScript related, the npm registry is a good place to put it. Node.js provides a CommonJS-esque module environment, but npm has no feelings on the matter.

不对。npm 希望成为 JavaScript 的包管理器,因此,只要是跟 JavaScript 相关的,都适合放入 npm 的包仓库(registry)。虽然 Node.js 提供了一个 “CommonJS 式” 的模块环境,但 npm 对此并不关心。

2. "npm is only for server-side JavaScript!"

2. “npm 只是为服务器端的 JavaScript 服务的!”

Also not true. Your package can contain anything, whether it's ES6, client-side JS, or even HTML and CSS. These are things that naturally turn up alongside JavaScript, so put them in there.

同样不对。你的包可以包含任何内容,不论是 ES6、客户端 JS,还是 HTML 和 CSS。有很多东西天生就是跟 JavaScript 绑在一起的,那就把它们都放进来吧。

npm's code of conduct defines a very short list of things we don't think are appropriate to put in packages (TLDR: don't use us as your database, or your media server) but if in doubt, just ask us on Twitter or email and we'll be happy to weigh in.

npm 的 《行为准则》 总结了一份非常简短的列表,列出了我们认为不适合放进包里的东西(简单来说:不要把 npm 当作你的数据库或多媒体服务器来用)。对此如有疑问,请通过 TwitterEmail 询问,我们乐于讨论。

npm's philosophy

npm 的哲学

npm's core value is a desire to reduce friction for developers. Our preferred way to do this is by paving the cowpaths. That is to say: we don't like to tell you what to do. We like to find out what you're doing, and then get the obstacles out of your way. If lots of people are doing different things, we try to avoid picking a winner until it's obviously the best.

npm 的愿景是帮助开发者减少摩擦。我们倾向于通过 “循踪辟径” 的方式来实现这一点。这句话的意思是说:我们不希望告诉用户该怎么做;我们希望观察用户是怎么做的,然后把障碍扫清。如果很多人都是在以各自不同的方式在行事,那我们不会轻易地从中挑出一个胜者,除非最佳实践已经昭然若揭。

So, when it comes to front-end packages, where is the friction, and what are the cowpaths?

那么,在前端包管理的领域中,用户遇到的阻力究竟在哪里?用户踩出的 “踪” 又是怎样的?

Front-end pain points

前端痛点

In addition to GitHub issues and users on IRC, Twitter, conferences and meetups, we've also spoken directly to developers on some of the bigger frontend packages like Angular and Ember (both of which are also in the top 50). They didn't all agree on solutions but their pain points were roughly in common. Let's look at them, and then talk about how to tackle them:

除了 GitHub issue 以及 IRC、Twitter、技术会议和线下聚会中的用户以外,我们还会跟一些大型前端包的开发者们直接对话——这其中包括 Angular 和 Ember 的开发者(这两者都位列五十强)。他们在解决方案上并不完全一致,但他们的痛点却是大体相同的。接下来我们会一一展开,并讨论如何攻克这些难题:

1. node_modules isn't arranged the way front-end packages need it to be

1. node_modules 目录并不是按照前端包所需要的方式来组织的

This is a pretty obvious problem. The node_modules folder is where npm puts packages by default, to take advantage of the Node.js module loading semantics. Depending what packages you install, packages end up in different places in the tree. This works great for Node, but HTML and CSS, for better or worse, generally expect things to be in one location, like /static/mypackage. There are workarounds for this to be sure, but no first-class solution yet.

这是一个非常明显的问题。node_modules 目录是默认情况下 npm 存放包的地方,它得名于 Node.js 的模块加载行为。根据你安装的包的具体情况,所有包最终会被存放在目录树的不同位置。这对于 Node 来说一切良好,但对于 HTML 和 CSS 来说,不管怎样,我们通常都期望所有东西可以汇总在同一个地方,比如 /static/mypackage 这样的目录下。肯定有一些变通方法可以绕过这个问题,但还算不上是最佳方案。

2. Front-end dependencies have different conflict-resolution needs

2. 前端依赖在解决冲突方面具有截然不同的需求

One of the joys of the Node module loader is that it allows you to have multiple, incompatible versions of the same module present at the same time, and the one of the joys of npm is that it puts these versions into the right places so that the version you were expecting gets loaded where you expected it. This goes a long way towards eliminating "dependency hell" and is one of the reasons Node's "many small modules" pattern is so practical and so popular.

Node 模块加载器的一个有意思的地方在于,它允许你同时使用同一个模块的多个不兼容版本;而 npm 的一大有意思的地方在于,它可以将包的这些不同版本放置在合适的地方,从而做到在想要的地方加载想要的版本。这种方式对于避免 “依赖地狱” 有很大帮助,同时这也是 Node 的 “大量小模块” 的实践模式如此实用且流行的原因之一。

But front-end dependencies simply don't work this way. If you load two versions of jQuery one will "win". If you load two versions of the Bootstrap CSS framework they will both apply simultaneously and wreck your styling. In the future, new developments in HTML like web components and Shadow DOM may help resolve these problems, but at the moment, front-end dependencies can conflict. How do we recognize and handle that gracefully?

但前端依赖却是无法以这样的方式来运作的。如果你在网页中同时加载两个版本的 jQuery,那其中只有一个会 “胜出”。如果你同时加载了两个版本的 Bootstrap CSS 框架,它们会同时起作用,然后把页面样式搞得一团糟。在未来,HTML 将获得新的特性(比如 web components 和 Shadow DOM),也许有助于解决这类问题;但在眼下,前端依赖会发生冲突。那我们如何优雅地判别并解决这个难题呢?

3. Maintaining multiple package manifests is annoying

3. 同时维护多个包清单是很烦人的

The solution to the previous problems has been to create additional registries for front-end packages, but this has created a situation where a single project must have a package.json, a bower.json, a component.json, and so on, and edit them all every time even a minor update happens. Like all data duplication, this is tedious and error-prone.

前两个问题其实已经有了一种解决方案,就是为前端包额外配备其它的包管理方案。但这会产生这样一种局面——单个项目可能会同时包含一个 package.json 文件、一个 bower.json、一个 component.json 等等。每当遇到哪怕是一丁点儿更新时,你都要把所有这些配置文件通通编辑一遍。跟所有的数据冗余一样,这种情形不仅烦人,而且容易产生错误。

4. Finding browser-compatible packages is a pain

4. 找到兼容浏览器的包很痛苦

npm is the registry for JavaScript, but at the moment most of what's in the registry is Node.js. Some of those modules work when adapted for clients using modules like browserify, but some of them don't. At the moment there's no way to easily find out which do and which don't without trying them out.

npm 是为 JavaScript 服务的包仓库,但目前库中绝大多数的包都是 Node.js 包。在采用 Browserify 等工具做过适配之后,某些模块是可以在客户端运行的,但还有很多仍然是不行的。目前,如果要判断某个包是否在浏览器端可用,除了实测,似乎还没有一种简单易行的方法。

Front-end solutions

前端解决方案

With those four problems in mind, let's talk about how we can solve them.

在找出了以上四个难题之后,让我们来逐一讨论如何解决。

The final problem mentioned is the easiest to tackle, and we have already started laying the groundwork for the solution: ecosystems.

上面提到的最后一个难题是最容易克服的,我们已经开始为解决方案奠定基础了。这个解决方案就是:生态圈

Ecosystems are searchable subsets of the registry, defined by programmatically filtering all the packages in the registry according to some criteria like "works in a browser" or "runs on Windows" or "is compatible with Express" or a million other possibilities. Once launched, one ecosystem will definitely be "browserify compatible", and other definitions of "client-side friendly" will definitely be implemented as well. We're really optimistic that this will be a great solution, which leaves us with the first three, harder problems.

生态圈是指包仓库的一些可搜索的子集,这些子集是通过程序化地筛选库中的所有包而产生的,筛选条件是诸如 “可在浏览器中运行” 或 “可在 Windows 上运行” 或 “兼容 Express” 等数以百万计种可能性。此功能一旦上线,必将会有一个叫作 “兼容 Browserify” 的生态圈,而其它名称比如 “对客户端友好” 也肯定会出现。这将是一个非常棒的解决方案,我们对此非常乐观。接下来,让我们着手处理剩下的三个难题。

Client-side package installation and dependency resolution

客户端的包安装与依赖解析

The third problem – multiple sets of package metadata – is a side-effect of solutions to the first two. People have written third-party tools to solve the problems of installation and dependency resolution for client-side packaging, and while doing so they have often created their own independent package registries and metadata formats. There are a whole bunch of these solutions, each with their own pros and cons. But, as you can see from our usage data the most popular solution by far is Bower. So with apologies to the great ideas in the other package managers, we're going to focus on what Bower does.

第三个问题——多套包管理系统——实际上是前两个问题的副作用。现在已经有一些第三方工具试图缓解客户端的包安装和依赖解析问题,它们通常需要建立各自独立的包仓库和配置文件格式。这类解决方案层出不穷,每一种解决方案都有其长处和短处。不过,从上面的统计数据中可以看出,目前为止,在这方面最流行的解决方案是 Bower。那么接下来,请允许我们暂时忽略其它优秀的包管理器,重点关注一下 Bower 是如何工作的。

Bower's solution

Bower 的解决方案

Bower can install packages by name, from Git URLs, or from arbitrary HTTP URLs, just like npm. Unlike npm, they are all installed into a single, flat directory structure under bower_components, e.g. if backbone requires underscore, bower install backbone puts both backbone and underscore into bower_components directly. This means referring to a component from a web app is very simple, because it will always be installed in the same place, unlike npm, where your exact install path can vary.

Bower 可以通过名称来安装包,也可以通过 Git URL 或任意 HTTP URL 来安装,这些都跟 npm 是一样的。但跟 npm 不同的是,Bower 会把每个包都安装到 bower_components 目录下的独立目录中,整个目录结构是扁平的。举例来说,如果 backbone 依赖 underscore,那么 bower install backbone 将会把 backbone 和 underscore 这两者都放置在 bower_components 目录下。这意味着,从一个 web 应用中引用一个组件是非常简单的,因为它总是会被安装在相同的地方——这跟 npm 不同,因为 npm 包的实际安装路径并不固定。

This flat package structure means that if you attempt to install two incompatible versions of the same library – say, jQuery 1.11.1 and 2.1.1 – they attempt to install to the same location, and conflict. If this happens, Bower asks you to manually select which one you prefer, and can optionally persist this selection to bower.json. This is nondeterministic, in that it relies on a human decision, so two people installing the same packages can end up with different sets of packages. But once you persist your selections to bower.json it is consistent – anybody installing your project will get the same packages.

扁平的目录结构存在一个问题,如果你试图安装同一个库的两个不兼容版本(比如 jQuery 的 1.11.1 版和 2.1.1 版)时,它们将会被安装到相同的位置,并发生冲突。如果发生了这种情况,Bower 会要求你手工选择哪个版本是你想要的,并且可以决定是否把这次选择的结果保存到 bower.json 文件中。这个过程存在不确定因素,它依赖人工干预,因此两个人在安装相同的依赖包时可能会得出不同的安装结果。不过一旦你把你的选择结果保存到了 bower.json 中,就不存在变数了——任何人在安装你的项目时都会得到相同的安装结果。

The user experience is not as good as Node land, where conflicts can be resolved without user intervention. However, it addresses the concerns of front-end developers and clearly works well enough.

这种体验没有 Node 环境那么好,因为后者遇到的版本冲突可以在无需人工干预的情况下自动解决。总的来说,它照顾到了前端开发者的关注点,而且它确实也干得挺不错的。

Reducing friction without picking a winner yet

现在还无法选出胜者,但我们还是想减少摩擦

We don't want to get ahead of ourselves. While Bower is clearly popular, there are a lot of other packaging solutions out there right now. Browsers continue to evolve rapidly, so it doesn't seem to us that now is the right time to bless a single way of handling front-end packaging. This is where the strategy we previously outlined in the npm command-line interface roadmap comes in.

我们并不想操之过急。尽管 Bower 已经十分流行了,但眼下仍然还有不少其它的包管理方案可用。同时,浏览器也在持续地快速演进,因此我们认为,现在就对前端包管理方案下结论还为时过早。正是基于这种考量,我们不久前在《npm 命令行界面(CLI)线路图》一文中提出了以下重要策略。

The plan for the npm CLI is to modularize it into discrete pieces that can be used independently and programmatically, not just as part of the npm client. The underlying goal is to make it possible for other people to write tools that re-use the parts of npm that work for them, and be able to implement their own solutions for the parts that don't, without turning npm into a gigantic ball of configuration options, switches, and lifecycle hooks.

我们计划把 npm CLI 模块化,将其设计为各个分离的部件。这些部件不仅作为 npm 客户端的一部分而存在,还可以独立地被程序所调用。底层的目标是令其他人可以在 npm 这个基础之上编写工具——如果 npm 中已有对他们有用的部件,那他们就可以重用;如果没有,他们也可以自行实现自己的解决方案。实现这个目标的方法,并不是把 npm 改造成配置选项、开关、生命周期钩子所组成的一坨大杂烩,而是将其模块化。

The exact design of a modularized CLI isn't finalized, but the big pieces would obviously include:

模块化 CLI 的完整设计还未定稿,但显然会包含以下几大部件:

  1. a API for downloading packages from the registry
  2. a "cache" API that can store, read and unpack packages locally
  3. an installer API that places packages into your project in the right location

  1. 一个用来从包仓库中下载包的 API
  2. 一个可以在本地存储、读取并且解压缩的 “缓存” API
  3. 一个安装器 API,可以把包放置到你的项目中的合适位置

It's pretty clear from what we've already said that any front-end package manager would probably want to use parts 1 and 2 and re-implement 3.

我们应该已经说得非常清楚了,相信任何前端包管理器都想用上第 1 和第 2 条,然后重新实现第 3 条。

Building your own front-end package management using npm

使用 npm 来构建你自己的前端包管理系统

If you were to build the ideal front-end package management system today, what would that look like?

如果你打算在今天构建一个理想的前端包管理系统,那它会是什么样子的呢?

Here's the medium-term future of client-side package management as we see it:

中期来看,我们所能想像到的官户端包管理系统将是这个样子的:

1. Don't run your own registry, use ours

1. 别去运营你自己的包仓库了,直接用我们的

This isn't (just) self-interest: the feedback we get from literally everybody else running package registries right now is that they don't want to do it anymore. It's expensive, difficult and time-consuming to maintain the kind of uptime, performance, and user support that is required. And in any case, "hosting packages" is not the problem that client-side package managers are trying to solve. If it's JavaScript-related, host it in npm. Once they are available, use ecosystems to create "mini-registries" within the global one, complete with custom search indexing and display characteristics.

这并不仅是自私自利:除了我们之外,还有一些人在运营着自己的包仓库,但他们给我们的反馈都是再也不想继续下去了。维持包仓库的稳定、高效、以及必要的客户支持都是十分昂贵、困难和耗费时间的。而且从任何意义上来说,“托管包” 都不是客户端包管理器想要解决的问题。如果包是跟 JavaScript 相关的,那就托管到 npm 吧。一旦生态圈功能上线之后,就可以通过它来在全局库中创建 “微型库”,通过自定义搜索的索引来充实其内容,并显示其特征。(译注:我其实不确定后半句在说什么。)

2. Use package.json for metadata

2. 采用 package.json 作为配置文件

If your tool needs metadata to make it work, put it in package.json. It would be rude to do this without asking, but we're inviting you to do it, so go ahead. The registry is a schemaless store, so every field you add is on an equal footing to all the others, and we won't strip out or complain about new fields (as long as they don't conflict with existing ones).

如果你的工具需要一些配置信息才能工作,那就把它放进 package.json 文件中吧。似乎未经询问就这样做稍显粗鲁,但我们在此发出邀请:但做无妨。npm 的包仓库是一个无模式限制的(schemaless)存储空间,因此你添加的每个字段都具有和其它字段一样的地位,我们既不会清除这些新字段,也不会因为存在新字段而报错(只要新字段没有跟现有的字段冲突就行)。

We realize this runs the risk of creating a jumble of incompatible metadata, so be reasonable: resist the temptation to grab a generic field name like "assets" or "frontend". Use a label specific to your application, such as "mymanager-assets" or "mymanager-scripts". If in the future we decide to more explicitly support your functionality and give it a generic field, it's easy to maintain backwards-compatibility with the old name.

我们也意识到这可能会带来一种风险,产生一堆互不兼容的配置信息,因此,请适度使用:千万要抵御住诱惑,不要试图抢占一些通用的字段名,比如 "assets""frontend" 等等。用一个特定的、代表你的应用的标签就好,比如 "mymanager-assets""mymanager-scripts"。在未来,如果我们决定更加明确地支持你的功能,并为你分配一个通用字段,那也是很容易实现对旧字段名的向后兼容的。

3. Use our cache module

3. 采用我们的缓存模块

Unpacking, storing and caching packages is a surprisingly complicated problem at scale. Especially if you are using our registry, once it becomes available, you should be using our cache module. This will save you effort, time, and bandwidth.

在规模化的情况下,解压缩、存储并缓存包其实是一个非常复杂的问题。因此,如果你是在使用我们的包仓库的话,那么一旦缓存模块可用,你就应该立即用上它。它将会节省你的精力、时间和带宽。

4. Write your own front-end semantics

4. 编写你自己的前端包行为

This is where your use-case differs from npm's Node-centric behavior, so this is the only bit you should need to write yourself. Even then, we should have some handy modules that will help you out. You could do like Bower does, and download and install front-end packages into a totally different folder and handle dependencies separately. Or you could get npm to install everything into node_modules and use a post-install or a run-time hook to resolve dependencies, or some combination of those strategies. We're not sure the best way to go, which is why we want to encourage experimentation here.

你的使用场景肯定跟 npm 以 Node 为中心的行为大相径庭,因此这是唯一一块你需要自己搞定的部分。即便如此,我们还是会提供一些顺手的模块来帮助你。你可以做到和 Bower 一样的效果,比如把前端包下载并安装到一个完全不同的目录中,然后自行处理依赖关系。或者你可以让 npm 把所有东西都安装到 node_modules 目录中,然后利用一个 post-install 脚本或一个运行时钩子来解析依赖,或以上策略的某种组合。我们不确定哪条路是最佳选择,这也是我们鼓励大家在此深入探索的原因。

When can I start doing this stuff?

我什么时候可以开始动手?

This is always the next question once we explain this plan. The best answer is: probably next year, sometime. The work necessary to get npm there as a program has already started, but npm Inc's first mission has to be becoming a self-sustaining entity, which is why we're concentrating on releasing private packages first, in early 2015. After that our likely next focus will be growing the usefulness of the registry itself, and that's where client-side packaging comes in.

一旦我们讲清楚了这个计划之后,接下来每个人都会问出这个问题。我们只能说:可能是明年(译注:2015 年)的某个时候。将 npm 改造成上述效果所需要的工作早已启动了,但 npm 公司的首要任务是得先让自己成为一个自给自足的实体,这也是为什么我们会在 2015 年早期专注于发布 “私有包” 服务。在此之后,我们的下一个专注点应该就是扩展包仓库自身的功能了,届时将是客户端包管理功能的登场之时。

What can I do right now?

我现在可以做什么?

It's all well and good saying we're going to support this stuff, but you have this problem right now! So what can you do immediately, starting today?

我们将对此提供支持,这确实没错,但这个问题现在就横在你的面前啊!那你眼下可以做些什么呢?

1. Use our registry

1. 使用我们的包仓库

There's no reason not to. It's fast, it's got 99.99% uptime, and it's free for open-source projects and always will be.

没有理由不这么做。它很快,它的可用性高达 99.99%,而且它对开源项目是(并且永远都将是)免费的。

2. Use package.json for metadata

2. 采用 package.json 作为配置文件

Again, no reason not to. It's your package, describe it how you want. Try to avoid duplicating data (don't make your own "name" field) and avoid generic names, but otherwise: have at it. If you think what you're trying to do with package.json is particularly weird or complicated, we are always available on IRC, Twitter and email if you want to run the idea past us first.

同样,没有理由不这么做。它是你的包,就用你想要的方式来描述它吧。要注意避免数据重复(不要另外弄出一个你自己的 "name" 字段),并且避免通用的字段名,除此以外,你就放手去做吧。如果你发觉自己对 package.json 的使用方式有些怪异或复杂,随时可以通过 IRC、TwitterEmail 找到我们——如果你想先跟我们通个气的话。

3. Tag your packages

3. 给你的包打标签

The npm "keywords" field is somewhat under-used right now, and can be used to unambiguously claim membership or compatibility with a specific ecosystem, even before they exist. For example, I tagged a package "ecosystem:hapi" and you can search for it by that tag. This obviously isn't as good as a real ecosystem because the automatic validation isn't there, but it's better than ambiguous keywords.

目前 npm 的 "keywords" 字段在某种程度上利用得还不够,其实它可以用来清晰地声明包与某个生态圈的从属关系或兼容性,即使这个生态圈还不存在也没关系。举个例子,如果我给一个包打上 “ecosystem:hapi” 的标签,那你就可以用这个标签搜到它了。这种方式明显不能像一个真正的生态圈那样好用,因为它不具备(将来生态圈功能将会提供的)自动的验证机制,但这总比模糊不清的关键字要好。

4. Use lifecycle scripts, and browserify

4. 使用生命周期脚本,以及 Browserify

It's not a perfect solution, but we think there is merit to exploring the idea of managing client-side assets installed by npm using lifecycle scripts. You could for instance have a "postinstall" script that moves packages installed by npm into a flat structure, and queries about dependency resolution. It's by no means perfect, but if you're desperate for a solution right now, we're interested to see what you can come up with using these, and your pain points will inform the work we do in getting out of your way.

使用 生命周期脚本 来管理那些通过 npm 安装的客户端资源,并不是一个完美的解决方案,但我们认为这个方向值得探索。比如说,你可以设置一个 "postinstall" 脚本,用来把 npm 安装的包移动到一个扁平的目录结构中,并处理依赖关系。这种方式肯定不够完美,但如果你把它作为救命稻草来用,我们会乐于关注你在这条路上能走多远,而你的痛点也将为我们接下来的行动带来启发。

We also think browserify is amazing and under-utilized, and an end-to-end solution that worked with it automatically at install time is a really, really interesting idea (check out browserify's sweet handbook for really great docs on how to use it effectively).

我们还认为 Browserify 是非常棒的工具,但远没有得到充分利用。如果在安装时把它作为一个端到端的解决方案来使用,将是一个非常有创意的想法。(请查阅 Browserify 的 温馨手册,那里有非常棒的文档,会告诉你如何用好它。)

Hang in there

请再坚持一下

Front-end developers want to stop using multiple package managers. Registry owners are tired of running their registries. The current support in npm for front-end packaging isn't good enough. We know, we agree, and we're committed to making things better. npm loves you, front-enders, and we care about your use cases. We build our own website using npm, and have the same pain points. So keep giving us feedback and ideas. We're working on it.

前端开发者希望不再同时使用多个包管理器。包仓库的运营者们也已经厌倦。目前 npm 对前端包管理的支持确实还不够好。我们知道、我们同意、我们承诺会让事情变得更好。前端开发者们,npm 爱你们,而且我们关心你们的使用场景。我们自己也使用 npm 来构建自己的网站,我们也有着同样的痛点。因此,请继续向我们提供反馈和建议。我们正在为之努力。

There will be a winner, eventually

最终,胜者必现

One final point we think it's important to make clear: we hope that a solution emerges that is so obvious and easy to use that we can "bless" it and either build it into or bundle it as part of npm. When we do that, we don't want people to think we pulled a bait-and-switch where we claimed there would be an ecosystem and instead we picked a winner (we've seen that go wrong at other companies). There is going to be a winner: we just don't know what it looks like yet.

我们的最终观点是有必要明确一下的:我们期望有一个解决方案能浮出水面,它是如此直观、如此易用,以致于我们可以 “仰慕” 它,甚至把它内建到 npm 中或将它绑定为 npm 的一部分。当我们这样做的时候,不希望人们认为我们是在偷换概念,因为我们曾许诺要维护一个良性的竞争生态,但结果我们又挑出了一位胜者(我们知道这个做法在其它公司身上曾出过问题)。但事实上最终必将出现一位胜者:我们只不过是到了那个时候才知道它是谁,而已。

If you have strong feelings about what that solution should be, building a solution that works and people use is ten thousand times more persuasive than writing a long comment on a GitHub issue about it, and also super-useful to everyone in the Node community. So go forth and build solutions, and we'll be watching closely.

如果你已经强烈地预感到那个终极方案是个什么样子,就去实现并推广它吧,这比在 GitHub issue 里写长篇评论要强一万倍;同样,对于每个处在 Node 社区的人来说,这也是极其受用的。因此,大步向前,去构建解决方案吧,我们会密切关注的!


译者后记

最初同事将这篇文章推荐给我时,我没有读下去。当江湖传闻 Bower “要完” 时,我再次翻出了这篇文章,并将它翻译了出来。

但译完之后,坦白地说,我有些失望。npm 在这篇文章中并没有提供任何有效的解决方案,只是期望 “美好的事情必将发生”。这篇文章发表于 2014 年底,但直到现在 npm 也没有拿出文中提到的 “生态圈” 功能;这一年多来,前端包管理领域也没有浮现任何真命天子般的终级解决方案。

不过,在前端开发者这一端,包管理的实践风向倒是发生了不小的转变。最明显的潮流就是 “放弃 Bower,直接采用 npm”。这背后的推力,一方面是越来越多的 npm 包采用 UMD 作为发布方式,网页直接使用也无压力(当然我们也可以认为这一点与上述潮流互为因果);另一方面,前端资源的构建过程已成常态,在页面中通过 <script> 标签直接引入脚本的情况越来越少了,Bower 的独有价值也就少了很多。此外,npm3 的扁平化目录结构也进一步瓦解了前端开发者的心理防线。

如此看来,npm 动作虽慢,但斗转星移,自己却被推到浪潮之巅。这篇文章已无时效,但读起来仍然很有意思,令我们有机会一窥这家公司的思维方式与价值观。


本文在 “CSS魔法” 微信公众号首发,扫码立即订阅:

weixin-qrcode


© Creative Commons BY-NC-ND 4.0   |   我要订阅   |   我要打赏

@riskers
Copy link

riskers commented Feb 7, 2016

bower已经不维护了

npm管理比较好,准备过一阵就用npm管理了,问一下,所有模块都在 node_modules 里,那么怎么用呢?只能用webpack 或者 bowserify来构建是么?

@cssmagic
Copy link
Owner Author

@riskers
是的,一般是需要构建的。不过如果某个包提供的 dist 文件是 UMD 格式,或已针对浏览器环境处理过,那也可以直接使用。

@xuexb
Copy link

xuexb commented Feb 15, 2016

mark

@icepy
Copy link

icepy commented Feb 15, 2016

长江后浪推前浪,采用包管理机制是前端生态发展的必然,但是特殊环境又有别于其他平台,比如iOS中的实事包管理Cocoapods,真希望“美好”的愿景早一天到来。

@andycall
Copy link

打个广告, FIS3 也开始支持node_modules了

https://github.com/fex-team/fis3-hook-node_modules

@cssmagic
Copy link
Owner Author

这篇文章本身其实没啥特别的,npm 打打官腔而已。不过这篇文章在开发者群体中却是引发了不小的反响。

有一位开发者针对这篇文章写了一篇吐槽文。他清晰地刻划出了前端包管理的疼点所在,同时描绘了他心目中前端包管理器所应该提供的功能和服务。推荐阅读,不过我就不翻译了哈。

JavaScript Modules: Welcome to My Emo Hellscape

@hax
Copy link

hax commented Mar 23, 2016

@cssmagic 吐槽文不错,有翻译的价值(尽管已经一年半,某些情况已经发生变化),而且应该没有人翻译过。

我只讲一下该文接近结论的部分:

After five years of community experimentation I’m pretty convinced this problem won’t go away until we all start using the same module format for both authoring and consuming[3] or some central broker makes publishing and consuming formats frictionless.

但实际上现在至少有两种方案——webpack和jspm——可以解决他讲的大部分问题。当然仍然还是有很多遗留问题。而我预言的前端云也包含了他讲的“some central broker”的作用。

@riskers
Copy link

riskers commented Apr 5, 2016

有个问题请教下,我的模块是一个小组件,有 html 、css 和 js,这样是不是就不适合发布到 npm 呢?我现在是 js 发到 npm,css外联,html写在 readme 里 😭

@zpbx
Copy link

zpbx commented Apr 6, 2016

@riskers
原文已经说了:

你的包可以包含任何内容,不论是 ES6、客户端 JS,还是 HTML 和 CSS。有很多东西天生就是跟 JavaScript 绑在一起的,那就把它们都放进来吧。

@leozdgao
Copy link

leozdgao commented Apr 6, 2016

@riskers @zpbx 感觉重点其实不是放不放在一起,而是在一起之后,如何再作为一个模块引入,之前对这方面也比较纠结,目前还是很依赖 webpack 之类的 bundle 工具。

@riskers
Copy link

riskers commented Apr 6, 2016

@zpbx @leozdgao 我知道是放在一起,只是在想怎么引入。现在似乎只能用webpack来构建?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants