初识 Flutter 还是在上个月的 GMTC 大会上。来自 Google 的工程师现场演示了如何使用 Flutter 构建美观、高性能的移动应用。个人对其中一些特性,比如良好的开发者体验、优秀的跨平台能力很感兴趣。于是决定在会后亲自体验一下。
最近几天尝试使用 Flutter 把京东 APP 中的排行榜频道的首屏布局实现了一下,算是对基于 Flutter 的开发有了一个最简单的了解,特地记录一下,方便其他想了解、尝试 Flutter 框架的小伙伴。
首先看看我实现了一个什么样的界面:
接下来让我们从不同方面说说 Flutter 的开发。
Flutter 开发环境搭建 安装 Flutter 不同平台的安装流程基本一致,这里就以 macOS 为例。首先下载 flutter macOS 版,并解压。
把 Flutter 的 bin 目录添加到系统 PATH 中:
export PATH=~/Software/flutter/bin:$PATH 提示:记得把这行代码放到你的 shell 启动脚本中,避免每次都要手动执行。
路径添加完成后就可以执行 flutter 命令啦。 Flutter 提供了一个 flutter doctor 命令协助我们安装 Flutter 的依赖。它会检查本地是否有 iOS 和 Android 的开发环境。如果检测到依赖缺失,它还会给出对应依赖的安装方法。你只需要不断执行该方法,然后安装缺失的依赖,直到全部依赖安装完成即可。
配置代码编辑器 主要是给 IDE 安装相关插件。
VS Code 上只需要安装 flutter 扩展即可。 Android Studio 上需要安装 flutter 和 dart 两个插件。
图片来自 https://blog.algolia.com 在上一篇文章中我们介绍了什么是单元测试以及单元测试框架 Jest 的基本用法。在本文中我们会具体聊聊如何用 Jest 为 React 组件编写单元测试。
首先我们要明确的一点,那就是 React 组件的单元测试本质是也是单元测试。因此它也符合我们之前介绍过的单元测试的全部特点。唯一不同的地方在于 React 组件的单元测试中我们需要找到合适的方法对执行结果进行断言。换言之,我们要根据 React 的特点来设置代码是否正确执行的判断条件。
那么 React 组件和其它的被测试对象有何不同呢?仔细想过,我们会发现:
React 组件的 render 结果是一个组件树,并且整个树最终会被解析成一个纯粹由 HTML 元素构成的树形结构 React 组件可以拥有 state,且 state 的变化会影响 render 结果 React 组件可以拥有生命周期函数,这些生命周期函数会在特定时间点执行 知道了要测试的内容,接下来的问题就是如何执行一个 React 组件并编写断言了。如何执行一个 React 组件呢?看到这个问题估计大多数儿人是蒙的。平时不就是直接 ReactDOM.render 吗?不错,ReactDOM.render 确实可以执行一个 React 组件并将它渲染到页面中,但这种方式不利于编写测试代码。
有没有更简单的方式呢?其实 React 已经帮我们提供好了工具,让我们一起来看看。
React 提供的测试工具 在 React 的官方文档中提到了两个用于测试 React 组件的库。让我们分别介绍。
react-test-renderer 在说 react-test-renderer 之前,让我们先聊聊什么是 renderer。React 最早是被用来开发网页的,所以早期的 React 库中还包含了大量和 DOM 相关的逻辑。后来 React 的设计思想慢慢被迁移到其它场景,最被人们熟知的莫过于 React Native 了。为了灵活性和扩展性,React 的代码被分拆为 React 核心代码与各种 renderer。React 自带了 3 个 renderer,前两个是大家常见的:
今天来说说如何书写好的 commit message。
Commit message 大家应该每天都在写,每次使用 Git 提交代码时,我们都会在执行 git commit 命令时附带上一句话来简要描述此次提交的改动。
Commit message 看似简单,作用却很重要。在阅读代码时,可以通过 commit message 了解到作者编写某行代码时的背景;调查 bug 时可以通过搜索 commit message 快速定位相关的提交记录。
那么什么样的 commit message 才算好的 commit message 呢?
开源社区已经为我们总结出了一套名为 Conventional Commits 的书写规范。很多流行的开源项目都使用了这套规范,如 Karma,Angular 等。其规定的格式如下:
<type>[optional scope]: <description> [optional body] [optional footer] 下面我们分别来介绍一下其中的各个组成部分:
type :用于表明我们这次提交的改动类型,是新增了功能?还是修改了测试代码?又或者是更新了文档?开源社区目前总结出了以下 11 种类型:
build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交 ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交 docs:文档更新 feat:新增功能 fix:bug 修复 perf:性能优化 refactor:重构代码(既没有新增功能,也没有修复 bug) style:不影响程序逻辑的代码修改(修改空白字符,补全缺失的分号等) test:新增测试用例或是更新现有测试 revert:回滚某个更早之前的提交 chore:不属于以上类型的其他类型 optional scope:一个可选的修改范围。用于标识此次提交主要涉及到代码中哪个模块。根据项目实际情况填写即可,最好在项目中规定好模块列表,保持一致性。
什么是单元测试? 测试是一种验证我们的代码是否可以按预期工作的手段。
被测试的对象可以是我们程序的任何一个组成部分。大到一个分为多步骤的下单流程,小到代码中的一个函数。
单元测试特指被测试对象为程序中最小组成单元的测试。这里的最小组成单元可以是一个函数、一个类等等。
单元测试的优势 由于被测试对象的简单(通常只有一个或多个输入以及一个输出),这就决定了单元测试开发起来也很简单,通常每个测试只有几行到十几行不等。测试代码的简单表示它可以被更频繁的执行(事实上,很多单元测试框架都有 watch 模式。每次改动代码时都会自动执行单元测试)。更频繁的执行意味着更早的发现问题。
试想,随着代码的不断迭代,程序中总有某些位置会频繁出现某类问题。在没有单元测试时程序员之间往往都是“口口相传”,隔一段时间很可能由于疏忽还会犯同一个错误。有了单元测试我们就可以为这些问题点编写对应的测试代码,每次提交代码前都执行一遍,可以极大的降低相同 bug 重复出现的概率。
此外,要为一个被测试对象编写单元测试,那么它应该首先是容易被测试的(这似乎是一句废话)。反过来讲,如果你面对一个函数、类却很难编写测试代码的时候,很可能是你的代码设计上存在问题。比如和外部依赖耦合过于紧密。这种情况下,编写单元测试的过程会倒逼我们优化我们代码的结构。将复杂的代码拆解成为更简单、更容易测试的片段。这个过程本身也会潜移默化的提高我们代码的质量。
单元测试的限制/不足 I get paid for code that works, not for tests - Kent Beck
首先,测试代码再简单,也是需要工作量来开发的。必定占用开发人员的时间。因此需要开发人员在投入与收益之间找到一个最佳的平衡点。
其次,单元测试覆盖率往往会给开发人员一种错觉:这段代码的单元测试都通过了(测试覆盖率以及 100% 了),肯定没有 bug。其实不然,单元测试覆盖率与代码质量没有必然的联系。作为开发人员必须尽早认识到这一点。
何时编写单元测试? 开发过程中,单元测试应该来测试那些可能会出错的地方,或是那些边界情况。 维护过程中,单元测试应该围绕着 bug 进行,每个 bug 都应该编写响应的单元测试。从而保证同一个 bug 不会出现第二次。 单元测试中的基本概念? 单元测试一般包含以下几个部分:
被测试的对象是什么 要测试该对象的什么功能 实际得到的结果 期望的结果 mock / spy (下文会详述) 具体到某个单元测试,往往包含以下几个步骤:
准备阶段:构造参数,创建 spy 等 执行阶段:用构造好的参数执行被测试代码 断言阶段:用实际得到的结果与期望的结果比较,以判断该测试是否正常 清理阶段:清理准备阶段对外部环境的影响,移除在准备阶段创建的 spy 等 Jest 简介 Jest 是 Facebook 开发的一款 JavaScript 测试框架。在 Facebook 内部广泛用来测试各种 JavaScript 代码。其官网上主要列出了以下几个特点:
一直以来都使用 nvm-windows 来管理 Node 版本。从没出过问题。今天团队小伙伴来反馈我们的一个内部命令行工具在 Node 6.10.0 上无法安装。于是决定安装一个 6.10.0 调查一下。
于是执行:
nvm install v6.10.0 结果输出:
$ nvm install v6.10.0 Node.js vv6.10.0 is not yet released or available. 似乎是哪里不对了。
于是下意识的 nvm ls available 一下看看:
$ nvm ls available Showing the 15 latest available releases. STABLE | UNSTABLE --------------------------- v8.9.1 | v8.7.0 v8.9.0 | v7.9.0 v8.8.1 | v7.7.4 v8.8.0 | v7.7.3 v7.10.1 | v7.7.2 v7.10.0 | v7.7.1 v7.8.0 | v7.7.0 v6.12.0 | v6.
最近和小伙伴们在尝试做把项目中经常用到的 React 组件整理成一套 React 组件库。为了保证代码质量且方便日后维护,我们决定为组件编写单元测试。接下来几篇文章会聊聊在这个过程中我们遇到的问题以及一些思考。
正文开始 要写单元测试,首先面临的一个问题就是“我该使用哪个测试框架”?
如果你去 Google 上搜索“how to test react component”,在结果页面中你大概会来来回回看到以下几个名词/概念:
Jest Enzyme Mocha全家桶(套餐内容大概率是:Mocha + Chai + Sinon + Istanbul) react-test-renderer react-dom/test-utils 首先让我们来看看这些库的功能和定位,然后再来做选择。
🃏 Jest Jest 是 Facebook 开发的一款 JavaScript 测试框架。在 Facebook 内部广泛用来测试各种 JavaScript 代码。其官网上主要列出了以下几个特点:
轻松上手 使用 create-react-app 或是 react-native init 创建的项目已经默认集成了 Jest 现有项目,只需创建一个名为 __test__ 的目录,然后在该目录中创建以 .spec.js 或 .test.js 结尾的文件即可 内置强大的断言与 mock 功能 内置测试覆盖率统计功能 内置 Snapshot 机制 虽然 Jest 官网介绍中多次 React,但实际上 Jest 并不是和 React 绑定的。你可以使用它测试任何 JavaScript 项目。
最近要为团队内一个项目搭建持续集成。项目代码托管在公司内部的 GitLab 上,于是很自然的选择使用 GitLab 自带的 CI/CD 功能。
在 GitLab 的 CI/CD 流程中具体执行任务的节点叫做 runner。GitLab 中有两种类型的 runner:
Shared Runners 由 GitLab 管理员配置的公有 runner。多个项目公用。作为开发人员无需配置,可以直接使用。 Specific Runners 开发人员为每个代码库单独配置的专属 runner。只能执行所属代码库的任务。需要开发人员手动搭建。 由于我厂的 GitLab 并没有配置任何 Shared Runner。所以只能选择在自己的台式机上手动搭建。
具体流程如下:
Step 1 下载 runner 可执行文件 根据你的环境下载 x86 或者 amd64 版本。
创建 D:\GitLab-Runner 目录,将刚刚下载好的文件复制到该目录并重命名为 gitlab-runner.exe。
Step 2 以管理员身份运行 Git Bash Step 3 访问代码库的配置页获取配置信息 进入代码库主页,依次点击 Settings => CI / CD => Runners settings。
这里展开的信息中有两个字段需要我们记下来。分别是一个 URL 和一个 Token。
Step 4 注册 runner 进入 D:\GitLab-Runner 目录执行命令:
Context API 可以说是 React 中最有趣的一个特性了。一方面很多流行的框架(例如react-redux、mobx-react、react-router等)都在使用它;另一方面官方文档中却不推荐我们使用它。在 Context API 的文档中有下面这段话:
The vast majority of applications do not need to use context.
If you want your application to be stable, don’t use context. It is an experimental API and it is likely to break in future releases of React.
为何会出现这种情况呢?这还得让我们从现有版本 Context API 要解决的问题已经它自身的缺陷说起。
现有版本 Context API 的使用场景以及缺陷 我们都知道在 React 中父子组件可以通过 props 自顶向下的传递数据。但是当组件深度嵌套时,从顶层组件向最内层组件传递数据就不那么方便了。手动在每一层组件上逐级传递 prop 不仅书写起来很繁琐同时还会为夹在中间的组件引入不必要的 prop。这时 Context API 就派上用场了。你只需要在外层组件上声明要传递给子组件的 Context:
本文来和大家聊聊 pkg.module 字段的功能以及使用场景。
在谈 pkg.module 之前,让我们先来了解一个和它有着紧密关系的概念 —— Tree Shaking。
什么是 Tree Shaking? 让我们通过两个小例子来了解。
假设我们有以下两个文件:
// math.js exports.add1 = function (x) { return x + 1; } exports.add2 = function (x) { return x + 2; } // app.js import { add1 } from './math'; add1(100); app.js 文件通过 import 引入了 math.js 中的 add1 方法。
我们通过 webpack 命令打包:
webpack --entry ./app.js --output-filename app.bunble.js 在生成的 app.bundle.js 文件中我们可以看到以下内容:
这里我们可以看到虽然我们只用到了 math.js 文件中的 add1 方法,但是在最终生成的 bundle 文件中却包含了 add1 和 add2 两个方法。这是为什么呢?
从上个月底开始坚持每天为组内的小伙伴推荐一篇技术文章。内容涵盖各种前端话题,比如 React, Node.js, ES6, React Native, 职业生涯等等。一来可以开阔小伙伴们的视野,二来可以锻炼小伙伴们的英文阅读能力。
从这个月开始,每月最后一天会把当月推荐过的文章列表归档出来。大家可以选择自己感兴趣的话题阅读啦。
20170831 Keep Your Bundle Size Under Control 20170830 Understand async/await better 20170828 How to get the most out of the JavaScript console 20170824 ASYNC/AWAIT WILL MAKE YOUR CODE SIMPLER 20170823 Error handling Promises in JavaScript 20170822 Singletons versus Dependency Injection 20170821 Working with Environment Variables in Node.js 20170818 Rx.js: Operators, Part I 20170817 How to use Memoize to cache JavaScript function results and speed up your code 20170816 Building A Simple AI Chatbot With Web Speech API And Node.