React Native三端同构(二: [email protected]脚手架构建和项目代码规范)

(一)前言
一个完整的web开发手脚架,应该包含以下

  • babel-loader 图片 音视频 字体 样式处理等loader
  • 开发环境配置
  • 生产环境配置,流程化前端多生产构建
  • 生产环境打包优化, 如构建速度,打包外链库,抽离公共模块,页面切片处理(代码内部),
  • git commit 检查规范 和 eslint配置

(二)新增eslint配置

  1. 采用eslint-config-airbnb规范

安装依赖

$  yarn add babel-eslint eslint eslint-config-airbnb eslint-loader eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-native --dev
  1. 在根文件下新增.eslintrc文件
{
  "parser": "babel-eslint",
  "parserOptions": {
    "ecmaVersion": 7,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true,
      "modules": true
    }
  },
  "extends": "airbnb",
  "env": {
    "es6": true
  },
  "plugins": [
    "react",
    "react-native",
    "jsx-a11y",
    "import"
  ],
  "globals": {
    "__DEV__": true,
    "__dirname": false,
    "__fbBatchedBridgeConfig": false,
    "alert": false,
    "cancelAnimationFrame": false,
    "cancelIdleCallback": false,
    "clearImmediate": true,
    "clearInterval": false,
    "clearTimeout": false,
    "console": false,
    "document": false,
    "escape": false,
    "Event": false,
    "EventTarget": false,
    "exports": false,
    "fetch": false,
    "FormData": false,
    "global": false,
    "jest": false,
    "Map": true,
    "module": false,
    "navigator": false,
    "process": false,
    "Promise": true,
    "requestAnimationFrame": true,
    "requestIdleCallback": true,
    "Set": true,
    "setImmediate": true,
    "setInterval": false,
    "setTimeout": false,
    "window": false,
    "XMLHttpRequest": false,
    "pit": false
  },
  "settings": {
    "import/resolver": {
      "babel-module": {}
    }
  },
  "rules": {
    "no-underscore-dangle": ["error", { "allow": ["__APP__", "__ANDROID__", "__IOS__", "_root"] }],
    "react/jsx-filename-extension": [
      1,
      {
        "extensions": [
          ".js",
          ".jsx"
        ]
      }
    ],
    "import/no-extraneous-dependencies": [
      "error",
      {
        "devDependencies": true
      }
    ],
    "import/prefer-default-export": 0,
    "react/no-unused-prop-types": 0,
    "jsx-a11y/no-static-element-interactions": 0,
    "no-bitwise": "off",
    "no-param-reassign": "off",
    "max-len": [
      0,
      160,
      4
    ],
    "arrow-parens": [
      2,
      "as-needed",
      {
        "requireForBlockBody": true
      }
    ],
    "guard-for-in": "off",
    "no-restricted-syntax": [
      "error",
      "BinaryExpression[operator='in']"
    ],
   "react/prefer-stateless-function": [0],
    "global-require": [0]
  }
}

配置eslint和修复命令请 参考这里

  1. package.json新增加script命令
$ "lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
  1. 自己根据eslint, 修复src/App.js
    运行命令检查
$ yarn lint 

React Native三端同构(二: [email protected]脚手架构建和项目代码规范)

(三) 增加webpack配置
将环境默认为dev,prod,base使用webpack-merge连接,然后运行不同的打包命令。

  1. 安装依赖
$ yarn add happypack copy-webpack-plugin html-webpack-include-assets-plugin webpack-merge open-browser-webpack-plugin webpack-bundle-analyzer webpack-parallel-uglify-plugin clean-webpack-plugin env-cmd --dev

$ yarn add @babel/polyfill
  1. 更新webpack配置文件
    React Native三端同构(二: [email protected]脚手架构建和项目代码规范)
    代码太多,最后点demo看吧

  2. 在根文件夹下新建.env-cmdrc文件,这里是环境参数配置

