引言
在很早以前,开源软件的开发并不受待见,甚至受到排挤,普遍认为软件是商业性质的产物,开源没有任何利益,也没有一个很好的平台去分享自己的技术成果。如今,观念发生了转变,认为开源更易于发现问题,解决问题,促进技术交流,技术升级,技术创新,并且能推动公司业务的发展。随着大型同性交友平台Github的诞生,吸引了全球范围内无数的开发人员共同参与到开源项目中,开发者可以自由的创建项目,分享代码,共同合作完成一个项目。近几年,Github开源项目数量呈指数型增长,已然成为一个趋势,尤其是JavaScript脱颖而出,成为了毫无疑问的最热门语言,本文谈谈参与一个前端开源项目你需要了解并具备哪些知识。
包管理器
社区中几乎每一个开源项目都是采用NPM作为包管理器,当然也有一小部分使用了Bower包管理器,比较新的项目则采用Yarn来替代NPM管理模块。
NPM & Yarn
NPM生成的入口文件是package.json,需要指定必要的基本信息,以及编写npm run
快捷脚本命令。
- name决定模块的名称,不允许与npm社区中的已发布模块同名,模块发布后,其他开发者可以通过该名称安装该模块。
- version需遵循语义化版本规范,格式为[MAJOR].[MINOR].[PATCH],分别代表主版本,次版本,补丁版本,可以通过执行
npm version
命令自动更替版本。 - main表示模块的入口文件,用户通过
require('example')
加载该入口文件。 - license声明版权类型,若是私有项目,则设置
"license": "UNLICENSED"
或者"private": "true"
,这种情况下,执行npm publish
发布模块将会失败。 - scripts用于编写自定义npm脚本命令,通常上包括开发、编译、打包构建、测试、格式检查、文档构建等常用脚本命令,对于复杂脚本命令,可以单独写在shell脚本文件里,一般放在根目录下scripts文件夹中。
一个基本的package.json示例如下:
{
"name": "example",
"version": "1.0.0",
"description": "This is an example project",
"keywords": [
"example"
],
"main": "lib/index.js",
"scripts": {
"dev": "webpack --config webpack.dev.config.js",
"build": "webpack --config webpack.prod.config.js",
"lint": "eslint src",
"test": "mocha *.test.js",
"docs": "gitbook build",
"clean": "rm -rf ./dist",
},
"dependencies": {
},
"author": "xxx",
"repository": {
"type": "git",
"url": "https://github.com/xxx/xxx.git"
},
"license": "MIT"
}
自动化构建及模块打包器
Gulp/Grunt属于自动化构建工具,是为了解决前端工程化中重复性、繁琐性的工作如配合第三方插件进行编译、压缩、合并、复制等文件操作。而Webpack/Rollup/Browserify定位是模块加载兼打包器,支持打包AMD/CMD/COMMONJS/ES6/HASTE/UMD等模块规范,随着生态的壮大,插件机制越来越丰富,越来越完善,在某些场景下已经完全可以取代Gulp/Grunt的工作。
ES6+Webpack+Babel
老项目仍采用Gulp+Webpack等双机制构建,主流项目采用纯粹的Webpack结合各种loader插件及配置打包构建。如今,Webpack生态和Babel生态受到了越来越多开发者的青睐,具备可配置性高、可扩展性高、功能丰富强大等特点,开发者可以自由地制定插件及引用第三方插件,两者协同工作,可以尽情地体验ES6/7/8的开发。
测试
一个大型可靠的开源项目离不开测试,测试可以帮助开发人员及时发现问题,定位问题,提高代码质量,保证输出结果的正确性,避免缺陷回归,减少每次修改代码后人工review大量代码的成本,可分为测试驱动开发(TDD)和行为驱动(BDD)开发两种类型。另一方面,开发者不仅可以通过阅读文档还可以通过阅读测试用例来看懂程序的功能,尤其是当一个项目越来越庞大,逻辑越来越复杂,就需要根据测试用例通过与否、测试覆盖率等指标来衡量项目的质量。
- 测试执行工具:Karma
- 测试框架:Mocha/Jasmine/QUnit/AVA/Jest/Enzyme
- 断言库:Chai/Expect/Should/Assert
- 覆盖率:Coveralls/Codecov/Istanbul/Isparta
Karma+Mocha+Chai
Karma是一个测试执行过程管理工具,原名Testacular,该工具主要作用是让测试用例跑在所有主流浏览器如Chrome/Firefox或者无界面浏览器PhantomJS上,所以如果你的代码是设计在浏览器上的,那么使用Karma的测试结果更贴近真实环境。
测试框架有很多,从NPM下载量上来看,Mocha是下载量最高的测试框架,它可以同时运行在浏览器和Node端,Mocha本身不带断言库,扩展性高,支持异步测试,需要结合第三方断言库如Chai(支持TDD/BDD)实现单元测试。
测试覆盖率是一项衡量测试用例设计好坏的硬性指标,如可以使用覆盖率统计工具Istanbul结合测试框架Mocha进行测试,自动分析、记录并保存测试结果,生成测试报告,最后通过Coveralls上传至远程服务器。
Linter
一个大型可靠的开源项目也需要统一代码风格,强调代码质量,遵循同一套规范标准,例如缩进格式,是否使用分号等等,其直接影响了项目的可维护性,合作性。因此,就需要引入Linting工具来检查约束代码格式,各大公司也纷纷制定了自己的Javascript编码规范,如Google/Airbnb/Clean Code等等。当然,每个项目代码风格各不相同,萝卜青菜,各有所爱,这完全取决于项目维护者的偏好!
King of Linter
目前Linter工具主要有ESLint/JSCS/JSHint/JSLint等等。ESLint毫无疑问已经成为最主流的Linter,提供了丰富的插件,可配置性很高,支持JSX语法,生态越来越完善。ESLint的优点是完全插件化,每一个规则都是一个插件并且你可以在运行时通过注释添加更多的规则,或者禁用某项规则。此外,执行eslint --fix
命令可快速修复部分常见可自动修复错误,便捷快速强大,开源项目必备。
持续集成
持续集成在开源项目中不可或缺,每次代码提交或PR后都会在持续集成服务器上触发一次自动化测试构建部署,确保开发人员对项目源码作出的更改不会导致程序发生错误,减少了风险,增加了项目的可靠性。
Travis CI
目前,前端项目中比较流行的持续集成工具有TravisCI/CircleCI/AppVeyor等等,配置文件一般是一个YAML文件。以Travis CI为例,需要在根目录下创建一个.travis.yml
文件,并指定一些基本配置信息,例如语言、运行环境、执行脚本命令、启用缓存、分支选择等等,当指定分支代码提交后,持续集成环境将会读取该文件并执行相关指令,最后将是否构建成功的结果反馈给用户。
一个Travis配置文件示例:
sudo: false
language: node_js
node_js:
- "4"
- "5"
- "6"
cache:
directories:
- node_modules
script:
- npm run lint
- npm run test
- npm run build
after_script:
- coveralls < ./coverage/lcov.info
branches:
only:
- master
静态网站生成器
每一个庞大的开源项目必然有详细的文档介绍和示例演示,但仅仅依靠README.md文件局限性太大,篇幅不够长,不足以直观地展示所有内容。另一个方案是手动编写一系列HTML文件,每一个HTML文件都包含一系列CSS文件、JS文件,最后部署到自己的服务器或Github Pages网站上。但是,当项目越来越庞大,越来越复杂,时间成本、人力成本将会大幅度增加,开发者不得不花大量精力去维护站点,无法专注于业务编码。正由于这种原因,催生了静态网站生成器的快速发展与普及使用,你可以在StaticGen上找到目前较为流行的静态网站生成器。
Jekyll
静态网站生成器都有一些共同特点,支持markdown格式,更好得适应文档的编写,将网站组件化、模板化,复用公共组件,消除重复组件,并且包含一个资源管道,用于处理资源编译、转译、打包、压缩。除此之外,静态网站生成器还会提供一个命令行功能用于在本地服务器构建网站进行实时预览。在项目中,一般把文档放在根目录下docs文件夹中。
必备文档
README.md
开源项目的门面,让用户第一时间了解该项目具体是做什么的,一份好的README文件应包含但不仅限于项目标题、描述、徽章、主要内容、如何安装、如何使用、API文档、如何参与贡献、版权类型等等内容。
CHANGELOG.md
用于记录每一次版本升级后的更新说明,包括Bug修复、新功能等等,一般和项目新Tag一起发布。
CODE_OF_CONDUCT.md
行为守则是一套个人或组织参与开源项目所必须遵循的规则,规范,公约,大多数项目都是采用Contributor Covenant规则。
CONTRIBUTING.md
全方位指导你如何参与贡献代码,如何进行本地开发,如何提ISSUE,如何提PR等等,参与项目前必看的文档。
ISSUE_TEMPLATE.md
ISSUE模板,提ISSUE时Github自动识别读取注入。
PULL_REQUEST_TEMPLATE.md
PR模板,提PR时Github自动识别读取注入。
其它
目录规范
常见目录结构及文件说明,以下只列出一部分,实际项目可变通
root/
├── .github/ # ISSUE&PR模板文件夹
├── bin/ # 命令行指令入口文件夹
├── build/ # 工程配置类文件夹
├── dist/ # 打包输出后的产品文件夹
├── docs/ # 文档文件夹,最终被静态网站生成器编译
├── examples/ # 使用示例文件夹
├── packages/ # 子模块文件夹
├── lib/ # es编译后的输出文件夹
├── scripts/ # 脚本命令文件夹
├── src/ # 源代码文件夹
├── test/ # 测试文件夹
├── .babelrc # babel配置文件
├── .editorconfig # 编辑器配置文件
├── .eslintrc # ESLint配置文件
├── .eslintignore # ESLint忽略文件
├── .flowconfig # Flow配置文件
├── .gitattributes # Git属性配置文件
├── .gitignore # Git忽略文件
├── .npmignore # NPM忽略文件
├── .stylelintrc # StyleLint配置文件
├── .travis.yml/circle.yml # CI环境配置文件
├── CHANGELOG.md/History.md # 版本更新说明文件
├── CODE_OF_CONDUCT.md # 行为守则说明文件
├── CONTRIBUTING.md # 贡献指导文件
├── AUTHORS # 贡献者列表文件
├── LICENSE # 版权声明文件
├── PATENTS # 专利声明文件
├── README.md # 自述文件
├── Makefile # Make命令文件
├── Gruntfile.js # Grunt配置文件
├── gulpfile.js # Gulp配置文件
├── karma.conf.js # Karma配置文件
├── webpack.config.js # Webpack配置文件
├── rollup.config.js # Rollup配置文件
├── bower.json # Bower入口文件
├── package.json # NPM入口文件
└── yarn.lock # Yarn生成的模块记录文件
结尾
无论你是小白或是大牛,希望读完此文能让你有所收获,可以对开源项目的结构、模式大致有所了解。实际上,一个大型的开源项目往往要面临和解决各种各样的问题,项目的维护者需要付出很多的时间与精力。近几年,开源项目的产出速度越来越快,不断涌现新框架、新工具、新库,但国内优秀的开源项目仍旧为数不多,大部分只是在造轮子,任重而道远,与此同时,我们更应该注重开源项目的质量,也希望更多的人参与到开源项目中。