前端技术的开放和封闭 #18

Open
jayli opened this Issue Jul 8, 2015 · 45 comments

Projects

None yet
@jayli
Owner
jayli commented Jul 8, 2015

Unix 哲学”的根本原则:“简单原则”——尽量用简单的方法解决问题。

阿里系的 KISSY 框架的取名就源自 Unix 哲学中的这一条,Keep it Simple & Stupid。这也是我们在 PC 和无线时代不断提炼前端开发框架、研发模式、共享代码和开源社区建设的基本理念,即将规范做轻、研发环境做实、抽离代码、贡献代码的体验打磨到最佳。这种对一致性、规范性、简单性的美学追求,一直影响所有前端开发同学至今,也让前端的开源世界充满活力。

我们(阿里航旅前端团队)也在前端研发模式上有了一定沉淀,但随着业务和开源社区的平行发展,我越发感觉到自己和开源社区之间的壁垒越来越重。以至于影响到团队成员的(技术)意识形态,我们必须做出选择,追求拥抱开源,还是更加务实封闭。

1. 航旅的前端研发模式

架构图大图

  1. 底层是项目源码仓库,项目代码携带开发环境,项目目录结构固定,开发环境通过 tnpm (阿里内部私有 NPM 仓库)一键安装
  2. 源码(src)需要被构建到可发布代码(dist),构建过程包括模板解析、TMS (阿里内部的运营数据管理系统)数据异步化(生产环境只支持静态 HTML)、HTML 合并和压缩,JS 和 CSS 的合并和压缩
  3. 项目仓库中所需的组件是通过 bower 安装进来的,组件代码存放在内部的 gitlab 仓库上
  4. 最后的打包发布也是通过 Node 工具完成的,这些工具都是一键安装的
  5. 项目和组件的初始模板通过基于 Yeoman 的生成器来生成,基本上也是一键生成的
  6. JavaScript 模块规范遵循 KISSY 模块规范(KMD)

整个研发模式基于以上六个要点搭建,看上去也很完整,能够很好的支撑研发模式所有环节,而且对面向多端容器的适配也一并在 Node 工具层面完成,保持源码(src)的“轻便”。

2. Why Bower?

KISSY 组件库提供了组件研发的体系,为什么不直接依赖这个体系建设航旅的组件库?原因有二:

  1. 这些组件只能在线使用,不能离线(或者说离线成本很高)
  2. 线上组件出了问题,bugfix 升级成本很高(因为你要 at 组件作者去修复)

而在业务高速增长的阿里内,稳定的组件可能仅限于一些不痛不痒的轮播日历之类。大量组件配合业务的迭代需要不断升级,在缺少 UI 测试用例的前提下,集中式管理组件代码极大拖慢了整个节奏,干脆把组件 fork 到我项目里吧。bower 作为对格式无约定的包管理器,非常适合安装、升级外部模块。

3. 问题出在哪里?

刚刚我用“轻便”来描述我们的项目源码环境,实际上每个项目迭代几个版本之后,就再也不轻便了。源码(src)开始有冗余,特别是 bower 安装进来的组件代码也因频繁升级导致版本交错愈加剧烈,组件被 fork 出来之后基本上就单独衍生版本了,再也难合并到主干去。一方面有研发任务的压力,另一方面,绝大多数组件的构成原本就不干净,要么文档不全要么注释稀少、再要不连 Demo 也没有,merge Request 难度很高。

这就是我们实实在在发生的事情,一个团队中,到头来始终只有几个编程高手在抽组件、维护核心的公用代码,大部分人大都只会 fork。这就背离了我们的初衷,代码流动性越来越差。这也是 KISSY 开始走向没落的大背景,组件库一直缺少血液供给,社区再难像两年前搞组件大赛那样火爆。团队小圈子开始一个个的形成,轮子越来越多。

进一步讲,阿里业务的发展实在太快,无线化对研发模式带来极大的冲击,从天猫、支付宝、淘宝等前端团队变化来看,从作为支撑角色的前端,会逐渐强耦合业务,就又加剧了前端技术的多元化和去中心化的大趋势。所以我们经常开玩笑,百度的前端业务得多简单,一个 FIS 就可以支撑百度绝大多数前端业务了。

所以,问题很明显:

  1. 业务之间壁垒加剧,阻碍优秀代码的传播
  2. PC 时代大教堂模式的前端生态建设,在无线端早已水土不服
  3. 阿里成了围城,大量业务强相关的私有技术崛起,和开源社区渐行渐远

4. 那么,航旅解了这个问题了吗?

