摘要:隔壁老王今日行程不同的內(nèi)容使用這種方法就可以將我們得所有路由寫在一起了,可能有人覺得每次都要寫引入很麻煩,有沒有其他更好用的辦法,在講的時(shí)候會(huì)說到這里就先跳過。
前言
距離上篇文章已經(jīng)好長一段時(shí)間了,這兩個(gè)星期公司派駐到京東方這邊出差負(fù)責(zé)入駐項(xiàng)目團(tuán)隊(duì)的前端工作。這段時(shí)間從零搭建一下前端項(xiàng)目,這次給的時(shí)間比較充裕,思考的也比較多。以前也常有搭過前端項(xiàng)目,但是給的時(shí)間都比較緊,因此很多問題都忽略掉了。這次正好對(duì)以前的進(jìn)行一次優(yōu)化,并總結(jié)了一些經(jīng)驗(yàn)分想給大家。如果大家有更好的想法,歡迎留言交流。
溫馨提示:
這個(gè)項(xiàng)目是以PC端前端項(xiàng)目為視角,移動(dòng)端前端項(xiàng)目并不完全適用。這點(diǎn)各位小伙們還需要注意一下。
該項(xiàng)目已分不同方向去維護(hù),每個(gè)分支與之對(duì)應(yīng)的方向可在CONTRIBUTING.md里查看
項(xiàng)目說明項(xiàng)目地址: https://github.com/ruichengpi...
該項(xiàng)目可以用我自己寫的腳手架工具asuna-cli完成項(xiàng)目構(gòu)建,我自己寫的腳手架工具地址如下:
https://github.com/ruichengpi...
以上是示例項(xiàng)目的目錄結(jié)構(gòu),下面我們將逐一進(jìn)行分析**build
這個(gè)文件主要放了一些與webpack打包的相關(guān)文件。
build.js ---- webpack打包腳本,用于構(gòu)建生產(chǎn)環(huán)境的包
check-versions.js ---- 主要檢測當(dāng)前打包環(huán)境的node以及npm的版本是否符合要求
utils.js ---- webpack打包所需要的一些工具庫
webpack.base.conf.js ---- webpack的一些基礎(chǔ)配置,不同環(huán)境的webpack配置都是基于此
webpack.dev.conf.js ---- 開發(fā)環(huán)境的webpack配置
webpack.prod.conf.js ---- 生產(chǎn)環(huán)境的webpack配置
這個(gè)項(xiàng)目的webpack配置我是在vue-cli的項(xiàng)目上進(jìn)行修改的,可以用于React的項(xiàng)目構(gòu)建。目前只要開發(fā)環(huán)境和生產(chǎn)環(huán)境這兩個(gè)環(huán)境,可能一些公司有多個(gè)環(huán)境,每個(gè)環(huán)境下webpack的配置還不同,此時(shí)可以根據(jù)不同環(huán)境建一個(gè)文件名格式為“webpack.<環(huán)境名>.conf.js”的webpack配置使用。webpack.base.conf.js里面有一些基本配置比如rules、input、output的等配置,一般來說每個(gè)環(huán)境下這些大致都是相同,一些不同之處可以用webpack-merge插件進(jìn)行合并。一般來說大多數(shù)項(xiàng)目來說開發(fā)環(huán)境和生產(chǎn)環(huán)境兩個(gè)webpack配置足夠了。
config這里存放著不同環(huán)境webpack所需要的配置參數(shù)。
dev.env.js ---- 向外暴露開發(fā)環(huán)境下的環(huán)境變量NODE_ENV
index.js ---- 存放不同環(huán)境的配置參數(shù)
prod.env.js ---- 向外暴露生產(chǎn)環(huán)境下的環(huán)境變量NODE_ENV
如果你需要再加一個(gè)環(huán)境的話,可以建一個(gè)文件名為“<環(huán)境名>.env.js”并向外暴露環(huán)境變量NODE_ENV,然后在index.js中導(dǎo)入,進(jìn)行相關(guān)參數(shù)設(shè)置。
mock這里是用來做接口的mock的,可能很多公司都不太用,我在工作也很少去mock。這里介紹一下自己的接口mock思路,這里我選擇mockjs加上json-server的組合。二者具體的使用,大家可以查看其官方文檔。
api ---- 存放不同api所對(duì)應(yīng)的數(shù)據(jù)
index.js ---- json-server的主文件
routes.json ---- 路由的映射
package.json我配置一個(gè)script,如下:
"mock": "json-server mock/index.js --port 3000 --routes mock/routes.json"
控制臺(tái)執(zhí)行“npm run mock“即可。
src apiurl.js
export default { fetchUserInfo:{ method:"get", url:"/api/user" }, fetchAuthorInfo:{ method:"get", url:"/api/author" }, fetchUserList:{ method:"get", url:"/api/userList" } }
index.js
import _ from "lodash" import http from "@/utils/http" import API_URL from "./url"; function mapUrlObjToFuncObj(urlObj){ const API = {}; _.keys(urlObj).forEach((key)=>{ const item = urlObj[key] API[key]=function(params){ return http[item.method](item.url,params) } }); return API; } function mapUrlObjToStrObj(urlObj){ const Url = {}; _.keys(urlObj).forEach((key)=>{ const item = urlObj[key] Url[key]=item.url }); return Url; } export const API = mapUrlObjToFuncObj(API_URL); export const URL = mapUrlObjToStrObj(API_URL);
這里我們用來放置api的接口地址,為了后續(xù)的接口維護(hù),我們在使用的過程中不會(huì)直接寫死接口地址,而是將接口請求封裝成一個(gè)個(gè)方法。通過對(duì)接口的統(tǒng)一維護(hù),我們就可以做到在執(zhí)行修改接口地址、修改請求方法、新增接口等等操作時(shí),就不用在整個(gè)項(xiàng)目里到處找了,只要維護(hù)好url.js向外暴露的對(duì)象即可。使用方法如下:
import {API} from "@/api" //params為請求參數(shù) API.fetchUserInfo(params).then(response=>{ //response為返回值 ... })assets
這里我們會(huì)放項(xiàng)目的所需要圖片資源,這些圖片資源一般來說都是做圖標(biāo)的,都比較小。webpack會(huì)將其轉(zhuǎn)化成BASE64去使用。如果你不想以這種方式使用,可以在static目錄下存放圖片資源。
components這里存放整個(gè)項(xiàng)目所用到的公共組件。定一個(gè)組件,這里要求是新建一個(gè)文件夾,文件夾名為組件名,另外在這個(gè)文件夾下新建index.jsx和style.scss文件。例如做一個(gè)HelloWorld組件,則應(yīng)該是如下結(jié)構(gòu)。
HelloWorld
index.jsx
style.scss //存放組件的樣式
index.js
import React from "react"; import "./style.scss"; class HelloWorld extends React.PureComponent{ render(){ return (Hello World
) } } export default HelloWorld;
style.scss
.u-text{ color: red; }layouts
這里存放著布局文件。關(guān)于這個(gè)布局文件我是這么去定義它的,我在開發(fā)過程中有一些頁面他們的某一部分都是相同,早之前可能大家可能會(huì)在一個(gè)React組件加
先定一個(gè)layout(本職也是React組件)BasicLayout.jsx
import React from "react"; class BasicLayout extends React.PureComponent{ render(){ const {children} = this.props; return () } } export default BasicLayout;隔壁老王今日行程:{children}
定義完之后我們可以這么使用:
import React from "react"; import BasicLayout from "" class Work extends React.PureComponent{ render(){ return ( 今天隔壁老王比較累,不工作!) } } export default BasicLayout;
最后在的dom結(jié)構(gòu)如下:
隔壁老王今日行程:今天隔壁老王比較累,不工作!
這樣我們可以基于BasicLayout做出很多個(gè)像下面的頁面。
隔壁老王今日行程://<不同的內(nèi)容>
使用這種方法就可以將我們得所有路由寫在一起了,可能有人覺得每次都要寫引入BasicLayout很麻煩,有沒有其他更好用的辦法,在講App.jsx的時(shí)候會(huì)說到這里就先跳過。
pages這里的存放的都是頁面級(jí)組件,跟react-router對(duì)應(yīng)的路由需要一一對(duì)應(yīng)。每個(gè)頁面都是一個(gè)文件夾,文件名就是頁面名稱,每個(gè)頁面都要包含如下幾個(gè)文件:
components ---- 存放當(dāng)前頁獨(dú)有的一些組件
redux ---- 存放三個(gè)文件actions.js、actionTypes.js、reducer.js,這幾個(gè)文件應(yīng)該只與這個(gè)頁面相關(guān)
index.jsx ---- 頁面的入口文件
style.scss ---- 頁面所需要的樣式
具體代碼可以自行g(shù)it clone 項(xiàng)目查看,這里就不貼出來了。
scss這里存放共有的scss文件,比較一些常用的功能類、@mixin、@function等等。
store這里有四個(gè)文件:
actions.js
actionTypes.js
reducer.js
index.js
我們知道每個(gè)頁面都有自己的actions.js、actionTypes.js、reducer.js,但是這里是全局的,另外index.js會(huì)向外暴露store,然后再main.js中引入使用。
import {createStore,combineReducers,applyMiddleware} from "redux"; import thunk from "redux-thunk"; import API from "@/api"; import user from "./reducer"; import author from "@/pages/PageOne/redux/reducer"; const rootReducer = combineReducers({ user, author }); const store=createStore( rootReducer, applyMiddleware(thunk.withExtraArgument({ API })) ) export default store;
這里有一個(gè)小細(xì)節(jié),redux-thunk是可以攜帶一些額外的對(duì)象或者方法的,這里,我攜帶API對(duì)象。當(dāng)我們需要在actions.js里面使用API對(duì)象時(shí),就不需要再import導(dǎo)入進(jìn)來。下面我們做個(gè)對(duì)比:
修改前
import * as actionTypes from "./actionTypes"; import API from "../api"; export const fecthUserName=(params)=> async (dispatch,getState)=>{ const response =await API.fetchUserInfo(params); const {success,data} = response; if(success){ dispatch({ type:actionTypes.CHANGE_USER_NAME, payload:data }); } }
修改后
import * as actionTypes from "./actionTypes"; export const fecthUserName=(params)=> async (dispatch,getState,{API})=>{ const response =await API.fetchUserInfo(params); const {success,data} = response; if(success){ dispatch({ type:actionTypes.CHANGE_USER_NAME, payload:data }); } }utils
這里會(huì)存放一些自己的封裝的js工具文件,比如我在項(xiàng)目基于axios封裝了一個(gè)http.js,簡化了axios的操作。
router/index.js這里以配置化的防止去注冊路由,并app.js里面去渲染路由標(biāo)簽。
import Loadable from "react-loadable"; import createHistory from "history/createBrowserHistory"; import BasicLayout from "@/layouts/BasicLayout"; import NavTwoLayout from "@/layouts/NavTwoLayout"; import Loading from "@/components/Loading"; import NotFound from "@/pages/Exception/404"; const Home = Loadable({loader: () => import("@/pages/Home"),loading: Loading}); const Teachers = Loadable({loader: () => import("@/pages/Teachers"),loading: Loading}); export const history = createHistory(); export const routes = [ { path:"/", redirect:"/navone/home" }, { path:"/navone", redirect:"/navone/home", children:[{ path:"/home", layout:BasicLayout, component:Home }] }, { path:"/navtwo", redirect:"/navtwo/teachers", children:[{ path:"/teachers", layout:NavTwoLayout, component:Teachers }] }, { path:"*", component:NotFound } ]App.js
這里根據(jù)路由配置用來渲染路由標(biāo)簽,先放代碼:
import React from "react"; import {Router} from "react-router-dom"; import {Switch, Route ,Redirect} from "react-router"; import {history,routes} from "@/router"; function getRouterByRoutes(routes){ const renderedRoutesList = []; const renderRoutes = (routes,parentPath)=>{ Array.isArray(routes)&&routes.forEach((route)=>{ const {path,redirect,children,layout,component} = route; if(redirect){ renderedRoutesList.push() } if(component){ renderedRoutesList.push( layout? React.createElement(layout,props,React.createElement(component,props))} />: ) } if(Array.isArray(children)&&children.length>0){ renderRoutes(children,path) } }); } renderRoutes(routes,"") return renderedRoutesList; } class App extends React.PureComponent{ render(){ return ( ) } } export default App; {getRouterByRoutes(routes)}
這里我們需要重點(diǎn)講的是之間在layouts中我們跳過的內(nèi)容,能不能不每次都用layout組件去包裹代碼,答案是可以的。這里我選擇
webpack入口文件,主要一些全局js或者scss的導(dǎo)入,并執(zhí)行react-dom下的render方法,代碼如下:
import React from "react"; import {render} from "react-dom"; import {Provider} from "react-redux"; import store from "@/store"; import App from "@/App"; import "@/scss/reset.scss"; import "@/scss/base.scss"; render(static, document.getElementById("app") )
這是一個(gè)靜態(tài)資源目錄,一般存放一些第三方工具庫。這個(gè)目錄主要兩方面考慮:
有些第三方工具庫沒有npm包,我們無法用npm install 或者 yarn add方式添加
一些比較大的第三方工具庫會(huì)影響我們的打包速度,可以把它拿出來通過script的方式引入
其實(shí)第三方工具庫最好的方式是CDN,但是有些公司就是沒有,無奈只能如此。你加入的第三工具庫都可在當(dāng)前服務(wù)器下”/static/*“路徑下獲取到。
templates這里存放著頁面和組件級(jí)別構(gòu)建所需要的模板文件,頁面級(jí)別構(gòu)建提供了兩種模板PageReducer(集成了reducer)和PageSample(不集成reducer),而組件只提供了一種模板ComSample。頁面和組件級(jí)別的構(gòu)建是需要配合asuna-cli才能構(gòu)建,目前項(xiàng)目已經(jīng)集成了asuna-cli。package.json寫了兩個(gè)script:npm run newPage(頁面構(gòu)建)和npm run newComponent(組件構(gòu)建)。開發(fā)可根據(jù)實(shí)際需要選擇構(gòu)建,asuna-cli具體使用可以去https://github.com/ruichengpi...查看。
其他文件.babelrc ---- babel轉(zhuǎn)換的配置文件
.gitignore ---- git操作所需要忽略的文件
.postcssrc.js ---- postcss的配置文件
index.html ---- 模板index.html,webpack會(huì)根據(jù)此生成新的index.html,配合html-webpack-plugin使用
package.json ---- 家喻戶曉的東西
README.md ---- 項(xiàng)目說明
theme.js ---- ant-design的主題色配置文件,具體使用可以參考ant-design
asuna.config.js ---- asuna-cli的配置文件
yarn.lock ---- 鎖定包的版本
結(jié)語這個(gè)只是個(gè)人搭建企業(yè)級(jí)React項(xiàng)目的一些總結(jié)。當(dāng)然存在不足的地方,后面在工作過程中如果有一些好的想法也會(huì)在這上面進(jìn)行更新。歡迎大家Star關(guān)注!如果你也有好的想法歡迎留言交流,希望這篇拙文能給大家一些啟發(fā)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/108313.html
摘要:很長一段時(shí)間就想把引入公司的項(xiàng)目,但總是因?yàn)橐恍┰虮粩R置。接下來有機(jī)會(huì)重構(gòu)之前的項(xiàng)目,借此機(jī)會(huì)正好可以引入,為了使后期的項(xiàng)目架構(gòu)更加完善,近期我會(huì)梳理的一些知識(shí)點(diǎn)和新特性。 很長一段時(shí)間就想把ts引入公司的項(xiàng)目,但總是因?yàn)橐恍┰虮粩R置。接下來有機(jī)會(huì)重構(gòu)之前的rn項(xiàng)目,借此機(jī)會(huì)正好可以引入ts,為了使后期的項(xiàng)目架構(gòu)更加完善,近期我會(huì)梳理rn的一些知識(shí)點(diǎn)和新特性。 首先來介紹下Type...
摘要:更多資源請文章轉(zhuǎn)自月份前端資源分享的作用數(shù)組元素隨機(jī)化排序算法實(shí)現(xiàn)學(xué)習(xí)筆記數(shù)組隨機(jī)排序個(gè)變態(tài)題解析上個(gè)變態(tài)題解析下中的數(shù)字前端開發(fā)筆記本過目不忘正則表達(dá)式聊一聊前端存儲(chǔ)那些事兒一鍵分享到各種寫給剛?cè)腴T的前端工程師的前后端交互指南物聯(lián)網(wǎng)世界的 更多資源請Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfr...
摘要:純前端開發(fā)主要是針對(duì)靜態(tài)頁面。自主權(quán)最大,正常是使用進(jìn)行輔助開發(fā),上線等。大致原因使用是為了和端的保持同步。四總結(jié)對(duì)于比較正式的項(xiàng)目,前端技術(shù)選型策略一定是產(chǎn)品收益最大化,用戶在首位。 對(duì)于前端團(tuán)隊(duì),可以實(shí)現(xiàn)企業(yè)受益最大化要點(diǎn)。 一、技術(shù)選型的策略 1、保證產(chǎn)品質(zhì)量 (1)功能穩(wěn)?。壕W(wǎng)頁不白屏,不錯(cuò)位,不卡死;操作正常;數(shù)據(jù)精準(zhǔn)。 (2)體驗(yàn)優(yōu)秀:加載體驗(yàn),交互體驗(yàn),視覺體驗(yàn),無障礙訪...
摘要:與此同時(shí),因新冠疫情的影響使得用戶對(duì)移動(dòng)應(yīng)用程序的需求激增。調(diào)查報(bào)告顯示年移動(dòng)應(yīng)用程序已經(jīng)產(chǎn)生了億美元的收入,預(yù)計(jì)到年將產(chǎn)生億美元的收入。 引言 計(jì)劃在2021年進(jìn)...
閱讀 1996·2021-10-20 13:49
閱讀 1515·2019-08-30 15:52
閱讀 3001·2019-08-29 16:37
閱讀 1175·2019-08-29 10:55
閱讀 3226·2019-08-26 12:14
閱讀 1796·2019-08-23 17:06
閱讀 3377·2019-08-23 16:59
閱讀 2702·2019-08-23 15:42