一个项目源码如何入手_新手向:如何给大型前端开源项目贡献源码

参与开源项目对开发者个人的好处是显而易见的:进一步熟悉你所使用的库,和其他开发者进行交流,提高技术水平和社区影响力,发现新的工作机会等等。特别是对于没有工作经验的在校大学生来说,参与开源项目是体现技术热情和积累经验的一个好方法,能在简历筛选和面试环节得到面试官的青睐。

这篇文章将会和大家分享如何参与大型前端开源项目的开发。你将会看到:开源的门槛其实并不高,只要有贡献代码的意愿并了解最基本的流程,任何人都可以给大型前端开源项目添砖加瓦。

为了方便你理解这篇文章的内容,我会以我之前给西湖区最大的 React 组件库 Ant Design 做的一个新功能为例来讲解。这个新功能使得用户能够通过唯一的 key 来修改消息框(Message)的内容。

绝大多数的前端开源项目都在 GitHub 上维护。开源项目的用户们会将他们找到的 bug 或是功能请求(feature request)提交到这些项目的 issues 列表当中,贡献代码的第一步就从这里开始,即:找到你感兴趣的 issue。

如果你还不了解 GitHub 及它的基本使用,可以参考这一篇知乎回答:如何使用 GitHub。

比如 Ant Design 的 issues 中,你可以看到许多 bug 反馈和功能请求。

5163b7ed7b77b5c29ba331bf5ce85f99.png

如何找到适合自己的项目和 issue,哪些 issue 比较容易上手呢?

对于新手来说,最好找这样的一些项目:

  • 工作和学习中使用较多,比较熟悉的项目,这样你在动手阅读、修改它的代码之前就已经对它有了充分的了解
  • 各个模块耦合性比较低的项目,比如组件库(比如 Ant Design)、工具库(比如 lodash),方便定位问题,找到入手点;相反,模块之间耦合性比较大的项目可能就不太合适,例如前端框架

issue 方面,建议寻找这样的 issue:

  • 小的功能需求,可以允许复用项目中已有的代码。在本文的例子中,用户所请求的功能其实在 Notification 组件上已经有实现,这样对我们解决这个 issue 就很有帮助
  • 一些 issue 会被项目官方团队标记为 Good First Issue,是官方认为比较适合初次贡献者的,比如 Angular 组件库 ng-zorro-antd 就有这样的一些 issue
  • 错别字、文档翻译、国际化。这些一般都不 touch 到库的核心功能,难度较低而且不会引入 bug,可以放心地把它们作为你的开源初体验

找到了想要解决的 issue 之后,在 issue 下面留言说你想要负责这个 issue,一般项目的维护者都会把这个 issue 交给你。你可以看到我在原 issue 下的回复。

维护者们都巴不得有人来完(tian)善(keng)他们的项目呢,所以尽管留言吧!

对于你的初体验,要记得 issue 的难度并不重要,重要的是走一遍贡献代码的流程,了解开源社区是如何协作的。

好了,现在我们手头已经有了一个待解决的 issue,接下来我们需要了解这个项目是如何运作的。

阅读源码的能力是必须的,这里推荐阅读《如何阅读大型前端开源项目的代码》。

了解项目的第一步永远都是先把这个项目在本地运行起来。

如果你在阅读下面的内容的时候发现对一些概念一无所知,请立刻回头阅读 如何使用 GitHub。

首先你要 fork 该项目,fork 意味者创建一份源仓库的拷贝,在贡献代码的时候,我们没有向源仓库推送(push)代码的权限,往往都需要先推送到自己的拷贝上,然后请求项目的维护者们合并我们的新代码,即发起 Pull Request。

你可以看到我的账户底下就有一份 ant-design 的 fork。

然后把 fork 后的代码 clone 到你的电脑。

b46c9e5fb77e2ed5908c610cab73c024.png

通过 npm 或者 yarn 安装依赖。

一般通过查看 package.json 文件的 scripts 字段,就可以知道如何运行该项目,进行测试等等。对于 Ant Design,只需要运行 npm start 就可以。

b50f8ee7e58d66552132da313e6eb04d.png

下面我们就要解决 issue 中提出的功能请求了。

这一段会比较具体,对于其他开源项目不具有通用性,不感兴趣的话可以直接跳过。

我们先前提到 Notifcation 组件早已实现了此功能,先来看看它是如何实现的。

我们可以追溯到,当用户通过 Notification.open 方法创建一个 Notification 实例的时候,最终会调用到 getNotificationInstance 方法上(源码在此)。

getNotificationInstance(
    {
      prefixCls: outerPrefixCls,
      placement,
      top,
      bottom,
      getContainer,
    },
    (notification: any) => {
      notification.notice({
        content: (
          <div className={iconNode ? `${prefixCls}-with-icon` : ''}>
            {iconNode}
            <div className={`${prefixCls}-message`}>
              {autoMarginTag}
              {args.message}
            </div>
            <div className={`${prefixCls}-description`}>{args.description}</div>
            {args.btn ? <span className={`${prefixCls}-btn`}>{args.btn}</span> : null}
          </div>
        ),
        duration,
        closable: true,
        onClose: args.onClose,
        onClick: args.onClick,
        key: args.key,
        style: args.style || {},
        className: args.className,
      });
    },
  );
}