当然没有。好在我们在最初开始争论的时候就选择了站队,目前形成了自有的技术体系:

  1. Bower:组件代码管理器
  2. Yeoman:项目脚手架
  3. Grunt:构建管理
  4. Clam:开发环境工具集合(内网访问)
  5. KMD:JavaScript 模块规范
  6. Sass:Css 语言扩展
  7. Juicer:HTML 模板引擎
  8. KISSY mini:JavaScript 基础库

于此同时,天猫(@三七)和我们(的 PC 产品)在坚守 KISSY 1.4 体系(MUI),淘宝原核心业务(@圆心)开始 KISSY 5 的探索,同时面向无线产品开始研发一个将 Zepto 私有化的项目 Kimi(内网访问)。支付宝(@玉伯)坚持走 Seajs 生态路线。而无线淘宝(@寒泉)则选择“不站队”。

这么多体系,脑袋要炸了。

本质上讲,业务的高速发展加剧了这种“失控”,很多方案有着现实意义。比如 KISSY Mini 很好的承接了航旅的 PC 业务转无线。而 KISSY 1.4 在目前全站 PC 业务中支撑良好。Kimi 则在最快时间内提供了低学习成本的一个无线方案。因此,从业务支撑方面讲,这些技术方案都是“成功”的。尽管这些分支各自活的很好,但在前端开源世界蓬勃发展的今天,私有技术和开源社区之间渐行渐远,不免让人感觉有些失落。

KISSY 看上去不再 KISS,Sigh~

KISS 的 Unix 哲学理念在充满创新和变化的业务面前,应当如何自处并渗透自有的优雅美感呢?

5. WebPack & Browserify

今天跟@勾股 兄长聊,有点小感慨,也很认同@勾股 的两个技术观点:

  1. 企业内开源无法持久,只有参与到开源社区中才能真正吮吸到技术创新的新鲜空气
  2. 用成熟的开源技术来搭建私有技术,帮助业务私有技术体系走完最后一公里

保持开放的心态拥抱开源,用务实的精神快速“拿来落地”。在模块规范和代码生态建设上,最适合拿来的就是 WebPackBrowserify。这也是@寒泉 的无线淘宝团队打算要做的事情,有信仰总归是更可爱一些的吧。

6. 完全被小瞧了的前端技术

好吧,我个人表示 WebPack 和 Browserify 难堪大用。

以 Browserify 为例,来对比下理想和现实的差距,Browserify 的优势:

  1. 用 npm 的大量开源资源
  2. 收敛的代码仓库(共有仓库 npm)
  3. CommonJS 规范 + Npm Package 规范

Cool!~

Browserify 的不足:

  1. 工程项目里的前端页面必须对 Seed(KISSY Seed 或者 jQuery) 有依赖,这种依赖不能在构建的时候复制多份(特别是在 H5 离线包 中,为了控制离线包体积,必须要去重),npm 中的模块物理上都是复制存储的
  2. CSS 样式的载入时机太慢(为了做到离线页面秒出 UI。样式必须比 JS 提前载入,在 DOM 构建时就生效),CSS 问题在 WebPack 和 Browserify 中无解决方案
  3. 项目代码下辖的模块代码存储过于分散,代码分三个部分
    1. 项目本身的代码,就在 gitlab 项目仓库中
    2. npm 安装进来的代码,在项目的 node_modules 目录中
    3. 项目组件代码,通过 bower 安装进来,存放在另外的 gitlab 仓库中
  4. 前端组件真真不同于 Npm 包,需要在此上构建一个前端 widget 包规范的超集,需要考虑这几个问题
    1. 为了便于 widget 代码携带 Demo,需要一个本地环境,将源码(src)构建出目标代码(dist)以便运行起来,所以包内必须携带 grunt 或者 gulp 之类的构建脚本
    2. widget 所携带的样式引用,依然缺少优雅的方案提
    3. 业务私有的 widget 代码事实上都在 gitlab 里,需要通过 bower 来安装,概念上就一定程度混淆 npm 安装和 bowser 安装,于是难对组件进行干净的归类,比如我要修复一个 npm 组件的 bug,修复之后应当 fork 在 gitlab 里用 bower 管理起来还是重新提交给 npm?
    4. 如果想收敛组件仓库,则 gitlab 里开发的公用代码必须发布到 npm 上,多此一举,不然,怎么收敛仓库?
  5. 物理代码不收敛
    1. 物理代码分散:npm 安装的代码放在项目的 node_modules 中,这个目录一般都在.gitignore 里,不会提交到gitlab上
    2. 配置信息分散:代码依赖需要在两个地方定义,package.json 和 源码中(应用包时往往需要 require 一下),模块依赖关系定义没法干净的在一个地方指定,实在不爽。

