diff --git a/package.json b/package.json index 5034f63..eaf7823 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "serve": "webpack serve --open --config webpack.dev.js", + "start": "webpack serve --open --config webpack.dev.js", "build": "webpack --config webpack.prod.js", "pre-commit": "lint-staged" }, diff --git a/public/index.html b/public/index.html index fecfdf5..539ace7 100644 --- a/public/index.html +++ b/public/index.html @@ -5,7 +5,7 @@ - + <%= htmlWebpackPlugin.options.title %> diff --git a/src/App.js b/src/App.js new file mode 100644 index 0000000..476100a --- /dev/null +++ b/src/App.js @@ -0,0 +1,8 @@ +import React from 'react' +import Router from './router' + +const App = () => { + return +} + +export default App diff --git a/src/config/defaultApp.js b/src/config/defaultApp.js new file mode 100644 index 0000000..a577904 --- /dev/null +++ b/src/config/defaultApp.js @@ -0,0 +1,15 @@ +const { RouteCode } = require('./routeConstants') + +module.exports = { + name: 'app', + urls: { + loginUrl: '/passport/login', + defaultUrl: '/home/index', + }, + redirects: [ + { + from: RouteCode.ROOT, + to: RouteCode.PAGE_HOME, + }, + ], +} diff --git a/src/config/routeConstants.js b/src/config/routeConstants.js new file mode 100644 index 0000000..f92c1d4 --- /dev/null +++ b/src/config/routeConstants.js @@ -0,0 +1,11 @@ +export const RoutePath = { + ROOT: 'layout', + LAYOUT_BASIC: 'layout/basic', + PAGE_HOME: 'page/home', +} + +export const RouteCode = { + ROOT: 'LAYOUT', + LAYOUT_BASIC: 'LAYOUT_BASIC', + PAGE_HOME: 'PAGE_HOME', +} diff --git a/src/index.js b/src/index.js index ea97850..7935655 100644 --- a/src/index.js +++ b/src/index.js @@ -3,13 +3,13 @@ import 'regenerator-runtime' import React from 'react' import ReactDOM from 'react-dom' -import Router from './router' +import App from './App' import { Provider } from 'react-redux' import store from './store' const element = ( - + ) diff --git a/src/layout/index.js b/src/layout/index.js new file mode 100644 index 0000000..15865db --- /dev/null +++ b/src/layout/index.js @@ -0,0 +1,8 @@ +import React from 'react' +import { Outlet } from 'react-router-dom' + +const Layout = () => { + return +} + +export default Layout diff --git a/src/router/index.js b/src/router/index.js index 77c2013..aaba76c 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,15 +1,47 @@ -import React from 'react' -import { BrowserRouter, Route, Routes } from 'react-router-dom' -import BasicLayout from '../layout/basic' -import Home from '../page/home' +import React, { lazy, Suspense } from 'react' +import { useSelector } from 'react-redux' +import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom' +import Redirect from './redirect' +import { defaultRoutes } from './routes' +import { routerTool } from '../util/router' const Router = () => { + const appUrls = useSelector((state) => state.app.urls) + const redirects = useSelector((state) => state.app.redirects) + + const processRoutes = (params) => { + if (!params) return [] + let allRedirects = routerTool.processRoutes(defaultRoutes, redirects) + let routes = params.map((item) => { + let Component = lazy(() => import(`src/${item.component}`)) + let redirect = allRedirects.find((p) => p.from === item.code) + let props = { + element: ( + loading}> + + + + + ), + path: item.path, + } + return ( + + {processRoutes(item.children)} + + ) + }) + return routes + } + return ( - }> - } index /> - + {processRoutes(defaultRoutes)} + } + /> ) diff --git a/src/router/redirect.js b/src/router/redirect.js new file mode 100644 index 0000000..a8f8bf8 --- /dev/null +++ b/src/router/redirect.js @@ -0,0 +1,20 @@ +/* eslint-disable react/prop-types */ +import React, { useEffect } from 'react' +import { generatePath, useMatch, useNavigate } from 'react-router-dom' + +const Redirect = (props) => { + const match = useMatch(props.redirect) + const navigate = useNavigate() + useEffect(() => { + if (props.redirect) { + if (match) { + navigate(generatePath(props.redirect, match.params)) + } else { + navigate(props.redirect) + } + } + }, []) + return <>{props.children} +} + +export default Redirect diff --git a/src/router/routes.js b/src/router/routes.js new file mode 100644 index 0000000..52ba3ec --- /dev/null +++ b/src/router/routes.js @@ -0,0 +1,26 @@ +import { RouteCode, RoutePath } from '../config/routeConstants' + +export const defaultRoutes = [ + { + code: RouteCode.ROOT, + title: 'root', + path: '/', + component: RoutePath.ROOT, + children: [ + { + code: RouteCode.LAYOUT_BASIC, + title: 'home', + path: 'home', + component: RoutePath.LAYOUT_BASIC, + children: [ + { + code: RouteCode.PAGE_HOME, + title: 'index', + path: 'index', + component: RoutePath.PAGE_HOME, + }, + ], + }, + ], + }, +] diff --git a/src/store/index.js b/src/store/index.js index 4f0729c..5344590 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -2,11 +2,11 @@ import { createStore, combineReducers, applyMiddleware, compose } from 'redux' import thunk from 'redux-thunk' import storageEnhancer from './enhancer/storage' import loggerMiddleware from './middleware/logger' +import appReducer from './reducer/app' import countReducer from './reducer/count' -import todoReducer from './reducer/todo' const reducer = combineReducers({ - todo: todoReducer, + app: appReducer, count: countReducer, }) const middlewareEnhancer = applyMiddleware(loggerMiddleware, thunk) diff --git a/src/store/reducer/app.js b/src/store/reducer/app.js new file mode 100644 index 0000000..aca504e --- /dev/null +++ b/src/store/reducer/app.js @@ -0,0 +1,18 @@ +import defaultApp from '../../config/defaultApp' +import { copyTool } from '../../util/copy' +import { storeTool } from '../../util/store' + +const fetch = async (state) => { + return state +} + +const update = async (state, ...props) => { + return copyTool.merger(state, ...props)() +} + +const appReducer = storeTool.createReducer(defaultApp, { + APP_FETCH: fetch, + APP_UPDATE: update, +}) + +export default appReducer diff --git a/src/store/reducer/count.js b/src/store/reducer/count.js index 53f68dd..7c2caf1 100644 --- a/src/store/reducer/count.js +++ b/src/store/reducer/count.js @@ -1,15 +1,15 @@ import { storeTool } from '../../util/store' -const addCount = (countState) => { - return countState + 1 +const addCount = (state) => { + return state + 1 } -const setCount = (countState, param) => { +const setCount = (state, param) => { return param } -const delCount = (countState) => { - return countState <= 0 ? 0 : countState - 1 +const delCount = (state) => { + return state <= 0 ? 0 : state - 1 } const countReducer = storeTool.createReducer(0, { diff --git a/src/store/reducer/todo.js b/src/store/reducer/todo.js deleted file mode 100644 index 9a150e2..0000000 --- a/src/store/reducer/todo.js +++ /dev/null @@ -1,30 +0,0 @@ -import { storeTool } from '../../util/store' - -const addTodo = (todoState, param) => { - const newTodo = todoState.concat(param) - return newTodo -} - -const editTodo = (todoState, param) => { - const _index = todoState.findIndex((item) => item.id === param.id) - if (_index < 0) return newTodo - const newTodo = storeTool.updateItemInArray(todoState, _index, (item) => { - return storeTool.updateObject(item, param) - }) - return newTodo -} - -const delTodo = (todoState, param) => { - const _index = todoState.findIndex((item) => item.id === param.id) - if (_index < 0) return newTodo - const newTodo = todoState.splice(_index, 1) - return newTodo -} - -const todoReducer = storeTool.createReducer([{ id: 1, name: 'hello' }], { - ADD_TODO: addTodo, - EDIT_TODO: editTodo, - DEL_TODO: delTodo, -}) - -export default todoReducer diff --git a/src/util/copy.js b/src/util/copy.js new file mode 100644 index 0000000..adfb6c0 --- /dev/null +++ b/src/util/copy.js @@ -0,0 +1,74 @@ +const defineType = (param) => { + let type = Object.prototype.toString.call(param) + return type.split(' ')[1].split(']')[0] +} + +const mergeObject = (target = {}, source, isJoin, isReplace, isFilter) => { + for (const key in source) { + if (Object.hasOwnProperty.call(target, key)) { + if (isReplace) { + target[key] = source[key] + } else { + target[key] = merger(target[key], source[key])( + isJoin, + isReplace, + isFilter + ) + } + } else { + if (isJoin) { + target[key] = merger(target[key], source[key])( + isJoin, + isReplace, + isFilter + ) + } + } + } + return target +} + +const mergeArray = (target = [], source, isJoin, isReplace, isFilter) => { + if (isJoin) { + target = [...target, ...source] + } else { + for (let i = 0; i < source.length; i++) { + if (isReplace) { + target[i] = source[i] + } else { + target[i] = merger((target && target[i]) || undefined, source[i])( + isJoin, + isReplace, + isFilter + ) + } + } + } + if (isFilter) { + target = [...new Set(target)] + } + return target +} + +const merger = (...props) => { + let res + const merge = (isJoin = true, isReplace = false, isFilter = true) => { + for (let i = 0; i < props.length; i++) { + switch (defineType(props[i])) { + case 'Array': + res = mergeArray(res, props[i], isJoin, isReplace, isFilter) + break + case 'Object': + res = mergeObject(res, props[i], isJoin, isReplace, isFilter) + break + default: + res = props[i] + break + } + } + return res + } + return merge +} + +export const copyTool = { merger } diff --git a/src/util/router.js b/src/util/router.js new file mode 100644 index 0000000..0c4523e --- /dev/null +++ b/src/util/router.js @@ -0,0 +1,33 @@ +const findPath = (params, code) => { + for (let i = 0; i < params.length; i++) { + if (params[i].code === code) { + return [params[i].path] + } else { + if (params[i].children) { + let childPath = findPath(params[i].children, code) + return childPath ? [params[i].path, ...childPath] : [] + } + return [] + } + } +} + +const processRoutes = (routes, redirects) => { + return redirects.map((item) => { + let fromUrl = findPath(routes, item.from) + if (fromUrl.length > 0) { + fromUrl = fromUrl.join('/').replace('//', '/') + } + let toUrl = findPath(routes, item.to) + if (toUrl.length > 0) { + toUrl = toUrl.join('/').replace('//', '/') + } + return { + ...item, + fromUrl, + toUrl, + } + }) +} + +export const routerTool = { processRoutes } diff --git a/src/util/store.js b/src/util/store.js index a0146e7..ba2b944 100644 --- a/src/util/store.js +++ b/src/util/store.js @@ -1,20 +1,3 @@ -const updateObject = (oldVal, newVal) => { - return Object.assign({}, oldVal, newVal) -} - -const updateItemInArray = (array, index, updateCallback) => { - const updatedArray = array.map((_item, _index) => { - if (_index !== index) { - return _item - } - - const updatedItem = updateCallback(_item) - return updatedItem - }) - - return updatedArray -} - const createReducer = (initialState, handlers) => { return function reducer(state = initialState, action) { if (Object.prototype.hasOwnProperty.call(handlers, action.type)) { @@ -25,4 +8,4 @@ const createReducer = (initialState, handlers) => { } } -export const storeTool = { createReducer, updateObject, updateItemInArray } +export const storeTool = { createReducer } diff --git a/webpack.dev.js b/webpack.dev.js index 070ef67..0bcae59 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -1,3 +1,4 @@ +const path = require('path') const CaseSensitivePathsWebpackPlugin = require('case-sensitive-paths-webpack-plugin') const { merge } = require('webpack-merge') const common = require('./webpack.common')