大约三年前,我写了一篇《 前端开发者的基本技能》,嗯,那大概是我最出名的一篇文章。三年后,仍然有人在Twitter上@我询问如何开始学习前端知识。
在某种程度上,我曾经写下的文字历经了时间的考验:令我感到震惊的是,2012年我写的那篇文章并没给我带来难堪的问题。尽管如此,3年之久,很多事情都变得与众不同。2012年我鼓励人们学习浏览器开发工具,紧跟模块化开发大潮;那时候人们还不太接受CSS预处理和客户端模板这类新事物,它们仍然值得一提;相比于JSLint锱铢必较的精确(甚至让人感到厌烦),JSHint非常受欢迎,它使我们彻底解放。
现在时间来到了2015年,我想写一个升级版的前端指南,但是当我坐下动笔开始写的时候,我突然意识到两件事情:
相对来说,称这篇文章为基本技能是不公平的,如果你回忆起以前的文章,你会发现这篇文章仿佛偏离了基础。人们可能会争辩说,我们应该考虑那些能让我们找到工作的技能来作为基本技能。但是事实上,市场上有很多前端的工作可以选择,为了得到一份工作你并不需要太多的基础。于我而言,我并不想简单找一份工作了事,我希望参与到一份绝妙的工作中去;我不想简单工作就度过一整天,我希望能够与有才能的人一起工作;我不想从事那些已经被大众所熟知的,坐在这里稍作思考,预计差不多明天之前就可以完成的那种工作,我希望从事那些,因为我知道如何去工作,我能在明天之前钻研出一个成果,所以我明天可以顺利完成任务的工作,对,就是有挑战的那种!
我的世界正在变得彻底以JavaScript为中心:除了一些必要的性能优化,我的日常工作接触到的CSS知识越来越少。我知道有许多非常聪明的前端开发者,他们的JS和CSS技能都很厉害,但是根据我的观察,专注研究JavaScript和专注研究CSS的人们正在逐渐分离。我大概可以写另外一篇博文来阐述这个话题,但在这里我只想说:我没有做过多有关CSS的准备,所以不要对这一点抱有过多的期许。
简而言之:当你以你的前端世界的视角来阅读这篇文章,不一定能找到你需要的内容。但请谨记,我们都是很棒的开发者!
JavaScript
记忆回到2009年,如果你在文章里读到类似“HTML5将会在2014年定稿使用”的预言,是否看起来那一天还很遥远?如果当时你这样想,你将要准备好迎接缓慢更新但是稳步向前的ES6(现在被称为ES2015,这个名称已经随处可见),也就是下一个版本的JavaScript。准备与ES6——啊不对,ES2015——接轨吧,毫无疑问,这是接下来在JavaScript领域中最重要的事情。ES6 classes、真正的隐私、更好的函数和参数、可引入(import)的模块以及许多其它特性,一定会彻底改变游戏规则。那些能力十足并且十分高产的新语法无疑将会彻底从JS社区中孕育出来。为此,你需要阅读:
理解ES6,一本Nicholas Zakas正在撰写的书籍,目前已开源(译注: 新坑已开,欢迎一起填坑)。
BabelJS,一个允许你编写ES6代码并将其编译为可以在市面浏览器中运行的ES5的工具。他们还有一个非常棒的 学习章节。
ES6 Rocks,有很多探索ES6特性、语义和坑的文章。你是否需要成为一位ES6/ES2015专家?或许现在不需要,但你至少应该了解足够多或者更多有关ES6的知识才能不落后于你的同行。你在开发下一款新项目的时候,尝试一下ES6吧,未来近在眼前,只待你去拨开它的面纱。
新的语言特性先暂且不谈,你应该能够流利地说出JavaScript的异步模式,并且使用回调和promise来管理它。关于在浏览器中加载应用并在每个应用之间通信的策略,你应该拥有足够完备的见解。你也许应该掌握一个你非常喜欢的应用开发框架,同时也应该对其它的框架是如何运行的有一个概览,你需要稍作权衡选择你喜欢的那一个。
模块和构建工具
毫无疑问,模块应当是客户端Web应用的构建元素。回到2012年,关于使用什么类型的模块来构建浏览器应用的讨论此起彼伏,不过基本围绕着 AMD和 CommonJS展开。还有一个略显粗俗的 UMD包装器尝试融合二者来方便大家重用代码——他们认为,既然长得差不多,不如多写点儿代码来同时支持二者。
我认为这场争论没有一个统一的结论,但是我感觉这是自2012年我写文章之后,这个领域中最大的转变,当然这也可能只是我个人的心路历程。我没有彻底搞定AMD,但是我被它的实用性征服了,你可以使用CommonJS开发并部署Web应用,使用npm引入模块。
RequireJS为模块通信做了很大的贡献,出于对它的厚爱,我现在有点儿迷恋W ebpack了。webpack的功能——例如容易理解的构建参数(译者注:build flag,命令行中形如-p的参数)——相比于RequireJS来说更容易理解。通过它的内建开发服务器实现的热交换构建打造了一个快速且令人愉悦的开发传奇。它并不强制你使用AMD或者CommonJS,因为它同时支持两者。还有非常多的加载器,使得完成许多相同工作对它来说简直是小意思。你也可以去了解一下 Browserify,但在我看来,一定要在熟悉了Webpack之后再去搞它,我信任的聪明人儿告诉我, systemjs在这个领域也是一个的认真的竞争者,但是我还没用它呢,它的文档让我很想拜读。它的包管理器 jspm很迷人,允许你从包括npm在内的不同的源拉取所需的模块,但是我有点儿担心这俩货结合起来会有些问题。我不得不重复,我从没想过我会与AMD分开,但是看起来我不得不放弃它了,我们终将会看到这事情的发生。
我仍然渴望有一天我可以停止喋喋不休地争论有关模块和构建工具的话题,那时候全世界只有一个模块系统,这样就可以在所有项目里共享使用代码,同时还能免去使用UMD的开销。理想情况下,那一天将会因为ES6模块而变为现实——在这一天到来前你可以使用转译器(Transpiler)来填补空缺——但我发现很有可能我们会持续不断地找一些方法让它变得愈发复杂。
与此同时,前端开发者需要了解至少一对构建工具和相关的模块系统,这需要在实践中不断积累经验。不管怎样,就目前JavaScript的发展情况来说,你仍然需要选择一个模块系统,它将支撑你的每一个项目。
测试
一些新的测试框架,例如 Karma和 Intern,已经让客户端代码的测试变的轻而易举。我发现Intern基于promise来进行异步测试的方法特别(作者拼错了particulary)爽,我不得不承认,大多数时候我依然用Mocha来写测试——有时我还真就是屈于习惯的生物啊。
测试过程中的主要阻碍是前端开发者倾向于写的代码,关于这个问题,我在2012年末公开谈论了有关编写可测试的JavaScript的话题,几个月后随即写了一篇有关这个话题的 文章。
测试过程中第二个大的阻碍是工具化,Web驱动仍然是你需要处理的巨大伤痛。一个复杂UI在所有支持平台上的持续自动化测试依然不可行,即使可行开销也非常巨大,以致于那看起来根本不可能实现——更别提移动端了。很大程度上我们仍然局限于在浏览器、设备、操作系统结合的支持平台的很小的一个子集上做一些轻量级自动化功能测试,并且越来越难以依赖可以快速、便宜地运行的底层测试。有时候想想这个问题就觉得自己弱爆了。
如果你对改进未经检验(不可测试)的代码问题感兴趣,有一本书非常值得一读: Working Effectively with Legacy Code,作者Michael Feathers将“遗留代码”定义为任何没有测试的代码,在测试的话题上,唯一的底线是接受这一说法的真实性,即使其它约束会阻止你解决它。
过程自动化
你很有可能认为 Grunt是任务自动化工具的不二选择, Gulp和 Broccoli提供了一个不同的方法来进行自动构建。我没用过Broccoli,并且我只浅尝了一下Gulp,即使Grunt有一定的局限性,但我绝对要感谢它依靠其它服务帮助我把复杂任务自动化——尤其每天要运行上千次任务的时候。
Yeoman在我2012年写文章之后的45天就发布了。我承认它刚一出来时我并没有用它,但最近我(用不熟悉的技术从纸上草稿开始一个项目)尝试找出如何标准化我们在Bazaarvoice平台上开发第三方JS应用的方法,Yeoman的确在这些案例中闪闪发光。在命令行中输入一个简单的yo react-webpack就可以为你创建一整个新项目,项目里的你想要的应有尽有——测试、开发服务器、一个Hello World应用,以及更多。如果React和Webpack不是你的菜,可能一个生成器就可以满足你的需求,同样,你可以很轻松地打造自己的生成器。
考虑到Yeoman是一个你通常只在项目开始的时候使用的工具。并且考虑到你不总会开始新的项目,它只是一个值得了解的工具。当然了,如果你正在跨越项目尝试标准化实践,那么它或许还有那么一些价值的。
Broccoli作为ember-cli的核心被委以重任,我信任的人们说这一对儿将来会有大作为,还会改一个新的名字,在未来会逐步替代Grunt/Yeoman组合。使用Grunt和Yeoman组合进行开发的确会渐渐淡出人们的视野,所以我们一起看看未来能带来什么有趣的东西。
代码质量
如果你像我一样,当你只要看到代码违反了项目良好的文档风格指南时就情不自禁开始抽搐,那么像JSCS和 ESLint这样的工具简直是天赐之物。2012年的时候他们都还没有出现呢,他们都提供了一个格式化你的样式指导规则的方法,然后在你创建一个pull request之前自动地按照规则校验你的代码,说到这儿我们就不得不提Git了。
Git
我认为自从2012年以来,世界范围内的Git工作流没有太大的变化,话说回来,Github pull request页面上仍然没有给分支名加上链接,谁知道是因为什么天杀的原因。
很显然,在特性分支下工作你应该感到非常舒适,将你与他人的工作成果进行衍合(rebase),借助交互式衍合工具来改写(squash)提交,而且在小的单元里工作不太可能导致随时可能产生的冲突。另一个必备的Git工具的是钩子(hooks)——你尤其需要预推送和预提交钩子来运行你的测试案例并执行所有代码的质量检查。你可以自己写这些钩子,但类似于 ghooks这样的工具可以帮你完成这些繁杂的过程,你没有理由不将他们集成到你的工作流中去。
客户端模板
对于一些“错误”的定义可能是我在以前的文章中犯下的最大的错误。客户端模板仍然很有价值,毫无疑问——它的价值高到它将会内建到ES2015中去——但过度滥用依然会有不好的后果。许多团队将所有的渲染工作转移到浏览器中,极大的性能开销使得这种“客户端生成所有HTML”的方法逐渐失宠,这是来之不易的教训。成熟的项目现在都在服务器端生成HTML——甚至还预生成它,将它存储为静态文件可以快速响应提供服务——然后在客户端逐步补充这个HTML,当事件触发的时候用客户端模板更新它。
我希望无论对于你还是我自己,在考虑到自己的决策对于性能的影响时,不仅局限于浏览器领域,这也就是我接下来要谈到的……
Node
你说你很了解JavaScript,所以接下来的时间我期待你能够深入研究Node,如果你知之甚少,那你起码需要投入一点精力去了解它。的确,Node世界里有一些有关文件系统、流、服务器的知识,甚至还有一些完全与前端开发不一样的范式,但作为前端开发者,如果你把这些宝贵的财富拒之门外将会极大地限制你的潜力。
即使你实际开发的产品没有使用Node作为项目的后端,你仍然可以利用它来模拟后端服务的状态来尽快完成前端开发。最起码的,你应该熟悉如何 初始化一个Node项目,如何配置一个 Express服务器和路由,以及如何使用 request模块来代理请求。