如此看来,Npm 天生不适合存放前端模块,一个前端代码包含的技术碎片过于分散,以至于几乎不可能用一种优雅的方式解决。举个例子,前端是强依赖 Loader 规范的,而由于场景不同,Loader 可以像 YUI Loader一样复杂,也可以像requirejs一样简单。而作为组件代码则必须明确“知道”依赖其中哪一种 Loader。Loader 作为前端模块载入的基础装置,是需要预载入 HTML 中的。所以,这个“知道”就是一种依赖。一旦有依赖,就很难将解耦拆的干净。所谓“约定”,不过是强行隐藏一些存在的配置项,很早之前就有过类似的讨论

So,Unix 哲学在前端技术领域里的影响总是有限的,受浏览器运行机理的限制,前端项目研发复杂度是固定的,你只能封装其中的一部分,总有一些复杂度你无法封装,所以前端项目研发环境一定是为业务场景高度定制的,未来前端技术的私有化和壁垒天然会加剧。就如同开源和闭源一直争论不休一样。

但这丝毫不妨碍我们拥抱开源,包括 bootstrap 在内的大量私有项目被开源出来,我们也可以享受前端技术高度“去中心化”和“碎片化”带来的红利。把社区中现有成熟的工具利用好,并严格律己的遵循开源协议,前端的开源也一定呈现多元共生的局面。这些所有成果,都极为有利于我们完成手头工作的“最后一公里”。

7. 前端技术未来

让人欣慰的是,ES6 让人看到了希望。

至少我们不用再为 JavaScript 本身的 OO 去打各种补丁了。作为企业专职的前端工匠,面对现有技术选型时,也应当遵照标准的 ES6 规范去制定长远规划。Kissy Mini 接下来的版本中会更加拥抱 ES6。

另一方面,在无线领域,H5 和 Native 的耦合会越来越重,前端代码的研发模式会一定程度和客户端开发整合,这也是我们航旅团队接下来将要突破的重点。前端技术边界向 Native 很多特性延伸,制定 H5 容器标准,目标是让 Hybrid 挑战 Native 的原生体验,PPK 似乎还在下意识的将两者对立,大量的事实已经证明,混合式研发会在未来无线战场中挑大梁。特别是 ReactNative 开始大量运用后,我们所掌握的已知的前端工程化管理的方法都将被打散重构,前端技术从真的变得此不再孤立。

可以断定,前端技术学习门槛和身价会越来越高,会切页面已经不足以打动面试官了,FE 们开始消耗大量的计算机课上的那些基础知识,计算机网络、数据结构、数据库、C 语言、编译原理、信息安全这些基础课变得越来越重要,对知识面广度的要求远超从前。

而在开源社区和闭源的私有技术中,这种开放与封闭的博弈会一直持续,着眼开源,立足闭源,保持开放、坚持务实,是我们应当具备的做事原则。

