概覽
目前社區(qū)上主流的 React 應(yīng)用初始化工具為 create-react-app,所以我們也是基于其來(lái)創(chuàng)建我們的 React 應(yīng)用。
初始化項(xiàng)目
我們推薦使用 TypeScript,所以可以參照 Adding TypeScript 中的的命令初始化項(xiàng)目:
yarn create react-app --template typescript
增加 Prettier 的支持
我們推薦使用 Prettier 對(duì)提交的源碼進(jìn)行格式化,所以我們可以按照 Install 教程來(lái)使用它。
1. 安裝 Prettier
首先需要通過(guò)以下的命令安裝 Prettier:
yarn add --dev --exact prettier
接著我們需要在項(xiàng)目根目錄下創(chuàng)建 .prettierrc 文件,并將以下內(nèi)容寫(xiě)入:
{
"tabWidth"``: 2,
"printWidth"``: 80,
"trailingComma"``: ``"none"``,
"singleQuote"``: ``true``,
"jsxBracketSameLine"``: ``false
}
因?yàn)轫?xiàng)目中可能存在著一些不需要被格式化的文件,所以我們需要在項(xiàng)目根目錄下創(chuàng)建 .prettierignore 文件來(lái)記錄這些不需要被格式化的文件:
# Ignore artifacts:
build
coverage
2. 提交前的鉤子
在之前的步驟中,我們已經(jīng)為項(xiàng)目安裝了 Prettier,接著我們需要為項(xiàng)目增加提交前的格式化的鉤子,我們依然可以參照 Pre-commit Hook 教程來(lái)添加鉤子(這邊選用 Option 2. pretty-quick 進(jìn)行介紹)。
首先,我們需要安裝 pretty-quick 與 husky。
yarn add --dev pretty-quick husky
然后我們需要往 package.json 的末尾塞入這么一段 JSON:
{
"husky"``: {
"hooks"``: {
"pre-commit"``: ``"pretty-quick --staged"
}
}
}
配置 TypeScript
每次啟動(dòng)項(xiàng)目 create-react-app 都會(huì)檢查 tsconfig.json 配置是,我們需要通過(guò) extends 配置進(jìn)行定制,否則配置將會(huì)被 create-react-app 覆蓋。
首先,我們?cè)?tsconfig.json 配置中增加 extends 配置:
{
"extends"``: ``"./tsconfig.paths.json"
}
緊接著我們?cè)陧?xiàng)目根目錄下創(chuàng)建 tsconfig.paths.json 文件,并填充如下的內(nèi)容:
{
"compilerOptions"``: {
"baseUrl"``: ``"."``,
"paths"``: {
"@/*"``: [``"src/*"``]
}
}
}
這樣,我們就可以令 TypeScript 能夠識(shí)別 @ 別名了。
自定義配置
默認(rèn)情況下,create-react-app 不能夠自定義配置,我們選用了社區(qū)的 react-app-rewired 自定義配置方案對(duì)原有的配置進(jìn)行擴(kuò)展。
首先,我們需要安裝 react-app-rewired 以及 customize-cra
yarn add --dev react-app-rewired customize-cra
安裝完畢之后,我們需要對(duì) **package.json** 的 **scripts** 進(jìn)行修改:
{
"scripts"``: {
"start"``: ``"react-app-rewired start"``,
"build"``: ``"react-app-rewired build"``,
"test"``: ``"react-app-rewired test"
}
}
接著我們需要在項(xiàng)目根目錄創(chuàng)建 config-overrides.js 配置文件,用于修改默認(rèn)的配置。
module.exports = ``function override(config, env) {
// do stuff with the webpack config...
return config;
};
將 moment 替換成 dayjs
moment 是一個(gè)優(yōu)秀的日期庫(kù),它的歷史非常悠久,我們使用它的時(shí)候往往忽略了它的大小,現(xiàn)在社區(qū)流行的做法就是在打包的時(shí)候?qū)⑵涮鎿Q成 dayjs。
首先,我們需要安裝 dayjs
yarn add dayjs
接著,我們需要安裝 antd-dayjs-webpack-plugin
yarn add --dev antd-dayjs-webpack-plugin
最后,我們需要修改 config-overrides.js 配置文件,增加對(duì) antd-dayjs-webpack-plugin 的支持。
const AntdDayjsWebpackPlugin = require(``'antd-dayjs-webpack-plugin'``);
const { addWebpackPlugin, override } = require(``'customize-cra'``);
module.exports = override(
addWebpackPlugin(``new AntdDayjsWebpackPlugin())
);
增加 @ 別名的支持
我們?cè)谥暗?TypeScript 配置中,增加了 TypeScript 中對(duì) @ 別名的解析,但是!實(shí)際上我們并不會(huì)在 webpack 中有任何的卵用。所以我們需要令 webpack 增加對(duì)該別名的支持:
const { addWebpackAlias, override } = require(``'customize-cra'``);
const path = require(``'path'``);
module.exports = override(
addWebpackAlias({
[``'@'``]: path.resolve(__dirname, ``'./src'``)
})
);
為 CSS Modules 增加 camelCase 變量名
默認(rèn)情況下,CSS Modules 生成的字典中是根據(jù)樣式的原始名稱(chēng),舉個(gè)例子,寫(xiě)的樣式如果是 .foo-bar,生成的字典將會(huì)是 { 'foo-bar': 'xxx' },這對(duì)我們的開(kāi)發(fā)是比較不方便的。
所以,我們需要將要支持生成的字典的鍵全都為小駝峰的格式。
首先,需要安裝 [customize-cra-util](https://github.com/PeckZeg/customize-cra-util)
yarn add --dev customize-cra-util
然后,我們?cè)?strong>config-overrides.js中增加配置
const { addCssModulesCamelCase } = require(``'customize-cra-util'``);
const { override } = require(``'customize-cra'``);
module.exports = override(
addCssModulesCamelCase()
);
為應(yīng)用注入標(biāo)題
create-react-app 默認(rèn)的應(yīng)用標(biāo)題是 React App,這個(gè)可能和我們?cè)?.env 配置文件中定義的 REACT_APP_TITLE 常量有出入,所以我們期望模板中能夠配置標(biāo)題。
為了達(dá)到我們的目標(biāo),我寫(xiě)了一個(gè)工具 customize-cra-util 用來(lái)解決當(dāng)前的問(wèn)題。
首先,需要安裝 customize-cra-util
yarn add --dev customize-cra-util
接著,我們?cè)陧?xiàng)目根目錄下新建 .env 文件,并在文件中增加下面的內(nèi)容
# 應(yīng)用名稱(chēng)
REACT_APP_TITLE=React App
然后,我們?cè)?code>**config-overrides.js**中增加配置
const { addDocumentTitle } = require(``'customize-cra-util'``);
const env = require(``'react-scripts/config/env'``)().raw;
const { override } = require(``'customize-cra'``);
module.exports = override(
addDocumentTitle(env.REACT_APP_TITLE)
);
最后,我們需要修改 public/index.html,將標(biāo)題注入到模板中
<!DOCTYPE html>
<``html lang``=``"en"``>
<``head``>
<``title``><%= htmlWebpackPlugin.options.title %></``title``>
</``head``>
</``html``>
區(qū)分環(huán)境
在大部分情況下,我們構(gòu)建的 React 應(yīng)用是區(qū)分環(huán)境的,所以我們約定了 REACT_APP_ENV 常量來(lái)指代當(dāng)前應(yīng)用的環(huán)境。
下面是 REACT_APP_ENV 值和其所代表環(huán)境的參考
REACT_APP_ENV |
應(yīng)用環(huán)境 |
|---|---|
development, 空值 |
開(kāi)發(fā)環(huán)境 |
pre |
預(yù)發(fā)環(huán)境 |
beta |
測(cè)試環(huán)境 |
release |
線(xiàn)上環(huán)境 |
所以,我們可以對(duì)上面的配置進(jìn)行修改,令其在標(biāo)題之后加上環(huán)境信息
const { addDocumentTitle } = require(``'customize-cra-util'``);
const env = require(``'react-scripts/config/env'``)().raw;
const { override } = require(``'customize-cra'``);
module.exports = override(
addDocumentTitle(
(() => {
const envNames = {
pre: ``'預(yù)發(fā)環(huán)境'``,
beta: ``'測(cè)試環(huán)境'``,
development: ``'開(kāi)發(fā)環(huán)境'
};
const { REACT_APP_TITLE: title, REACT_APP_ENV: appEnv } = env;
const appEnvName = envNames[appEnv || ``'development'``];
return appEnvName ?title (${appEnvName}): title;
})()
)
);
增加對(duì) Lodash 的支持
lodash 是一個(gè)優(yōu)秀的工具庫(kù),我們一般都會(huì)在項(xiàng)目中使用它。但是 lodash 是一個(gè) CommonJS 的庫(kù),其對(duì) webpack 構(gòu)建工具來(lái)說(shuō),不能夠非常友好的進(jìn)行 Tree Shaking.所以,我們需要引入 babel-plugin-lodash 插件來(lái)優(yōu)化這個(gè)打包過(guò)程。
首先,我們先安裝 lodash:
yarn add lodash @types``/lodash
接著,我們還需要安裝 babel-plugin-lodash
yarn add --dev babel-plugin-lodash
最后,我們需要在 config-overrides.js 中增加配置
const { addBabelPlugin, override } = require(``'customize-cra'``);
module.exports = override(
addBabelPlugin(``'lodash'``)
);
增加對(duì) antd 的支持
antd 是一個(gè)優(yōu)秀的中后臺(tái)基礎(chǔ)組件庫(kù),要在項(xiàng)目中支持它也是非常簡(jiǎn)單的。
首先,我們需要安裝它
yarn add antd
因?yàn)?antd 使用 less 作為樣式的預(yù)加載器,所以我們應(yīng)當(dāng)添加 less 的支持
less-loader 需要指定為 ^7.3.0 的版本(因?yàn)?customize-cra 的 addLessLoader 還未對(duì)最新版本的 less-loader 進(jìn)行支持)
yarn add --dev ``less less``-loader@^7.3.0
然后,我們?cè)?strong>config-overrides.js中增加配置
const { addLessLoader, override } = require(``'customize-cra'``);
module.exports = override(
addLessLoader({
lessOptions: {
javascriptEnabled: ``true``,
localIdentName: ``'[local]_[hash:base64:8]'``,
noIeCompat: ``true``,
modifyVars: {
'@primary-color'``: ``'#7955ff'
}
}
})
);
最后,我們需要利用 babel-plugin-import 來(lái)按需加載組件和樣式
yarn add --dev babel-plugin-``import
在 config-overrides.js中增加配置
const { fixBabelImports, override } = require(``'customize-cra'``);
module.exports = override(
fixBabelImports(``'import'``, {
libraryName: ``'antd'``,
libraryDirectory: ``'es'``,
style: ``true
})
);
應(yīng)用體積分析
我們?cè)跇?gòu)建應(yīng)用的時(shí)候,有時(shí)候會(huì)關(guān)注整個(gè)應(yīng)用的體積,所以在項(xiàng)目中增加包分析工具是非常有必要的。
我們通過(guò) create-react-app 中的 Analyzing the Bundle Size 教程,可以很好的對(duì)應(yīng)用體積進(jìn)行分析。
首先,我們需要安裝 source-map-explorer
yarn add --dev ``source``-map-explorer
{
"scripts"``: {
"analyze"``: ``"source-map-explorer 'build/static/js/*.js'"
}
}
接著,我們可以通過(guò)先后執(zhí)行以下的命令來(lái)對(duì)應(yīng)用的體積進(jìn)行分析了
yarn build
yarn analyze