{
  "start:dev": {
    "NODE_ENV": "development",
    "BABEL_ENV": "development",
    "OUTPUT_DIR": "dist",
    "IS_WEB": "1"
  },
  "build:staging": {
    "NODE_ENV": "production",
    "BABEL_ENV": "production",
    "OUTPUT_DIR": "dist-staging",
    "IS_WEB": "1"
  },
  "build:prod": {
    "NODE_ENV": "production",
    "BABEL_ENV": "production",
    "OUTPUT_DIR": "dist-prod",
    "IS_WEB": "1"
  }
}
  1. package.json新增加script命令
 "setup-web": "yarn && yarn build-dll",
 "build-dll": "webpack --config web-build/webpack_dll.config.js --mode production",
 "dev": "webpack-dev-server --progress --colors --config web-build/webpack.dev.js",
 "start-web": "env-cmd start:dev yarn dev",
 "start-b": "BUNDLE=1 yarn start",
 "release": "webpack --progress --colors --config build/web-build.prod.js --profile --json > stats.json",
 "build-s": "env-cmd build:staging yarn release",
 "build-p": "env-cmd build:prod yarn release"

我简要说明下目前scripts命令

在web首先使用setup-web生成react动态连接库
start-web 为开发环境命令
start-b 为开发下分析打包大小命令
build-s 为生成staging环境包命令
build-p 为生成production环境包命令

(四) git commit检查

  1. 安装依赖
$ yarn add pre-commit --dev
  1. package.json新增加script命令
"scripts": {
    "precommit-msg": "echo 'Pre-commit checks...' && exit 0",
    "lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
    "start": "node node_modules/react-native/local-cli/cli.js start",
    "setup": "yarn && cd ios && pod install && cd .. && react-native link",
    "android": "react-native run-android",
    "iPhoneX": "react-native run-ios --simulator 'iPhone X'",
    "clear": "watchman watch-del-all && rm -rf $TMPDIR/react-* && rm -rf node_modules/ && yarn && yarn start -- --reset-cache",
    "test": "jest",
    "setup-web": "yarn && yarn build-dll",
    "build-dll": "webpack --config web-build/webpack_dll.config.js --mode production",
    "dev": "webpack-dev-server --progress --colors --config web-build/webpack.dev.js",
    "start-web": "env-cmd start:dev yarn dev",
    "start-b": "BUNDLE=1 yarn start",
    "release": "webpack --progress --colors --config build/web-build.prod.js --profile --json > stats.json",
    "build-s": "env-cmd build:staging yarn release",
    "build-p": "env-cmd build:prod yarn release"
  },
  "pre-commit": [
    "precommit-msg",
    "lint"
  ],

这样,在每次我们commit都会触发yarn lint命令,去检查代码规范, 当然,如果如果有漏掉的报错,能一次直接屏蔽,避免在pr过程还有这种小错误

(五)路由处理 和 页面分层

上一章也说到了其实web和react native的路由核心不一样,而且官网维护的react native路由库本身也不是最优的选择,所以我们还是选择react-navigation,web当前是4的react-router-dom

安装过程大体就不说了

再说下页面分层,我们在src下的分层如下
React Native三端同构(二: [email protected]脚手架构建和项目代码规范)

  • assets 为静态文件夹
  • components 为通用组件,为两端提供共用组件
  • config 配置文件
  • constants 常量文件夹
  • modals mobx store 做业务逻辑处理
  • pagesRn react-native 路由配置
  • pagesWeb web 路由配置
  • services 服务api
  • utils 工具库
  • index.rn.js react-native 入口
  • index.web.js web 入口

我说下我为什么要采用pagesRn/pagesWeb两个文件夹分别处理路由。

  1. 路由库不一样
  2. 一般组件是分为两种,一种是components内的通用组件,另一个是在pages内部维护的当前页面独有的components,所以,我们将要兼容两端的就写在components内部,如果只是当前端独有的就在对应的模块新建一个components作为私有组件维护,
  3. css in js 是react-native样式,但是社区提供一个styled-components的库,能用css in js方式,也同时支持web和react native两端的样式写法

(六)结论

目前只给了一个项目的雏形,实际开发中肯定还会遇到很多其他问题,但是也可以作为一种跨平台的参考了,当然,如果你喜欢html的方式,可以选择ionic3的方式

Demo 地址