可以看到 key 是第二个回调参数的一部分。那么在 Message 组件中有没有类似的代码呢?可以发现的确存在这样的代码(链接在此)!

function notice(args: ArgsProps): MessageType {
  const duration = args.duration !== undefined ? args.duration : defaultDuration
  const iconType = {
    info: 'info-circle',
    success: 'check-circle',
    error: 'close-circle',
    warning: 'exclamation-circle',
    loading: 'loading',
  }[args.type]

  const target = key++
  const closePromise = new Promise(resolve => {
    const callback = () => {
      if (typeof args.onClose === 'function') {
        args.onClose()
      }
      return resolve(true)
    }
    getMessageInstance(instance => {
      const iconNode = (
        <Icon
          type={iconType}
          theme={iconType === 'loading' ? 'outlined' : 'filled'}
        />
      )
      const switchIconNode = iconType ? iconNode : ''
      instance.notice({
        key: target,
        duration,
        style: {},
        content: (
          <div
            className={`${prefixCls}-custom-content${
              args.type ? ` ${prefixCls}-${args.type}` : ''
            }`}
          >
            {args.icon ? args.icon : switchIconNode}
            <span>{args.content}</span>
          </div>
        ),
        onClose: callback,
      })
    })
  })
  const result: any = () => {
    if (messageInstance) {
      messageInstance.removeNotice(target)
    }
  }
  result.then = (filled: ThenableArgument, rejected: ThenableArgument) =>
    closePromise.then(filled, rejected)
  result.promise = closePromise
  return result
}

那我们是不是依样画葫芦,直接允许 key 使用用户传递进来的值呢?试了一下果然可以!

- key: target,
+ key: args.key || target,

这功能实现起来就非常简单。我们接着修改一下测试,添加一下 demo 即可。

以下是对该功能的测试代码(链接在此):

it('should support update message content with a unique key', () => {
  const key = 'updatable'
  class Test extends React.Component {
    componentDidMount() {
      message.loading({ content: 'Loading...', key })
      // Testing that content of the message should be updated.
      setTimeout(() => message.success({ content: 'Loaded', key }), 1000)
      setTimeout(() => message.destroy(), 3000)
    }

    render() {
      return <div>test</div>
    }
  }

  mount(<Test />)
  expect(document.querySelectorAll('.ant-message-notice').length).toBe(1)
  jest.advanceTimersByTime(1500)
  expect(document.querySelectorAll('.ant-message-notice').length).toBe(1)
  jest.runAllTimers()
  expect(document.querySelectorAll('.ant-message-notice').length).toBe(0)
})

开源项目特别重视测试,还会有覆盖率检查工具来检查是否有代码未被测试覆盖,当你修复了一个 bug 或者新增了一个功能的时候,记得一定要写测试!

再改改文档,说明我们增加了这样的一个功能,就可以发起 PR 啦。

发起 PR(Pull Request)时,需要 commit 代码,然后 push 到你 fork 的仓库。

如果你同时给一个项目解决好几个 issue,你应该从 master 分支 checkout 出多个分支,然后分别在这些分支上解决 issue。更好的实践是永远 checkout 一个新分支来解决 issue,不要向 master 分支提交任何代码。

提交 PR 之前,你并不需要确定已经做到尽善尽美了,肯定有一些东西要和项目维护者们进行讨论。

之后在 GitHub 上发起 PR,当你在 fork 的仓库推送了分支时,GitHub 会很聪明地询问你是否要发起 PR,点击绿色的小按钮之后,填写 PR 模板即可发起 PR。

2908c668b939de63a1c8de0124707b74.png

534701d9666b2c5039ac3a1783d6912c.png

“烦人”的维护者们是不会轻易让你的代码进入他们的主分支的!你必须接受维护者们的代码 review,有时候他们会要求你做出一些修改。

比如 afc163 认为加入 key 后参数数量过多,要求实现以对象的形式传参。

当然他们也是为了保证代码的质量而非存心跟你过不去,而且和维护者们的互动有助于你写出更鲁棒的代码和更精炼的 API 哦。

这种 review 和修改和互动可能会有很多轮。如果维护者们对你的 PR 和修改没有做出回应,你可以主动 @ 他们。

当维护者们对所有事情都表示满意,approve 了你的 PR,你就可以坐等代码被合并到 master 并成为该项目的 contributor 啦。之后你参与该项目的讨论时就会有个 Contributor 小徽章时刻提醒那些小白你是多么的牛逼(逃

d6340c68a7ef723d750988472f04b65d.png

温馨建议

  • 保持礼貌
  • 学好 Git,包括但不限于这些常用命令:fetch pull add commit push merge rebase
  • 在给任何项目做贡献之前,请务必阅读该项目的贡献指南,比如 Ant Design 的。这些指南往往能够帮助你更好地了解维护团队的工作流程,有些项目对 commit message 还有一定的要求,请务必遵照执行,这会让你的开源之旅更加顺畅
  • 时刻关注想要贡献的项目的 issues 界面,有想做的 issue 直接留言
  • 关注官方团队的开发者博客或者维护者的个人博客,了解项目的最新动态和技术细节
  • 不把参与开源当作很难的事

Happy coding :)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值