寫在前面
一直以來,我都至關納悶:爲何 React 的那些 starter kit 都構建得那麼噁心?
能不能像 Vue Cli 生成的項目架構般優雅?說幹就幹,本項目就改自 Vue Demophp
詳情可參閱
package.json
html
React 15.3.0前端
Reduxvue
React Routernode
Ajax 請求庫(Superagent / jQuery-Ajax / ...)python
Webpackreact
ES6 + Babelwebpack
jQuery + BootStrap (UI)git
在開始前,但願您已通讀以下資料github
Redux 文檔(看完後懵逼的請轉看 Redux 簡明教程)
同時您還須要熟悉 ES6。例如,請把以下代碼 const foo = ({ hello: { world: bar } }) => ({ bar })
轉譯成 ES5(答案請自行到 Babel REPL 在線編譯驗證)
建議升級到 node 5.x/6.x + npm 3.x 環境
推薦使用cnpm
或手動切換到淘寶 npm 源npm set registry https://registry.npm.taobao.org/
本示例項目須要結合 簡易留言板 RESTful API
模擬先後端分離開發(還爲了與 Vue Demo 共用)
請分別 git clone
,打開兩個命令窗口( Windows 下推薦使用 Cygwin
)分別切換到二者的目錄下
分別敲下 npm install
安裝依賴(爲避免 Windows 下的 npm 軟連接問題,可加上 --no-bin-link
徹底解構全部依賴)
雖然咱們已經切換到了淘寶 npm 源,但安裝
node-sass@3.8.0
的時候仍是頗有可能卡住
由於它的安裝須要從 Github 的 AWS 服務器拉取二進制文件,所以您能夠爲它指定源:npm i node-sass@3.8.0 --registry=https://registry.npm.taobao.org
若是您想簡單粗暴一點,這裏還提供了
node_modules.zip
,直接解壓便可
前後在 msg-board-api
、react-demo
的命令窗口下,敲下 npm start
如無心外,默認瀏覽器就會自動打開 localhost:9090
,您當即能夠看到效果
若瀏覽器沒有自動彈出,則請自行手動訪問
開發過程當中,經過 Webpack 處理的靜態資源都由基於內存的
webpack-dev-server
提供
P.S. 若是您還不清楚如何安裝與啓動,請看這個 issue
. ├─ build/ # Webpack 配置目錄 ├─ dist/ # build 生成的生產環境下的項目 ├─ src/ # 源碼目錄(開發都在這裏進行) │ ├─ components/ # 組件(COMPONENT) │ ├─ redux/ # Redux 一籮筐 │ │ ├─ actions/ # (ACTION) │ │ ├─ reducers/ # (REDUCER) │ │ ├─ store/ # (STORE) │ ├── routes/ # 路由(ROUTE) │ ├── services/ # 服務(SERVICE,用於統一管理 XHR 請求,這是從 Vue Demo 中直接複製過來的) │ ├── utils/ # 工具庫(UTIL) │ │ ├─ HoC/ # 高階組件(HOC,全稱 Higher Order Component) │ │ ├─ mixins/ # 混合(MIXIN) │ ├── views/ # 路由視圖基頁(VIEW) │ │ ├─ layout/ # 全局佈局 │ ├── app.js # 啓動文件 │ ├── index.html # 靜態基頁 ├── static/ # 放置無需經由 Webpack 處理的靜態文件 ├── .babelrc # Babel 轉碼配置 ├── .eslintignore # (配置)ESLint 檢查中需忽略的文件(夾) ├── .eslintrc # ESLint 配置 ├── .gitignore # (配置)需被 Git 忽略的文件(夾) ├── package.json # (這個就不用多解釋了吧)
在這裏您可能會問:怎麼沒有 containers/
目錄?
在個人理解裏,木偶組件與智能組件最大的差異在於:
前者的狀態是經過父組件傳入得到,然後者是直接鏈接到 state
得到
亦即:若一個木偶組件直接鏈接到 state
,那麼它就是一個所謂的智能組件
(詳見 src/utils/makeContainer.js
中對 react-redux
的 connect
函數的封裝)
本示例項目惟一在組件的定義中自行使用 connect
函數的是 Navbar
組件(且用到了 ES7 的裝飾器)
您能夠根據業務需求改動目錄結構。若目錄使用頻繁,建議配置 路徑別名
默認的路徑別名見上面目錄結構註釋中大寫形式的常量
本示例項目秉承最佳實踐,高度潔癖地實現代碼分離/複用
優化目錄結構,更好的模塊分離,更接近 Vue 的開發模式
Redux DevTools,可選 Chrome 插件形式(默認) 或 內嵌頁面的組件形式
Redux Logger 打印動做及先後狀態變化
why-did-you-update 檢測沒必要要的組件重渲染(默認關閉)
引入服務層統一管理 XHR 請求(好處請參考 Vue Demo 中的 引入服務層)
引入 路徑別名 實現優雅的加載模式
引入 React Hot Reload,支持熱替換
生產環境下的編譯對代碼進行優化
迄今爲止我見過的最完美的 starter kit
有關 Redux DevTools 與 why-did-you-update 的啓用與禁用,見下面的 開發環境全局變量 配置
因爲已經擁有相對成熟的 Webpack 配置,所以在必定程度上您能夠不求甚解,但瞭解其配置會更能把握總體開發
前端開發服務器爲 localhost:9090
,可在 build/webpack.config.dev.js
中找到
後端 RESTful API 基地址寫在了
src/services/xhr/config.js
中,請根據實際自行修改
框架 / 類庫 須分離打包以加快開發時的編譯速度並有利於緩存,詳見 build/webpack.base.conf.js
中的 vendor
路徑別名 的定義位於 build/webpack.base.conf.js
,好處就是引入與重構都很方便
例如,在某組件中,引入
userService
須要import userService from '../../../services/userService'
但有了路徑別名後,只須要import userService from 'SERVICE/userService'
相比於 AngularJS 中的依賴注入,這種方式依賴於構建工具,顯得更爲簡單您可能會說,Webpack 只須要設定了
root
屬性爲src/
就能夠import userService from 'services/userService'
但在這裏實際上是會引發歧義的(不過這屬於強迫症的範疇。。。)
例如,import createBrowserHistory from 'history/lib/createBrowserHistory'
您可能會以爲這是src/history/lib/createBrowserHistory.js
但實際上 history 是一個 npm package
一樣地,您又怎麼知道services
不是一個 npm package?
並且重構以後,文件夾的變更會致使相對路徑的變化,services/
目錄未必仍在src/
下
所以,路徑別名至關有必要。其常量的形式,讓人一看就知道不是一個 npm package
開發環境全局變量,由 webpack.DefinePlugin
提供(詳見 build/webpack.base.conf.js
)
默認有
__DEV__
/__PROD__
/__COMPONENT_DEVTOOLS__
/__WHY_DID_YOU_UPDATE__
四個全局變量
若要繼續添加,則還須要在.eslintrc
中globals
同步寫入在此須要提醒,在
package.json
中設置NODE_ENV
要注意末尾空格的問題
最好就是使用前trim
一下:process.env.NODE_ENV.trim()
拓展閱讀:解讀 UglifyJS
看看生產環境下編譯if (__PROD__) { ... }
=>if (true) { ... }
後 UglifyJS 會如何處理
本示例項目的代碼極盡詳細地添加了註釋,其中不乏最佳實踐提示
爲了減小代碼量,我省去了 Prop 驗證,建議您在日後的開發中使用
請自行選擇測試工具
在 react-demo
的命令窗口下,敲下 npm run build
,將會在項目根目錄下生成 dist/
您可使用命令行靜態資源服務器 serve (
npm i serve -g
),敲下serve -p [端口] dist
來快速查看 build 後的項目
還能夠cd dist
後,python -m SimpleHTTPServer [端口]
或php -S localhost:[端口]
快速便捷地實現靜態資源服務器關於生產環境下的部署與優化,已超出本文檔的論述範圍,請自行查閱相關資料
在這裏您可能須要全局安裝 rimraf:npm i rimraf -g
(或根據指引配置環境變量避免全局安裝)