React Native三端同构(二: [email protected]脚手架构建和项目代码规范)
(一)前言
一个完整的web开发手脚架,应该包含以下
- babel-loader 图片 音视频 字体 样式处理等loader
- 开发环境配置
- 生产环境配置,流程化前端多生产构建
- 生产环境打包优化, 如构建速度,打包外链库,抽离公共模块,页面切片处理(代码内部),
- git commit 检查规范 和 eslint配置
(二)新增eslint配置
安装依赖
$ 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
- 在根文件下新增.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和修复命令请 参考这里
- package.json新增加script命令
$ "lint": "eslint \"src/**/*.{js,jsx}\" --quiet",
- 自己根据eslint, 修复src/App.js
运行命令检查
$ yarn lint
(三) 增加webpack配置
将环境默认为dev,prod,base使用webpack-merge连接,然后运行不同的打包命令。
- 安装依赖
$ 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
-
更新webpack配置文件
代码太多,最后点demo看吧 -
在根文件夹下新建.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"
}
}
- 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检查
- 安装依赖
$ yarn add pre-commit --dev
- 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下的分层如下
- 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两个文件夹分别处理路由。
- 路由库不一样
- 一般组件是分为两种,一种是components内的通用组件,另一个是在pages内部维护的当前页面独有的components,所以,我们将要兼容两端的就写在components内部,如果只是当前端独有的就在对应的模块新建一个components作为私有组件维护,
- css in js 是react-native样式,但是社区提供一个styled-components的库,能用css in js方式,也同时支持web和react native两端的样式写法
(六)结论
目前只给了一个项目的雏形,实际开发中肯定还会遇到很多其他问题,但是也可以作为一种跨平台的参考了,当然,如果你喜欢html的方式,可以选择ionic3的方式