从零搭建现代 JavaScript 技术栈二Babel、ES6、ESLint、Flow、Jest 与 Husky 完整配置指南【免费下载链接】js-stack-from-scratch️⚡ Step-by-step tutorial to build a modern JavaScript stack.项目地址: https://gitcode.com/gh_mirrors/js/js-stack-from-scratch本文是《JavaScript Stack from Scratch》系列教程的第二章聚焦于如何让一个现代 JavaScript 项目同时具备转译、代码规范、静态类型检查、单元测试与提交门禁这五层能力。你将跟随本仓库 tutorial/02-babel-es6-eslint-flow-jest-husky.md 的完整步骤用 Babel 把 ES6 代码编译为兼容性更好的 ES5用 ESLint Airbnb 规则统一代码风格用 Flow 做静态类型检查用 Jest 编写单元测试最后用 Husky 把这一切串进git commit/git push的 Git Hooks 中。读完本文你将拥有一套一条yarn test即可完成 lint 类型检查 测试的工程化基线以及一个拒绝坏代码进入仓库的自动化防线。本系列第一章已完成 Node、Yarn 与package.json的基础搭建见 tutorial/01-node-yarn-package-json.md本章在此之上继续为项目装配现代 JavaScript 工具链。本章目标与前置条件本章结束时你的项目将具备Babel把 ES6以及后续章节的 JSX编译成所有环境都能理解的 ES5ESLint基于 Airbnb 配置的代码风格检查包括分号策略、浏览器兼容性检测FlowFacebook 出品的静态类型检查器Jest开箱即用的测试框架附带覆盖率统计Husky把test任务挂载到 Git Hooks提交/推送前自动校验。前置条件已完成第一章的 Node 6.5.0、Yarn 安装项目根目录存在package.json并且index.js中只有简单的console.log输出逻辑第一章末尾的示例使用了color包本章会移除该示例代码。Babel让 ES6 代码跑在任何环境里为什么需要 Babel所有浏览器和 JS 运行时都能良好理解 ES5但对 ES6以及 React 的 JSX 语法支持并不一致。Babel 就是来解决这个问题的编译器它把 ES6 代码转换成 ES5 代码且高度模块化可嵌入大量不同环境。Babel 是 React 社区最主流的 ES5 编译器选择。第一步建立src目录把index.js移入新建的src文件夹这里将成为你书写 ES6 代码的地方。删除第一章中与color相关的代码替换为const str ES6 console.log(Hello ${str})这里用到了模板字符串template string——ES6 特性之一可以通过${}把变量直接注入字符串无需拼接。注意模板字符串使用反引号backquote创建。第二步安装 Babel CLIyarn add --dev babel-cliBabel CLI 提供两个可执行文件babel把 ES6 文件编译成新的 ES5 文件babel-node替代node二进制直接即时执行 ES6 文件。babel-node非常适合开发环境但它比较重不适合用于生产。本章用babel-node搭建开发环境下一章tutorial/03-express-nodemon-pm2.md则会改用babel预先构建生产用的 ES5 文件。在package.json的start脚本中把node .替换为babel-node srcindex.js是 Node 默认查找的文件因此目录名src即可无需写src/index.jsscripts: { start: babel-node src }此时运行yarn start虽然能打印正确结果但 Babel实际上什么都没做——因为我们没有告诉它应用哪些转换。之所以输出正确只是因为 Node 原生支持 ES6。换成某些浏览器或旧版 Node 就不一定了。第三步安装env预设并创建.babelrcyarn add --dev babel-preset-envbabel-preset-env包含了 Babel 所支持的最新 ECMAScript 特性的转换配置。然后在项目根目录创建.babelrcBabel 的 JSON 配置文件让 Babel 使用env预设{ presets: [ env ] }yarn start仍然可以运行但这次 Babel 真的在做事了。由于babel-node是即时解释 ES6暂时看不出明显区别等你读到下文 ES6 模块语法 一节时就会得到代码确实被 Babel 转换过的实锤证据。ES6书写现代 JavaScriptES6 是 JavaScript 语言史上最重要的一次改进典型特性包括class类、const/let声明、模板字符串、箭头函数(text) { console.log(text) }等。创建 ES6 类新建文件src/dog.js写入一个 ES6 类class Dog { constructor(name) { this.name name } bark() { return Wah wah, I am ${this.name} } } module.exports Dog如果你熟悉其他语言的 OOP这段代码不会陌生——但对 JavaScript 来说这是相对较新的语法。类通过module.exports赋值暴露给外部。在src/index.js中引用它const Dog require(./dog) const toby new Dog(Toby) console.log(toby.bark())注意与之前引用的社区包color不同引用自己的文件时require()中必须带./前缀。 运行yarn start应输出 Wah wah, I am Toby。ES6 模块语法ES6 modules syntax把const Dog require(./dog)替换为import Dog from ./dog这是更新的 ES6 模块语法相对于 CommonJS 模块语法。它目前不被 Node 原生支持这正是证明 Babel 正确转译了这些 ES6 文件的证据。dog.js中同步把module.exports Dog改为export default Dog// dog.js class Dog { ... } export default Dog// index.js import Dog from ./dog const toby new Dog(Toby) console.log(toby.bark())yarn start仍应打印 Wah wah, I am Toby。ESLint为团队统一代码风格ESLint 是 ES6 代码的首选 linter。linter 会给出代码格式化建议强制团队风格一致也是通过犯错来学习 JavaScript 的绝佳方式。ESLint 基于**规则rules**工作规则数量众多。与其手工配置每条规则本教程直接采用 Airbnb 团队维护的配置eslint-config-airbnb它依赖几个插件需要一并安装。截至 2017-02-03官方推荐用下面的命令安装原命令中的npm install已被替换为yarn addnpm info eslint-config-airbnblatest peerDependencies --json | command sed s/[\{\},]//g ; s/: //g | xargs yarn add --dev eslint-config-airbnblatest它会自动安装并把eslint-config-airbnb、eslint-plugin-import、eslint-plugin-jsx-a11y、eslint-plugin-react写入package.json。注意该命令在 Windows 上不可用。Windows 用户请查看本仓库的package.json中列出的各包版本手动执行yarn add --dev packagename^#.#.#逐个安装。像配置 Babel 一样在项目根目录创建.eslintrc.json{ extends: airbnb }安装eslint包以使用eslintCLIyarn add --dev eslint然后更新package.json的scripts新增标准的test任务scripts: { start: babel-node src, test: eslint src }这里只是告诉 ESLint检查src文件夹下的所有 JavaScript 文件。后续这个test任务会变成一条命令链串联起 lint、类型检查和单元测试——它就是项目代码质量的总闸。 运行yarn test你会看到一大串缺少分号的错误以及index.js中使用console.log()的警告。在index.js顶部添加/* eslint-disable no-console */允许该文件使用console/* eslint-disable no-console */ import Dog from ./dog ...注意Windows 用户请把编辑器和 Git 配置为 Unix LF 换行符而非 Windows CRLF。如果项目只在 Windows 环境使用可在 ESLint 的rules中添加linebreak-style: [2, windows]强制 CRLF。分号之争安全地去分号JavaScript 的自动分号插入ASI机制允许写代码时不加分号这纯粹是个人偏好没有对错。本教程作者在参考 Redux 文档的代码示例后选择了无分号风格并认为无分号代码更易读、输入更快。如果选择无分号需要注意一些极少数的场景必须加分号。ESLint 的no-unexpected-multiline规则可以保护你避开这些坑。在.eslintrc.json中配置{ extends: airbnb, rules: { semi: [2, never], no-unexpected-multiline: 2 } }semi: [2, never]把分号规则设为错误级别2并要求从不使用分号no-unexpected-multiline: 2同样设为错误防止因 ASI 导致的意外多行解析。 运行yarn test应该通过。试着在某处多加一个分号确认规则确实生效。如果你坚持使用分号也没问题教程代码只是略不方便把 ESLint 改为强制分号后改写过程会很快。若把本教程当样板工程使用只需按 ESLint 提示批量调整即可。Compat检测浏览器 API 兼容性Compat 插件eslint-plugin-compat会警告你使用了目标浏览器不支持的 JavaScript API。它基于 Browserslist依赖 Can I Use 数据。yarn add --dev eslint-plugin-compat在package.json中声明要支持的浏览器——市场份额大于 1% 的浏览器browserslist: [ 1%]更新.eslintrc.json{ extends: airbnb, plugins: [ compat ], rules: { semi: [2, never], no-unexpected-multiline: 2, compat/compat: 2 } }你可以尝试在代码中使用navigator.serviceWorker或fetchESLint 应该会给出警告。仓库的 CHANGELOG.md v2.4.5 中记录了这个插件的加入。在编辑器中集成 ESLint终端里的 ESLint 适合在构建/推送前拦截错误但你很可能希望 IDE 给出即时反馈。不要使用 IDE 自带的原生 ES6 检查而应配置 IDE 使用node_modules里的eslint二进制这样它才能读取项目的完整配置Airbnb 预设等否则你得到的只是通用且无效的 ES6 检查。Flow静态类型检查Flow 是 Facebook 出品的静态类型检查器能检测代码中的类型不一致比如在应使用数字的地方用了字符串。纯 ES6 代码 Flow 也能分析但要发挥全部能力需要在代码中加入类型注解——这会变成非标准语法。因此必须教会 Babel 和 ESLint 认识这些注解让它们在解析文件时不报错。安装与接线yarn add --dev flow-bin babel-preset-flow babel-eslint eslint-plugin-flowtype各包职责flow-bin在scripts任务中运行 Flow 的二进制babel-preset-flow让 Babel 理解 Flow 注解的预设babel-eslint让 ESLint改用 Babel 的解析器而非自带解析器eslint-plugin-flowtype对 Flow 注解进行 lint 的 ESLint 插件。更新.babelrc{ presets: [ env, flow ] }更新.eslintrc.json{ extends: [ airbnb, plugin:flowtype/recommended ], plugins: [ flowtype, compat ], rules: { semi: [2, never], no-unexpected-multiline: 2, compat/compat: 2 } }plugin:flowtype/recommended已包含让 ESLint 使用 Babel 解析器的指令。如果想更显式可以在.eslintrc.json中额外添加parser: babel-eslint。ESLint 竟然能借助 Babel 的解析器理解 Flow 注解——这两款工具的高度模块化正是其强大之处。把 Flow 接入 test 任务scripts: { start: babel-node src, test: eslint src flow }在项目根目录创建.flowconfig[options] suppress_comment \\(.\\|\n\\)*\\flow-disable-next-line这是一个小工具让 Flow 忽略下一行的任何警告用法与eslint-disable类似// flow-disable-next-line something.flow(doesnt.like).for.instance()添加 Flow 注解为src/dog.js添加类型注解// flow class Dog { name: string constructor(name: string) { this.name name } bark() { return Wah wah, I am ${this.name} } } export default Dog// flow注释告诉 Flow这个文件需要被类型检查。Flow 注解的典型形态是函数参数或函数名后的冒号加类型。同时在index.js顶部也加上// flow。此时yarn test应该能同时通过 lint 和类型检查。接着做两个验证实验确认 Flow 与 ESLint 插件都配置正确实验一验证 Flow 生效把constructor(name: string)改成constructor(name: number)运行yarn test应得到一条Flow错误提示类型不兼容。实验二验证 flowtype 插件生效把constructor(name: string)改成constructor(name:string)冒号后无空格运行yarn test应得到一条ESLint错误提示 Flow 注解冒号后应有空格。 两种错误都出现说明 Flow 与 ESLint 配置成功。记得把注解中的空格补回去。在编辑器中集成 Flow与 ESLint 一样值得花时间配置编辑器/IDE让 Flow 在发现问题时即时反馈。Jest开箱即用的测试框架Jest 是 Facebook 出品的 JavaScript 测试库安装配置极简开箱即用还能测试 React 组件。yarn add --dev jest babel-jestbabel-jest让 Jest 使用 Babel 转译代码。为了让测试文件能直接使用 Jest 的函数test、expect等而无需手动导入在.eslintrc.json顶层对象中加入env: { jest: true }创建src/dog.test.jsimport Dog from ./dog test(Dog.bark, () { const testDog new Dog(Test) expect(testDog.bark()).toBe(Wah wah, I am Test) })把jest加入test任务链scripts: { start: babel-node src, test: eslint src flow jest --coverage }--coverage标志让 Jest 自动生成测试覆盖率数据用于查看代码库中哪些部分缺乏测试数据写入coverage文件夹。记得把/coverage/加入.gitignore/coverage/ 运行yarn test在 lint 和类型检查之后Jest 会运行测试并展示覆盖率表格一切应为绿色。Git Hooks 与 Husky提交前的质量门禁Git Hooks 是 Git 在特定动作如 commit、push发生时自动运行的脚本。现在我们有了test这条质量总闸任务就用 Husky 把它挂到每次git commit和git push之前防止不合格代码进入仓库。yarn add --dev husky然后只需在scripts中新增两个任务precommit和prepushscripts: { start: babel-node src, test: eslint src flow jest --coverage, precommit: yarn test, prepush: yarn test } 现在尝试 commit 或 push会自动运行test任务。如果没生效可能是yarn add --dev husky没有正确安装 Git Hooks少数人遇到过可尝试yarn add --dev husky --force强制重装。仓库 CHANGELOG.md 也印证了这套设计Linting / type checking / testing is not launched at every file change anymore, but triggered by Git Hooks via Husky——即本系列从 V1 的每次文件变更即检查演进为 V2 的Git Hooks 触发检查。小技巧如果 commit 后紧接着 push可以用git push --no-verify跳过再次运行全部测试。全量配置清单速览将本章所有配置汇总一个典型的package.jsonscripts 段如下scripts: { start: babel-node src, test: eslint src flow jest --coverage, precommit: yarn test, prepush: yarn test }.babelrc{ presets: [ env, flow ] }.eslintrc.json{ extends: [ airbnb, plugin:flowtype/recommended ], env: { jest: true }, plugins: [ flowtype, compat ], rules: { semi: [2, never], no-unexpected-multiline: 2, compat/compat: 2 } }.flowconfig[options] suppress_comment \\(.\\|\n\\)*\\flow-disable-next-line.gitignore新增条目/coverage/本章开发依赖汇总均以yarn add --dev安装babel-cli、babel-preset-env、eslint、eslint-config-airbnb、eslint-plugin-import、eslint-plugin-jsx-a11y、eslint-plugin-react、eslint-plugin-compat、flow-bin、babel-preset-flow、babel-eslint、eslint-plugin-flowtype、jest、babel-jest、husky。下一步本章的babel-node只用于开发环境。下一章 tutorial/03-express-nodemon-pm2.md 将引入 Express 服务器并用babel src -d lib把src预编译为lib目录下的 ES5 文件供生产使用同时用 Nodemon 实现开发热重启、用 PM2 管理生产进程。回到第一章可复习 Node、Yarn 与 package.json或从 README 目录 查看全部章节。【免费下载链接】js-stack-from-scratch️⚡ Step-by-step tutorial to build a modern JavaScript stack.项目地址: https://gitcode.com/gh_mirrors/js/js-stack-from-scratch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考