[TOC]
# ===babel 編譯===
## 借助 CRA:
```
yarn create react-app react-project --template typescript
```
## 手動安裝
```
npm init
npm i react react-dom react-router-dom core-js regenerator-runtime
npm i -D webpack webpack-cli webpack-merge html-webpack-plugin webpack-dev-server clean-webpack-plugin @babel/core @babel/preset-react @babel/preset-env babel-loader
```
## 依賴包
| 包名 | 釋義 |
| --- | --- |
| @babel/core | babel 核心依賴包,將 js 代碼分析成 ast,方便各個插件分析語法進行相應的處理 |
| @babel/preset-env | 解析 ES 的包,取代了`preset-es20**`系列的babel 預設,會根據配置`.babelrc`的 `env` 只編譯那些當前運行環境還不支持的特性。|
| @babel/preset-react | 專門為了 react 的包,解析 jsx 的包 |
| @babel/plugin-proposal-class-properties | 支持類屬性的轉化 |
| @babel/plugin-proposal-object-rest-spread | 支持對象使用解構,Babel 默認只轉換語法,而不轉換新的 API,如需使用新的 API,還需要使用對應的轉換插件或者 polyfill。更多查看官網 |
| @babel/plugin-syntax-dynamic-import | 支持動態導入文件 |
| @babel/plugin-proposal-decorators | 裝飾器插件 |
| @babel/plugin-transform-runtime | 使用 `async/await` 或其他一些功能時,會需要 |
| @babel/runtime | `@babel-plugin-transform-runtime`插件所需要的,需要將其作為**依賴項**安裝。 |
| core-js、regenerator-runtime | 作為 polyfill,供`@babel/preset-env`使用(適當的配置,可以把這2個庫的代碼,按需打入bundle) |
| webpack | webpack 核心包 |
| webpack-cli | webpack cli 工具包 |
| babel-loader | 和 webpack 結合,用于編譯打包 js 文件 |
| html-webpack-plugin | webpack 插件,用于將打包后的文件添加到指定的 html |
| webpack-dev-server | webpack 開發環境工具 |
## 配置文件
### `.babelrc`:
```
{
presets: [
[
'@babel/preset-env',
{
"corejs": "3", // 指定core-js的版本,2或者3,這里我們用最新版3
"useBuiltIns": "usage", // usage是最佳實踐,會按需把core-js和regenerator引入(所謂按需就是按下面的target和編譯的js用到的es6語法來判斷
"targets": '> 2% in CN and not ie <= 8 and not dead',
// 選擇目標環境為:中國區統計數據為2%以上的瀏覽器,不包括版本號小于8的IE瀏覽,不包括官方已經不維護的瀏覽器
},
],
'@babel/preset-react',
'@babel/preset-typescript',
],
"exclude": [/node_modules/], // 不要編譯node_modules,不然會出一些奇奇怪怪的問題
"plugins": ["@babel/plugin-transform-runtime", "@babel/plugin-proposal-object-rest-spread", "@babel/plugin-proposal-class-properties"],
"comments": false
}
```
### `webpack.config.js`:
```
const webpack = require('webpack');
...
module.exports = {
...
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'@': path.resolve(__dirname, '../src'),
},
},
module: {
rules: [
...
{
test: /\.js(x?)$/,
exclude: /[\\/]node_modules[\\/]/,
loader: 'babel-loader?cacheDirectory=true',
},
],
},
plugins: [
...
new webpack.ProvidePlugin({
React: 'react',
// 不用在每個組件文件中都使用一次`import React from 'react'`
}),
],
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
},
},
},
}
```
## 參考
> [純手動搭建React項目](https://juejin.im/post/5e7b16b0f265da57187c77a3)
# ===Typescript 編譯===
Typescript本身具有編譯器,可以根據`tsconfig.json`來進行編譯。當我們使用 Webpack 進行打包編譯的時候,我們需要相應的 loader,Webpack 官網推薦了 ts-loader。而社區也有 awesome-typescript-loader,它針對 ts-loader 做了一些優化,將類型檢查和代碼生成分離到單獨進程中,另外,它還可以直接集成 babel。最后祭出大殺器,Babel 本身是非常強大的語法轉換工具,在 babel7 之后開始支持 typescript。
綜上,目前轉換 Typescript 有三種常用的方式:
* 經典的 ts-loader
* awesome-typescript-loader
* babel7 之后已經支持的 `@babel/preset-typescript
` (目前推薦的)
————————————————
## 借助 CRA:
```
$ npx create-react-app my-app --typescript $
# 或者
$ yarn create react-app my-app --typescript
npm start / yarn start
```
# 手動安裝
```shell
mkdir ts-react && cd ts-react
npm init -y && tsc --init
npm i react react-dom react-router-dom @types/react @types/react-dom @types/react-router-dom
npm i -D typescript babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin
npm i -D css-loader sass-loader node-sass mini-css-extract-plugin
npm i -D url-loader file-loader
npm i -D eslint eslint-loader eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/parser @typescript-eslint/eslint-plugin
```
## 依賴包
| 包名 | 釋義 |
| --- | --- |
| @babel/preset-react | 專門為了 react 的包,解析 jsx 的包 |
| @babel/preset-typescript | babel 的 preset,用于處理 TypeScript,沒有類型檢查的能力 |
| @babel/preset-env | 解析過 JSX 和 TypeScript 之后得到的 JavaScript 可能依然無法在某些瀏覽器上正常運行,所以需要使用[@babel/preset-env](https://babeljs.io/docs/en/next/babel-preset-env.html) |
| @babel/plugin-transform-typescript | 增加了對 TypeScript 編程語言使用的語法的支持。但是,這個插件沒有添加類型檢查的能力 |
| @typescript-eslint | 配置 ESLint 來達到 TypeScript 類型檢查 |
| tsx-control-statements | babel 的 preset,用于處理 TypeScript |
| awsome-typescript-loader | babel 的 preset,用于處理 TypeScript |
| fork-ts-checker-webpack-plugin | 啟用 TypeScript 類型檢測 |
| eslint-plugin-react | 檢測和規范 React 代碼的書寫 |
| @typescript-eslint/parser | ESLint 的解析器,用于解析 typescript,從而檢查和規范 Typescript 代碼 |
| @typescript-eslint/eslint-plugin | ESLint 插件,包含了各類定義好的檢測 Typescript 代碼的規范 |
## `.babelrc`
```
// presets 是自下而上執行的,和 webpack 的 loader 一樣
{
presets: [
[
'@babel/preset-env',
{
"targets": '> 2% in CN and not ie <= 8 and not dead',
// 選擇目標環境為:中國區統計數據為2%以上的瀏覽器,不包括版本號小于8的IE瀏覽,不包括官方已經不維護的瀏覽器
},
],
'@babel/preset-react',
'@babel/preset-typescript',
]
}
```
## `.eslintrc.js`
~~~js
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended'
], //使用推薦的React代碼檢測規范
plugins: ['@typescript-eslint'],
env:{
browser: true,
node: true,
},
settings: { //自動發現React的版本,從而進行規范react代碼
"react": {
"pragma": "React",
"version": "detect"
}
},
parserOptions: { //指定ESLint可以解析JSX語法
"ecmaVersion": 2019,
"sourceType": 'module',
"ecmaFeatures":{
jsx:true
}
},
rules: {
//自定義React代碼編碼規范
}
}
~~~
## `tsconfig.json`
~~~json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"jsx": "react",
"lib": ["es6", "dom"],
"module": "esnext",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowSyntheticDefaultImports": true, // 允許使用 ES2015 默認的 import 風格
"esModuleInterop": true, // 可調用的CommonJS模塊必須被做為默認導入,在已有的“老式”模塊模式之間保證最佳的互通性
"moduleResolution": "node",
"noImplicitAny": true,
"rootDir": "src",
"sourceMap": true,
"strict": true,
"target": "es5"
},
"exclude": [
"node_modules",
"build"
]
}
~~~
## 目錄結構
~~~
├── build # 構建結果目錄
├── styles # 樣式
└── main.css
├── bundle.ssr.js # SSR應用文件
├── bundle.web.js # Web應用文件
├── index.html # Web應用入口HTML
├── public
└── index.html # 模板頁面
├── src # 應用源碼
├── components # 組件
└── Header
└── Header.js
├── home # 首頁
└── index.scss # 首頁 scss
└── index.tsx # 首頁
├── signin # 登錄頁
└── index.scss # 登錄頁 scss
└── index.tsx # 登錄頁
├── App.tsx # 應用路由設置
├── main.ssr.tsx # SSR入口文件
├── index.web.tsx # Web 入口文件
├── index.js # express服務器入口
├── package.json
├── tsconfig.json # TypeScript配置文件
├── webpack.config.js # Web應用webpack配置
├── webconfig.ssr.config.js # SSR應用Webpack配置
~~~
## 參考
> [Microsoft/TypeScript-Babel-Starter](https://github.com/microsoft/TypeScript-Babel-Starter)
> [使用Webpack等搭建一個適用于React項目的腳手架(1 - React、TypeScript)](https://juejin.im/post/5e8b3e626fb9a03c546c2e60#heading-6)
> [webpack從0開始手動搭建react + typeScript項目(二)](https://www.jianshu.com/p/34af24231d2a)
# create-react-app
eject 和 不 eject(使用react-app-rewired) 這2種情況下的 antd 組件按需引入配置:
* 不 eject(使用 [react-app-rewired](https://github.com/timarney/react-app-rewired))配置:
1. **react-app-rewired2.x 以后,不再支持 injectBabelPlugin 的方式,需要安裝 [customize-cra](https://github.com/arackaf/customize-cra)。**
替代項目和分支:
[Rescripts](https://github.com/rescripts/rescripts),用于擴展 CRA 配置的替代框架(支持 2.0+)
[react-scripts-rewired](https://github.com/marcopeg/create-react-app/blob/master/packages/react-scripts/README.md) 為該項目的一個分支,旨在支持 CRA 2.0
[craco](https://github.com/sharegate/craco)
2. 項目的根目錄下,新建名為 `config-overrides.js` 文件,然后進行 webpack 的相關配置。
3. 修改 package.json 文件
```
/* package.json */
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
}
```
ant.design 說明:https://ant.design/docs/react/use-with-create-react-app-cn
[使用 react-app-rewired2.x 添加 webpack 配置](https://www.cnblogs.com/zyl-Tara/p/10635033.html)
* eject 后,配置:
按需引入 antd 的2種方式:
出處:https://blog.csdn.net/well2049/article/details/78801228
推薦使用第2種方式:在`package.json`里面直接添加代碼,這種方式簡單。
---------------------
# 參考
[ How to set up React with Webpack and Babel](https://www.robinwieruch.de/minimal-react-webpack-babel-setup)
[webpack手動搭建React項目](https://juejin.im/post/5cfb8c0051882541b24c3ed3)