1、初始化构建项目
安装CLI 工具
npm install -g @tarojs/cli@3.5.7
初始化项目
taro init my-app-preact
安装Taro-ui
yarn add taro-ui@3.1.0-beta.4
2、加入格式校验工具
2.1 eslint + prettier
yarn add eslint -D
yarn add eslint-config-taro eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-prettier -D
typescript 相关的插件
yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parser -D
创建eslintrc.js和eslintignore
// eslintrc.js
module.exports = {
extends: ["taro/react"],
plugins: ["prettier", "react", "react-hooks"],
globals: { // 微信小程序原生写法时,不错误提示
wx: true,
getApp: true,
Component: true,
},
rules: {
"prettier/prettier": "warn",
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"no-unused-vars": ["error", { varsIgnorePattern: "Taro" }],
"react/sort-comp": "off",
"jsx-quotes": ["error", "prefer-double"],
"react/jsx-filename-extension": [
1,
{ extensions: [".js", ".jsx", ".tsx"] },
],
"arrow-parens": ["error", "as-needed"],
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", // 生产环境中不允许使用debugger
"no-console": "off",
"react/jsx-no-target-blank": "off",
"jsx-a11y/anchor-has-content": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"jsx-a11y/anchor-is-valid": "off",
"import/no-commonjs": "off",
"react/no-string-refs": "off",
'no-undef': 'off', // 这个不关会报错'definePageConfig' is not defined
'react-hooks/exhaustive-deps': 'off',
'import/no-named-as-default':'off',
'import/no-named-as-default-member':'off',
'import/prefer-default-export': 'off',
"react/jsx-indent-props": "off",
"no-unused-vars": "off", // 未使用的变量
'no-shadow':'warn', // 检查局部变量与全局变量重名
'import/export':'off',
},
parser: "babel-eslint",
};
2.2 stylelint
yarn add stylelint -D
其他插件:
- stylelint-config-standard 插件会处理 import语句,导致build 打包失败,不建议
- stylelint-config-recess-order 检测标签顺序
//stylelintrc
{
"ignoreFiles": ["src/**/*.jsx"],
"rules":
{
"indentation": 4,
"number-leading-zero": "never",
"string-quotes": "double",
"declaration-block-trailing-semicolon": "always",
"length-zero-no-unit": true,
"at-rule-no-unknown": null,
"declaration-empty-line-before": [ "never", { "ignore": ["after-declaration"] } ],
"rule-empty-line-before": [ "always", { "except": ["after-single-line-comment", "first-nested"] } ],
"block-closing-brace-empty-line-before": ["never"],
"at-rule-empty-line-before": [ "always", { "ignore": ["inside-block", "blockless-after-same-name-blockless"] } ],
"max-empty-lines": 1,
"no-eol-whitespace": true,
"no-missing-end-of-source-newline": true,
"unit-case": null,
"color-hex-case": "upper",
"value-keyword-case": "lower",
"function-name-case": "lower",
"property-case": "lower",
"at-rule-name-case": "lower",
"selector-pseudo-class-case": "lower",
"selector-pseudo-element-case": "lower",
"selector-type-case": "lower",
"media-feature-name-case": "lower",
"block-opening-brace-space-before": "always",
"comment-whitespace-inside": "always",
"declaration-colon-space-after": "always",
"declaration-colon-space-before": "never",
"declaration-block-semicolon-space-before": "never",
"function-comma-space-after": "always",
"selector-combinator-space-before": "always",
"selector-combinator-space-after": "always",
"selector-list-comma-space-before": "never",
"selector-descendant-combinator-no-non-space": true,
"value-list-comma-space-after": "always",
"value-list-comma-space-before": "never",
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"no-descending-specificity": null
}
}
2.3 commit 检查
使用husky在代码提交之前,进行代码规则检查。
- 添加插件:
yarn add husky -D
- 在package.json中添加prepare脚本,并执行一次:
{
"scripts": {
"prepare": "husky install"
}
}
或者,直接使用命令行
npm pkg set scripts.prepare="husky install"
npm run prepare
- 创建hook:
npx husky add .husky/pre-commit "npm test"
然后,你的项目根目录会有名为pre-commit的shell脚本,并且有一条npm test的命令
npm test 命令根据你自己项目中script脚本而定,例如,我的项目script脚本如下:
"scripts": {
"build:weapp": "taro build --type weapp",
"dev:weapp": "npm run build:weapp -- --watch",
"format": "prettier --write \"./src/**/*.{js,jsx,json}\"",
"eslint": "eslint --fix --ext .js,.jsx src",
"stylelint": "stylelint \"./src/**/*.{css,less,scss}\" --fix",
"prepare": "husky install"
}
那我的npm test可以改为 npm run format && npm run eslint && npm run stylelint
最后,把.husky/pre-commit提交到代码库即可。之后每次执行 git commit 或者 git commit --amend时,都会先触发pre-commit hook,执行代码检查命令啦~
2.4 commitlint规范
yarn add @commitlint/config-conventional @commitlint/cli -D
添加 commitlint.config.js
const types = [
'build', // 主要目的是修改项目构建系统(例如glup,webpack,rollup的配置等)的提交
'docs', // 文档提交(documents)
'feature', // 新增功能
'fix', // 修复 bug
'refactor', // 代码重构
'style', // 不影响程序逻辑的代码修改、主要是样式方面的优化、修改
'test', // 测试相关的开发,
], typeEnum = {
rules: { 'type-enum': [2, 'always', types], },
value: () => { return types; },
};
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': typeEnum.rules['type-enum'],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
}
};
3、React 替换为Preact
如果你一开始习惯性的选择了react框架,那很快你会发现,react占用的空间太大了,项目超出2M的限制。这时你可以选择把 React 替换为Preact。
Preact 是一款体积超小的类 React 框架,提供和 React 几乎一致的 API,而体积只有 5k 左右。
1、将 CLI、项目中 Taro 相关的依赖更新到 v3.4.0-beta 版本以上
2、安装依赖
yarn add preact @tarojs/plugin-framework-react
3、修改 Taro 编译配置:
// config/index.js
const config = {
framework: 'preact'
}
4、修改 Babel 配置:
// babel.config.js
module.exports = {
presets: [
['taro', {
framework: 'preact'
}]
]
}
5、开发时我们可以使用任意的 React 生态库,甚至对 React、ReactDOM 的 API 引用也不需要修改,只需要简单地配置 alias
// config/index.js
const config = {
"resolve": {
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
"react/jsx-runtime": "preact/jsx-runtime"
}
}
}
6、如果项目使用了 TypeScript,请打开 skipLibCheck 配置,以避免和其它 React 生态库配合使用时报类型错误:
//tsconfig.json
{
...
"skipLibCheck": true,
}
4、全局变量
在 Taro 中推荐使用 Redux 来进行全局变量的管理,但是对于一些小型的应用, Redux 就可能显得比较重了,这里使用了官方推荐的globalData的方式,存储用户信息、字典信息等。
const globalData = {}
export function setGlobalData (key, val) {
globalData[key] = val
}
export function getGlobalData (key) {
return globalData[key]
}
在实际应用时发现,很多时候异步请求的接口还没有完成,页面已经渲染,接口请求完毕,页面数据却无法更新,这需要我们监听异步请求,进行页面重新载入,我选择了 Taro.eventCenter 解决。
// app.js
// 执行完异步请求以后,触发一个事件,可传入多个参数
Taro.eventCenter.trigger('CHANGE_USER_INFO', _newData)
//index.jsx
const Index = () => {
let [userInfo, setUserInfo] = useState({})
useDidShow(() => {
Taro.eventCenter.on('CHANGE_USER_INFO', (_newData) => {
setUserInfo(_newData)
})
})
useDidHide(() => {
// 取消监听
Taro.eventCenter.off('CHANGE_USER_INFO')
})
}
5、打包优化
目前小程序分包大小有以下限制:
- 整个小程序所有分包大小不超过 20M
- 单个分包/主包大小不能超过 2M
首先进行项目的代码分析,可以用微信开发者工具自带的分析工具,或者借助 webpack-bundle-analyzer 插件,可以直观分析打包出的文件包含哪些,大小占比如何,模块包含关系,依赖项,文件是否重复,压缩后大小如何,我们可以做针对性优化。
我的优化思路如下:
-
静态资源上cdn
-
去除重复代码,提取公用代码和组件
-
慎用插件
-
dayjs 替代 momentjs
-
react 更换为preact
-
配置分包
-
启动图方案 🙋♀️
- 准备一个空主页面,一旦渲染,便立即跳转到其他分包页面。
- 这样主包的体积就基本固定了,业务持续迭代也不会增加主包的体积。但是需要评估交互体验是否可以被接受。
- 👉 但是要注意,由于空主页面没有引用任何内容,很可能会导致taro-ui被分别打包到每一个分包中,从而使整个包的体积增大一倍!这时,我们只需要在空主页随便引用一个taro-ui的组件,而不必真的使用,就可以让taro-ui仍然被打包到主包中啦~
-
dev环境执行build命令
6、遇到的一些问题
6.1 部分机型上setState报错
下面这段代码,在开发者工具里、大部分手机都是好的,特定的手机上查看才会报错。某报错机型:iPhone 13 Pro Max,微信版本v 8.0.30。1、2、3、4 步是排查过程。
import Taro from '@tarojs/taro'
import { useState } from 'react'
import { View } from '@tarojs/components'
function Demo(props) {
const [flag, setFlag] = useState(false)
const onSign = () => {
// setFlag(true) 4、在这里执行不会报错
Taro.scanCode({
success: result => {
console.log('扫码成功!')
setFlag(true) // 3、在这里执行也会报错
onSuccess()
},
fail: () => {}
})
}
const onSuccess = () => {
setFlag(true) // 2、拿到异步函数外面执行也会报错
// 1、这里执行一个异步函数,在then方法里执行setFlag(true)会报错
}
return (
<View>
<View onClick={onSign}>点我签到</View>
<View>{flag ? '签到成功' : '未签到'}</View>
</View>
)
}
export default Demo
报错如下:
在我的实际业务中,这里的签到状态其实可以在后端接口中拿到,于是我尝试了执行刷新页面,但是仍然会报错!我又尝试了把签到状态放到GlobalData中,签到成功后执行changeGlobalData,然后通过eventCenter监听拿到修改后的状态,执行成功~
🤔️ 但是这个报错原因仍然未知,有思路的小伙伴可以留言 ~
6.2 执行npm run dev 时无报错且可以正常访问页面,执行npm run build时也无报错但是访问页面一片空白
毛估估是页面代码有误导致根本没有渲染,由于无任何报错可参考,只能一行行看代码,最后发现有个函数的const被误删了,加上以后再执行执行 npm run build 就可以正常访问页面了
import { View } from '@tarojs/components'
function Demo(props) {
const onCheck=()=>{}
const onSubmit=()=>{
// 这个函数误删了 const
}
return <View>12345</View>
}
这种问题该如何避免呢???