摘要:隔壁老王今日行程不同的內容使用這種方法就可以將我們得所有路由寫在一起了,可能有人覺得每次都要寫引入很麻煩,有沒有其他更好用的辦法,在講的時候會說到這里就先跳過。
前言
距離上篇文章已經好長一段時間了,這兩個星期公司派駐到京東方這邊出差負責入駐項目團隊的前端工作。這段時間從零搭建一下前端項目,這次給的時間比較充裕,思考的也比較多。以前也常有搭過前端項目,但是給的時間都比較緊,因此很多問題都忽略掉了。這次正好對以前的進行一次優化,并總結了一些經驗分想給大家。如果大家有更好的想法,歡迎留言交流。
溫馨提示:
這個項目是以PC端前端項目為視角,移動端前端項目并不完全適用。這點各位小伙們還需要注意一下。
該項目已分不同方向去維護,每個分支與之對應的方向可在CONTRIBUTING.md里查看
項目說明項目地址: https://github.com/ruichengpi...
該項目可以用我自己寫的腳手架工具asuna-cli完成項目構建,我自己寫的腳手架工具地址如下:
https://github.com/ruichengpi...
以上是示例項目的目錄結構,下面我們將逐一進行分析**build
這個文件主要放了一些與webpack打包的相關文件。
build.js ---- webpack打包腳本,用于構建生產環境的包
check-versions.js ---- 主要檢測當前打包環境的node以及npm的版本是否符合要求
utils.js ---- webpack打包所需要的一些工具庫
webpack.base.conf.js ---- webpack的一些基礎配置,不同環境的webpack配置都是基于此
webpack.dev.conf.js ---- 開發環境的webpack配置
webpack.prod.conf.js ---- 生產環境的webpack配置
這個項目的webpack配置我是在vue-cli的項目上進行修改的,可以用于React的項目構建。目前只要開發環境和生產環境這兩個環境,可能一些公司有多個環境,每個環境下webpack的配置還不同,此時可以根據不同環境建一個文件名格式為“webpack.<環境名>.conf.js”的webpack配置使用。webpack.base.conf.js里面有一些基本配置比如rules、input、output的等配置,一般來說每個環境下這些大致都是相同,一些不同之處可以用webpack-merge插件進行合并。一般來說大多數項目來說開發環境和生產環境兩個webpack配置足夠了。
config這里存放著不同環境webpack所需要的配置參數。
dev.env.js ---- 向外暴露開發環境下的環境變量NODE_ENV
index.js ---- 存放不同環境的配置參數
prod.env.js ---- 向外暴露生產環境下的環境變量NODE_ENV
如果你需要再加一個環境的話,可以建一個文件名為“<環境名>.env.js”并向外暴露環境變量NODE_ENV,然后在index.js中導入,進行相關參數設置。
mock這里是用來做接口的mock的,可能很多公司都不太用,我在工作也很少去mock。這里介紹一下自己的接口mock思路,這里我選擇mockjs加上json-server的組合。二者具體的使用,大家可以查看其官方文檔。
api ---- 存放不同api所對應的數據
index.js ---- json-server的主文件
routes.json ---- 路由的映射
package.json我配置一個script,如下:
"mock": "json-server mock/index.js --port 3000 --routes mock/routes.json"
控制臺執行“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的接口地址,為了后續的接口維護,我們在使用的過程中不會直接寫死接口地址,而是將接口請求封裝成一個個方法。通過對接口的統一維護,我們就可以做到在執行修改接口地址、修改請求方法、新增接口等等操作時,就不用在整個項目里到處找了,只要維護好url.js向外暴露的對象即可。使用方法如下:
import {API} from "@/api" //params為請求參數 API.fetchUserInfo(params).then(response=>{ //response為返回值 ... })assets
這里我們會放項目的所需要圖片資源,這些圖片資源一般來說都是做圖標的,都比較小。webpack會將其轉化成BASE64去使用。如果你不想以這種方式使用,可以在static目錄下存放圖片資源。
components這里存放整個項目所用到的公共組件。定一個組件,這里要求是新建一個文件夾,文件夾名為組件名,另外在這個文件夾下新建index.jsx和style.scss文件。例如做一個HelloWorld組件,則應該是如下結構。
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
這里存放著布局文件。關于這個布局文件我是這么去定義它的,我在開發過程中有一些頁面他們的某一部分都是相同,早之前可能大家可能會在一個React組件加
先定一個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結構如下:
隔壁老王今日行程:今天隔壁老王比較累,不工作!
這樣我們可以基于BasicLayout做出很多個像下面的頁面。
隔壁老王今日行程://<不同的內容>
使用這種方法就可以將我們得所有路由寫在一起了,可能有人覺得每次都要寫引入BasicLayout很麻煩,有沒有其他更好用的辦法,在講App.jsx的時候會說到這里就先跳過。
pages這里的存放的都是頁面級組件,跟react-router對應的路由需要一一對應。每個頁面都是一個文件夾,文件名就是頁面名稱,每個頁面都要包含如下幾個文件:
components ---- 存放當前頁獨有的一些組件
redux ---- 存放三個文件actions.js、actionTypes.js、reducer.js,這幾個文件應該只與這個頁面相關
index.jsx ---- 頁面的入口文件
style.scss ---- 頁面所需要的樣式
具體代碼可以自行git clone 項目查看,這里就不貼出來了。
scss這里存放共有的scss文件,比較一些常用的功能類、@mixin、@function等等。
store這里有四個文件:
actions.js
actionTypes.js
reducer.js
index.js
我們知道每個頁面都有自己的actions.js、actionTypes.js、reducer.js,但是這里是全局的,另外index.js會向外暴露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;
這里有一個小細節,redux-thunk是可以攜帶一些額外的對象或者方法的,這里,我攜帶API對象。當我們需要在actions.js里面使用API對象時,就不需要再import導入進來。下面我們做個對比:
修改前
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
這里會存放一些自己的封裝的js工具文件,比如我在項目基于axios封裝了一個http.js,簡化了axios的操作。
router/index.js這里以配置化的防止去注冊路由,并app.js里面去渲染路由標簽。
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
這里根據路由配置用來渲染路由標簽,先放代碼:
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)}
這里我們需要重點講的是之間在layouts中我們跳過的內容,能不能不每次都用layout組件去包裹代碼,答案是可以的。這里我選擇
webpack入口文件,主要一些全局js或者scss的導入,并執行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") )
這是一個靜態資源目錄,一般存放一些第三方工具庫。這個目錄主要兩方面考慮:
有些第三方工具庫沒有npm包,我們無法用npm install 或者 yarn add方式添加
一些比較大的第三方工具庫會影響我們的打包速度,可以把它拿出來通過script的方式引入
其實第三方工具庫最好的方式是CDN,但是有些公司就是沒有,無奈只能如此。你加入的第三工具庫都可在當前服務器下”/static/*“路徑下獲取到。
templates這里存放著頁面和組件級別構建所需要的模板文件,頁面級別構建提供了兩種模板PageReducer(集成了reducer)和PageSample(不集成reducer),而組件只提供了一種模板ComSample。頁面和組件級別的構建是需要配合asuna-cli才能構建,目前項目已經集成了asuna-cli。package.json寫了兩個script:npm run newPage(頁面構建)和npm run newComponent(組件構建)。開發可根據實際需要選擇構建,asuna-cli具體使用可以去https://github.com/ruichengpi...查看。
其他文件.babelrc ---- babel轉換的配置文件
.gitignore ---- git操作所需要忽略的文件
.postcssrc.js ---- postcss的配置文件
index.html ---- 模板index.html,webpack會根據此生成新的index.html,配合html-webpack-plugin使用
package.json ---- 家喻戶曉的東西
README.md ---- 項目說明
theme.js ---- ant-design的主題色配置文件,具體使用可以參考ant-design
asuna.config.js ---- asuna-cli的配置文件
yarn.lock ---- 鎖定包的版本
結語這個只是個人搭建企業級React項目的一些總結。當然存在不足的地方,后面在工作過程中如果有一些好的想法也會在這上面進行更新。歡迎大家Star關注!如果你也有好的想法歡迎留言交流,希望這篇拙文能給大家一些啟發。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108313.html
摘要:很長一段時間就想把引入公司的項目,但總是因為一些原因被擱置。接下來有機會重構之前的項目,借此機會正好可以引入,為了使后期的項目架構更加完善,近期我會梳理的一些知識點和新特性。 很長一段時間就想把ts引入公司的項目,但總是因為一些原因被擱置。接下來有機會重構之前的rn項目,借此機會正好可以引入ts,為了使后期的項目架構更加完善,近期我會梳理rn的一些知識點和新特性。 首先來介紹下Type...
摘要:更多資源請文章轉自月份前端資源分享的作用數組元素隨機化排序算法實現學習筆記數組隨機排序個變態題解析上個變態題解析下中的數字前端開發筆記本過目不忘正則表達式聊一聊前端存儲那些事兒一鍵分享到各種寫給剛入門的前端工程師的前后端交互指南物聯網世界的 更多資源請Star:https://github.com/maidishike... 文章轉自:https://github.com/jsfr...
摘要:純前端開發主要是針對靜態頁面。自主權最大,正常是使用進行輔助開發,上線等。大致原因使用是為了和端的保持同步。四總結對于比較正式的項目,前端技術選型策略一定是產品收益最大化,用戶在首位。 對于前端團隊,可以實現企業受益最大化要點。 一、技術選型的策略 1、保證產品質量 (1)功能穩健:網頁不白屏,不錯位,不卡死;操作正常;數據精準。 (2)體驗優秀:加載體驗,交互體驗,視覺體驗,無障礙訪...
摘要:與此同時,因新冠疫情的影響使得用戶對移動應用程序的需求激增。調查報告顯示年移動應用程序已經產生了億美元的收入,預計到年將產生億美元的收入。 引言 計劃在2021年進...
閱讀 1814·2021-10-20 13:49
閱讀 1356·2019-08-30 15:52
閱讀 2862·2019-08-29 16:37
閱讀 1033·2019-08-29 10:55
閱讀 3064·2019-08-26 12:14
閱讀 1649·2019-08-23 17:06
閱讀 3235·2019-08-23 16:59
閱讀 2543·2019-08-23 15:42