至于那个在前端技术里一直水土不服的 [KISS 哲学]([Unix 哲学]%28http://www.faqs.org/docs/artu/ch01s06.html%29”),别担心,让他一直水土不服下去好了。

@jayli jayli added the blog label Jul 8, 2015
@chaoren1641

好文啊,绝大多数观点非常赞同。的确,企业内部人员流动使得内部开源工具很难长久健康发展。

不过文中提出的“Browserify 的不足”中的第一点:

工程项目里的前端页面必须对 Seed(KISSY Seed 或者 jQuery) 有依赖,这种依赖不能在构建的时候复制多份(特别是在 H5 离线包 中,为了控制离线包体积,必须要去重),npm 中的模块物理上都是复制存储的。

应该可以通过 webpack multiple-bundlesbrowserify multiple-bundles 来解决吧(我也只是初步了解 😄)。

@Huxpro
Huxpro commented Jul 9, 2015

说到底还是历史包袱啊……
新东西总有新东西的玩法,迁移才是最麻烦的

其实除了构建工具之外,厂内 UI 层的库同样也有这个问题:
大量新框架层出不穷,MV*/Vue/React,但是厂内还是 Zepto+YUI 风格的 KISSY 系,吸收不了开源世界的新东西。更惨的是大量基础 UI 建立在 KISSY 生态上,根本没法迁移。之前去啊也实践过一段时间的Angular,后来听说又 drop 掉了。

现在@玉伯 团队全面拥抱 React, @勾股 开始尝试 Vue,不知道航旅这边有什么想法

@soulteary

其实KISSY EDGE的时候,KMD就已经是CommonJS书写方式了,还是省了不少事情的,如果不是人员变动,Browserify和KISSY最后谁更容易被接受未可知。

经历过三家公司的变动,对5的两点深有同感,@勾股 。

关于6的种种问题,虽然看起来是通用场景下的需求,但是实际上都和业务相关了,使用者会是自己团队的小伙伴,那么软性约束是可以愉快解决的,尤其是1、2;3,4使用类似@不四 他们做的事情,做个cBrowserify(私有Browserify),同样还能解决5,另外,既然使用了npm的方式来进行管理,不管是符合dry的理念抽象一个团队使用的team-config.json来统一保存内容,还是直接就在package里开辟一个字段储存内容都是可行的,不需要纠结配置需要保存多份的问题。

还有一点,原po没有提到,内部百花齐放的原因和类库/工具/组件没有强制的数据交互约束也有关系。而做了这一点的,我记得只有 @鬼道 的RAP,如果能早点达成共识就好了。

ps:chap. 4似乎无视掉了小马团队的事情。

@hongru
hongru commented Jul 11, 2015

一大早起来通过拔赤周报辗转来到这里,看到文里提到的各种现状,最有感触的关于 npmmodule和browserify/webpack的一段。手淘前端从什么队都不站,纯依赖ml.x.taobao.net的简单的基础库cdncombo的工具把库引用,依赖管理这件事情走到现在。回头看看,感觉是略有心酸,五味杂陈。但是即使到今天经过讨论觉得是时候探探路站站队了,也对这件事情并不那么着急。原因是从现状看,大家对于“组件入库”,“引库使用”这件事有痛点,但单纯这个点上痛点没那么大,更多的痛点是混杂在其他地方,开发流,图片处理,预编译,构建,调试,发布等等一系列。

回到刚才说的module的引用方式,加上browserify或者webpack。开始讨论这件事情在团队内部也就上个月的事情。最开始的初衷是为了解决业务代码和基础代码中缺少模块依赖关系处理这个问题。过程中依然百花齐放,有同学业务模块自己browserify处理,基础库因为历史原因用bower管理,也有人在尝试ES6+webpack的module处理方式,还有人自己做过一个套件,包装了一个类CommonJS的依赖引用方式,可以在不改变现有基础库代码(没有模块范式)的前提下也能正常使用。

当时有个简单的讨论,大家想在上面提到的方式中选一个或者组合一个然后去挖。首先完全自造轮子的方式没必要,也有风险,放掉。ES6+webpack的方式大家相信应该会是面向未来的最好的选择,但是面临两个问题,一个是polyfill对业务来说可能太重,另一个是担心步子一下迈太大团队成员跟不上。所以当时的讨论回归到npmmodule和browserify。

说到正题,拔赤说道的前端组件npmmodule化和browserify/webpack 难担大任的问题。我们当时也心有戚戚。

  1. npmmodule化之后,组件引用从云共享变成代码实体引用。这并不是一个好的方式,至少在当前大环境下是。
    所以我们的考虑肯定是不能直接使用现有的browserify,而是是否能基于它包一层,比如my_browserify,以此来做到开发时本地依赖,但是基础库的部份在构建阶段解成线上依赖(动作有点大,感觉为了解决一个问题引入另一个更大的问题)
  2. css在browserify中没有直接的解法,在webpack中也只能换成js动态注入,显然也不是当前环境想要的结果。还好当时我们的基础库和功能控件涉及css的不多。当时就直接放掉了这块的讨论,css暂时还是老老实实刀耕火种吧,除非也是像1一样在自己包的my_browserify中解决。

3和4. 多源和多组织的问题,如果真打算淌这淌水,那么npm和bower理应只选择一个。而两个的各自优点让人放不下,比如bower灵活的依赖源支持,扁平的文件结构可能更适合前端的文件组织方式,但npm天生有更强的依赖引用和处理能力。
这种情况下选择就意味着放弃,关键就是权衡轻重的问题。要么就大家都不选,维持现状
npm源和gitlab源两处发布的问题,一样,如果真想淌这水,通过搭中间服务,接hook,或许也能解决一部分。也是性价比和轻重的问题

回过头来看关于前端组件依赖处理的问题。如果想在这个点上站队,随便做一点说我用了browserify或者webpack,没问题。但是想做通,把拔赤说的几个点都打通。要挖的坑或者说性价比可能并没有那么高。尤其是针对团队通用,而不是项目通用。

所以我们虽然在尝试这件事情,但我依旧持保守态度,同时也在兼容并包看待百花齐放,兼容并包。包括最近勾股一直在实践的vuejs+vueloader+webpack的方式,或者是ES6+webpack的方式。

到现在为止,现状都在,问题都在,大浪淘沙,谁剩下了,谁就是金子。在手淘前端团队里也是这样。

@sodatea
sodatea commented Jul 11, 2015

@hongru ES6 其他特性的 polyfill 可能的确是太重了,但是仅从模块化方案上来看,webpack 的 overhead 其实够轻了 -> http://webpack.github.io/docs/comparison.html 所以模块化规范尽早迁移到 ES6 Module 其实没太大问题的。
另外,关于 npm/bower 二选一的方案,不知道你们是否考虑过 jspm?国内很少看到这方面的对比,个人不是很明白 jspm 有什么很不好的地方么……?

@jayli
Owner
jayli commented Jul 13, 2015

@soulteary NPM 包规范在通常情况下是ok 的,但在夹杂了demo演示、本地运行环境、css 引用等情况是,复杂度会陡增,还是很纠结 npm 包规范太“服务端”而不够“前端”

@hongru webpack 的不足很少,但对css的处理是一个短板,我们也没想好太好的办法来hack

@soulteary

@jayli 个人认为,该走规范的走规范,该走约定的走约定,demo/runtime本身和代码关联相比较代码实现部分就不是特别强,应该遵守团队约定。

运行环境对于每个项目可能都有特殊性,厂内不是有daily环境可以玩么,或者结合在线mock服务,也能整一套『通用的运行环境』,个人比较倾向自己搞开发机或者本地虚拟机来实现这些Pantimos

demo演示,前端demo除了UI展示的需求外,还有交互类型的,后者一般和接口相关,如果约定使用固定的mock库把在线接口转离线,或者根据参数、配置把代码里的接口转mock服务的接口,也是没啥问题的。

资源引用,应该是代码管理的事情。如果不存在依赖,那么应该用工具约束成方案吧。

@Jinjiang

周末参加深JS一直没时间回,有几个地方想再补充一下我的看法:

  1. 对 npm 本身已注册的包来说,修改/维护/发布的成本高这个确实如此,不过所幸 npm 还可以通过 npm install githubname/reponame 的方式直接安装任意 github 的包的任意版本,所以,在 npm 的方案里,原文中提到的“线上组件出了问题,bugfix 升级成本很高(因为你要 at 组件作者去修复)”的问题其实并没有那么麻烦,每个人可以自行 fork 或创建自己业务的 branch、tag 或 repo 解决现实问题,并在合适的时机争取 merge 回主仓库的主分支。所以现实问题 npm 是有解的,而后续问题不是工具可以单方面解决的,是需要人解决的。
  2. “物理代码分散”这在我看来并没有任何问题,前端的代码本来就是应该通过相互依赖的关系解耦的,如何在业务中把握好“物理代码分散”的问题恰恰就是如何上面修改/维护/发布 npm 的问题,而不能把它转换成“物理代码应该聚合”的问题
  3. 如果底层组件或库需要频繁维护和改动,我觉得首要问题是提升代码质量、版本控制和抽象设计,不然什么辅助工具也无法高效支撑在这样的基础上高效完成上层开发。
  4. Browserify 和 webpack 对 CSS 的记载时机确实也是我自己很介意的地方,是我希望大家可以一起借助 browserify/webpack 和社区的力量推动解决的,正如原文第 5 点的我的观点 (文中的 @勾股 就是我 😄 )。另外 CSS 加载实际上早已经变成了个综合问题,实际上你会发现,如果我只先加载了 CSS 而 template 还没有被 JavaScript 初始化,那这些样式并没有更早于 JS bundle 发挥价值。我更觉得,如果我们需要从用户感知上给加载提速,做好拆分包并按需加载是很重要的——而不是把 CSS 拆出来。
  5. npm 去重的问题前面有评论提到了,表示支持,我自己也是这么实践的,不多做赘述
  6. npm 的依赖关系同时写在了 package.json 和代码中的 require(),这个问题已经有工具在解决,那就是 duo 也许是我们更喜欢的,duo 主要的问题是现成配套的周边东西还是偏少,目前我对此持观望态度,也许近期就会试试看
  7. 关于 seed 依赖信息,如果我没理解错的话,这里面有两层面“去重”的需求,第一个是在完整的 bundle 里,在多处通过 package.json 依赖的包会被打入多次,这个问题前面已经有解法了;第二层含义是我们可能需要在特定的情况下动态决定要补充请求哪些组件,比如我现在随着用户的操作进入一个新的界面场景,还缺组件 A,但是组件 A 又依赖组件 B 和 C,可这时候需要知道页面是否已经加载过 B 或 C,然后才能去重,再请求回正确且最小集合的代码。手机淘宝的业务中有些场景是这样的,套路无非是 3 种
    1. 第一种显然是丧心病狂的不管重复的引入完整的 A B C
    2. 第二种是中心化管理 seed 依赖信息,每次类似的请求之前先在浏览器做好去重再向服务器请求结果
    3. 第三种是把已加载的所有模块借请求的机会传给服务器,由服务器去重再返回结果

似乎各有各的好处,但也都不完美,算是再抛出一个我自己的问题吧 (这个问题我周末还跟 不四 @dead-horse 聊到,但暂没有结论),希望楼下可以继续

@Jinjiang

另外其实我挺喜欢 bower 的,bower 有很多优点,只是 npm 的社区更好同时有 browserify 和 webpack 令其如虎添翼,并且 npm 不是没有前端资源库的最佳实践。综合考虑我今天可能还是会选 npm 吧…… (我也不想把 bower “黑”成什么样)

@nihaox1
nihaox1 commented Jul 17, 2015

问题2:
在bower和npm都开源了几个项目,总体感觉开发者这边其实还是挺方便的,痛点主要在没有足够的精力去后续维护,而且前期使用场景有限,开发维度上比较欠缺。
作为插件使用者使用bower和npm上,感觉npm还是比较受欢迎,nodejs直接支持,而且bower的依赖是走平行依赖,npm是项目内深度依赖,虽然npm包大了,但是很多二次开发上不会太担心其它的依赖问题。
目前的项目是2者都用,没啥不好的
问题3:
项目立项初比较轻,后期逐渐变重,这个几乎是没办法去避免的。只能通过模块化的方式,让部分相对比较固化的地方尽可能的固化,只允许核心的人员允许编辑,并且一定保持向后兼容。与业务强偶尔的代码可以通过相关的开发工具(grunt、gulp等)去整合开发。总的来说问题3,感觉是一个通病,目前没有找到什么好的方式去解决,只能尽可能的去缓解吧。
问题7:
前端未来一定是会走大前端的路线,目前很多朋友(包括自己)开发的项目,都已经走向服务器端了。关联的问题也越来越多,es6后面感觉肯定火,这个只能大家共勉了。

@luqin
luqin commented Aug 31, 2015

前端这是要逆天了哈,非常感谢分享

@yyx990803

说说关于 npm / webpack 的一些问题:

  1. 模块重复:npm3 自带模块去重。只要依赖的 semver 版本不冲突就只会安装一份。
  2. CSS 样式处理:webpack 的 ExtractTextPlugin 可以将整个包里依赖的 CSS 模块抽取成一个文件用于单独加载,并不是无解。Browserify 整体上对于很多工程化问题都欠考虑,依赖社区,但是社区工具 hack 很多,质量参差不齐。
  3. 代码分散。既然用了 webpack,最理想的就是全面拥抱 CommonJS (或者直接上 babel-loader,全面 ES6 模块化)。bower 是个历史包袱,能去掉最好。
  4. npm 包大多自带 devDependency 和构建脚本,这其实是好事,每个包都应该能够单独调试、测试、看 demo。大部分小组件根本不需要 grunt/gulp,直接 webpack + webpack-dev-server + npm script 就足够。纠结一个包 “看上去不前端” 是毫无意义的。
  5. package.json 声明的是包和包之间的联系,不是文件模块之间的依赖。文件模块的依赖关系就应该在文件内通过 require/import 自然形成,需要手动指定是画蛇添足。

以上,我的看法就是 npm 很好。

@yyx990803

另外,Duo 已经是个 dead project 了。如果想要类似的方案不如看看 System.js,但我的看法是现阶段(在全面 HTTP/2 化之前)不如 Webpack.

@yujiangshui

@yyx990803 的看法,npm 很好。

@jayli
Owner
jayli commented Aug 31, 2015

@yyx990803 文中提到的几个问题其实已经困扰了我们很久,最大的问题就是设计规则,用最小的成本换来团队内优秀代码的流通,所以有时候不得不取舍。webpack 的确和 CommonJS 是强关联的,全新的 PC 项目用起来会很合适,前提是所有的东东都必须很规范才行。像我们这种整天脏手摆弄代码的,整天为了赶工期净搞一些quick & dirity 勾当的厂内码农,webpack的消费成本略高,为了保持一切都很“整洁规范”,所消耗的不仅仅是工程的工期,可能还有很多过渡设计的成本。

@yyx990803

@jayli 嗯... 有历史包袱的过渡总是会复杂许多,这个我也深有体会。不知道你们厂内具体情况是怎样的,不过制定清晰的规范后在新项目里面小范围试点,如果好用再慢慢推广呢?

@jayli
Owner
jayli commented Aug 31, 2015

@yyx990803 会小范围试一下,新东西和旧业务之间总是需要一个磨合,呵呵

@hkongm
hkongm commented Sep 1, 2015

稍微有点历史的厂,债务就已经不可估算了。。。与开发人员数量成正比。。。
基本还不清啊,还不清

@jiyinyiyong

http://webpack.github.io/docs/ 官方的拼写是 webpack, 总之 P 不大写~

@liuyanghejerry

“为了便于 widget 代码携带 Demo,需要一个本地环境,将源码(src)构建出目标代码(dist)以便运行起来,所以包内必须携带 grunt 或者 gulp 之类的构建脚本”

what?真的要带在同一个npm package里面吗?这不是给自己找茬么,分开不就好了?slider,slider-minmax-demo,这样。

@jayli
Owner
jayli commented Sep 1, 2015

@iuyanghejerry 包代码的构建问题说来话长,你可以看下 kissy 提供的模块,为了方便直接在代码里载入这些包(无需其他配置),所以包里都携带了构建好的 dist 代码,用起来极其方便(直接代码里 use 模块名字即可)。在 PC 项目中这种模式在阿里基本上甩不掉了。这样搞的缺陷是修改起来很麻烦。

@chemdemo
chemdemo commented Sep 1, 2015

赞同 @yyx990803 对于npm/webpack的看法。

统一使用npm托管公共模块,它意味着前后端采用同一种模块化标准开发,不用去理解现存的各种标准(CMD、AMD、CommonJS等),其开发和维护成本何止是加倍这么简单。

但是因为前端和Node.js的运行环境实在是有差异,npm如果能够在package.json有意识地对前端和后端做区分就更好了,比如增加target字段,其中前端模块的依赖可以借鉴bower扁平化的约定。退一步讲,即使npm不这样规定,模块开发者也可以有意识地人为地进行约定。

至于构建工具,目前相对理想的应该就是webpack了。

@fouber
fouber commented Sep 7, 2015

进一步讲,阿里业务的发展实在太快,无线化对研发模式带来极大的冲击,从天猫、支付宝、淘宝等前端团队变化来看,从作为支撑角色的前端,会逐渐强耦合业务,就又加剧了前端技术的多元化和去中心化的大趋势。所以我们经常开玩笑,百度的前端业务得多简单,一个 FIS 就可以支撑百度绝大多数前端业务了。

并不是百度业务简单,而是FIS找到了支撑不同业务类型(从PC到移动,从web到native)之间共性的解决方案,没有凭借其他行政力量而支撑百度大部分前端业务,我想其原因应该是FIS定制的极简规则真正打动了百度前端工程师,否则早就会被挑剔的工程师所抛弃了。


关于组件生态和组件复用,我觉得是不是对(某些)前端场景来说是一个伪命题?虽然看似能提高生产力,但仔细想想其实有不少问题。

前端有两类产品,一种是CRUD类的产品(XX管理系统,XX后台),这类产品交互行为高度一致,具有“可成套复用组件库”的基础;而形如淘宝、天猫、阿里航旅等对外的服务型产品,业务与也业务之间的组件可复用度就应该大打折扣了吧。

借助制造业的概念来类比这两类产品,前者可以实现“减材制造”,就是给你一套功能齐全的组件库,通过删减其中的功能实现业务;而第二类产品,通常都是“增材制造”的过程,这些产品有各自的定制需求,彼此之间可复用的可能性并不高,为了长期维护考虑,一般都选择从0开始建设。

扩大一点,对于GUI软件来说,古往今来,组件生态的概念有真正广泛的成功过么?

@magicdawn

有现成的 util.inherits不用,做个 Function.prototype.derive 做甚~第一眼看不下去

@fouber
fouber commented Sep 7, 2015

@magicdawn 在js中,用派生的语义来构造一个类是没有问题的,甚至由于js语言的特殊性,派生会比继承更直观好用一些,也有项目采用了派生的语义来做OO,比如 WinJS

derive和inherits的用法比较就不贴了,离本主题太远,况且纯属个人喜好。

看不下去什么的多少还是偏见在作祟吧,无解。

@xuheng
xuheng commented Sep 8, 2015

npm完全胜任管理前后端依赖,项目中运用nodejs+react+redux搭建了整个应用,通过webpack+ babel 的组合方式编写es6代码,不需要关心模块化问题,gulp管理整个预处理任务, 至于文中提到的css问题,webpack是可以编译成单独的文件,所以实际使用的时候并没有觉得纠结,反而会暗爽~

@fouber
fouber commented Sep 8, 2015

@xuheng

是外部服务还是内部系统,有没有可访问地址看一下?

@nimojs
nimojs commented Sep 8, 2015

@xuheng
npm 是如何安装多版本 jquery 的,比如项目同时使用 jquery@1.11.2 和 jquery@2.0.0

@appleboy
appleboy commented Sep 9, 2015

@nimojs 我比較好奇的是,什麼狀況會使用到兩個 jQuery 版本?

@magicdawn

一个系统直接依赖 jQuery 两个版本是想干啥

@fouber
fouber commented Sep 9, 2015

@appleboy @magicdawn 可能选用了两个生态中的组件,而这两个组件依赖了不同的jquery版本吧,并不一定是开发者自己想找别扭。。。

@xuheng
xuheng commented Sep 9, 2015

@fouber 外部系统,已经提测了,开发整体来说比较顺利,有一些小坑不过都能解决,这里有个简单的介绍http://cnedwan.com/2015/08/22/%E5%9F%BA%E4%BA%8EReact%E6%9E%84%E5%BB%BAspa%E5%BA%94%E7%94%A8.html

@xuheng
xuheng commented Sep 9, 2015

@nimojs 用npm管理前端代码,还是看项目有没有需要,不一定非要使用,比如我们用npm管理前后端代码,是因为用了react、redux等一些现代框架,顺理成章我们就用了es6编写前端业务,接着用了es6的模块化, 因为es6的模块化兼容node_module这种方式,所以我们就采用了npm管理前后端代码

@fouber
fouber commented Sep 9, 2015

@xuheng 等上线了再看看吧

@magicdawn

所以那就不是直接了, 间接引用两个版本, 这不就是每个module都有自己的node_modules初衷么

@fouber
fouber commented Sep 9, 2015

@magicdawn

@jayli(作者):npm不爽,每个module都有自己的node_modules,物理上都是复制存储的
@yyx990803:npm3 自带模块去重
@nimojs:去重前提下,如果选了两个依赖不同semver版本jquery的生态组件怎么搞?
@magicdawn: 这不就是每个module都有自己的node_modules初衷么?
...
@jayli(作者):npm不爽,每个module都有自己的node_modules,物理上都是复制存储的

是要这么循环讨论下去么。。。

@nimojs
nimojs commented Sep 9, 2015

@appleboy
@magicdawn
这里的 jquery是举得一个例子,比如某个业务模块在产品中应用了 dialog@1.0.0 版本,因为新增了需求这个业务模块更新到了 dialog@1.0.1 ,我希望以后新的页面都用dialog@1.0.1。但是我希望老页面还是用 dialog@1.0.0 ,因为更新组件是有出错的风险的(或者将老页所有相关页面都测试一遍)。

所以会存在一个组件存在多个版本。

@appleboy
appleboy commented Sep 9, 2015

@nimojs

如果是我的話,把舊的頁面升級,或許會是比較快的方式。對我而言,如果拆成兩套,一來不好維護,二來在上線時,要跑的 job 或多出許多。通常而言,把 jQuery 的 Chnage log 看完,理論上就可以直接升級,除非寫法差異很大。

@wangfupeng1988

拥抱变化,持续发展。前端正在慢慢撑起半边天。

@alcat2008

通篇看下来,里面提到了

生产环境只支持静态 HTML

在我看来,这样能最大层面上保证页面 “秒开” 。

同时,也多次提到 css 的优先加载。但目前来看,基于 React 的 SPA 大行其道。

只先加载了 CSS 而 template 还没有被 JavaScript 初始化,那这些样式并没有更早于 JS bundle 发挥价值

这完全适应于 React 的场景。那此种情况下,如何才能保证其渲染或者加载速度,达到 “秒开” 呢?

全明星团队打造的 ant.design ,其官网的打开速度在我看来也不是非常的理想。

@afc163
afc163 commented Nov 9, 2016

@alcat2008 网站部署在美帝,国内肯定慢。

@alcat2008

@afc163 是的,仔细看过整个项目,知道它是 gitpage。

ant.design 打开就是一个很炫的 loading 动画,之后要等待一个 1.6M (gzip 515k) 的 index.js 加载完成页面才会真正开始渲染,可以脑补下网速稍差时的等待情形。

基于 React 的 SPA 应用,都会有一个大 jsbundle。即使通过 require.ensure 之类的方案进行 trunk,依然会有较为长时间的加载等待时间。相比静态 HTML 页面还是有劣势。

主要是想了解: 如何才能保证其渲染或者加载速度,达到 “秒开” 呢?

@afc163
afc163 commented Nov 9, 2016

目前能解决首屏速度问题的只有服务端渲染了,后续 https://github.com/benjycui/bisheng 会探索在静态站点进行服务端渲染的方案。

@alcat2008

@afc163 服务端渲染还需要对现有项目进行调整,不是理想的 “前端” 方案。

之前看 bisheng,只看到其构建能力。持续关注,希望能爆出惊喜。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment