├── .editorconfig
├── .env-cmdrc.js
├── .github
└── workflows
│ └── updatePages.yml
├── .gitignore
├── LICENSE
├── README.md
├── color.js
├── config
├── env.js
├── getHttpsConfig.js
├── jest
│ ├── babelTransform.js
│ ├── cssTransform.js
│ └── fileTransform.js
├── modules.js
├── paths.js
├── pnpTs.js
├── webpack.config.js
└── webpackDevServer.config.js
├── jsconfig.json
├── package.json
├── public
├── favicon.ico
├── iconfont.js
├── index.html
├── less.min.js
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── scripts
├── build.js
├── start.js
└── test.js
└── src
├── App.js
├── api
└── index.js
├── assets
├── images
│ ├── bg.svg
│ ├── layout1.jpg
│ ├── layout2.jpg
│ ├── layout3.jpg
│ └── logo.svg
├── json
│ └── iconfont.json
└── theme
│ └── var.less
├── common
├── ajax.js
├── index.js
└── var.js
├── components
├── color
│ ├── index.js
│ └── index.less
├── contextMenu
│ ├── index.js
│ └── index.less
├── dnd
│ └── free.js
├── echarts
│ ├── bar
│ │ └── index.js
│ ├── index.js
│ ├── line
│ │ └── index.js
│ └── pie
│ │ └── index.js
├── form
│ └── index.js
├── icon
│ └── index.js
├── layout-set
│ ├── index.js
│ └── index.less
├── menu-dnd
│ ├── index.js
│ └── index.less
├── modal
│ ├── feedback
│ │ └── index.js
│ ├── menu
│ │ ├── index.js
│ │ └── index.less
│ ├── type
│ │ └── index.js
│ └── user
│ │ └── index.js
├── pagination
│ ├── index.js
│ └── index.less
├── table
│ ├── index.js
│ └── index.less
└── theme
│ ├── index.js
│ └── index.less
├── index.js
├── layout
├── footer.js
├── header.js
├── index.js
├── index.less
├── mode
│ ├── fullScreen.js
│ ├── index.js
│ ├── singleColumn.js
│ ├── twoColumn.js
│ └── twoFlanks.js
├── siderMenu.js
└── topMenu.js
├── mock
└── index.js
├── pages
├── details
│ ├── index.less
│ └── person.js
├── err
│ └── index.js
├── form
│ ├── index.js
│ └── index.less
├── icons
│ ├── index.js
│ └── index.less
├── list
│ ├── card.js
│ ├── index.less
│ └── search.js
├── login
│ ├── index.js
│ └── index.less
├── power
│ ├── index.less
│ ├── menu.js
│ ├── type.js
│ └── user.js
└── statistics
│ ├── feedback.js
│ ├── index.less
│ └── vistor.js
├── router
├── appRouter.js
├── index.js
├── intercept.js
└── list.js
├── setupProxy.js
├── store
├── action.js
├── getters
│ ├── index.js
│ ├── layout.js
│ ├── menu.js
│ ├── user.js
│ └── visibel.js
├── hooks
│ ├── index.js
│ ├── layout.js
│ ├── menu.js
│ ├── user.js
│ └── visibel.js
├── index.js
├── layout
│ ├── action.js
│ ├── actionTypes.js
│ └── reducer.js
├── menu
│ ├── action.js
│ ├── actionTypes.js
│ └── reducer.js
├── user
│ ├── action.js
│ ├── actionTypes.js
│ └── reducer.js
└── visibel
│ ├── action.js
│ └── reducer.js
└── utils
└── index.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [Makefile]
15 | indent_style = tab
16 |
--------------------------------------------------------------------------------
/.env-cmdrc.js:
--------------------------------------------------------------------------------
1 |
2 | const devConfig = {
3 | PORT: 3000, // 启动端口
4 | HOST: "0.0.0.0", // 监听地址
5 | REACT_APP_ROUTERBASE: "/react-ant-admin", // react路由基础路径
6 | REACT_APP_API_BASEURL: "http://127.0.0.1:8081/api/react-ant-admin", //请求地址
7 | PUBLIC_URL: "/react-ant-admin",// 静态文件路径
8 | }
9 | const proConfig = {
10 | REACT_APP_ROUTERBASE: "/react-ant-admin", // react路由基础路径
11 | REACT_APP_API_BASEURL: "/api/react-ant-admin", //请求地址
12 | PUBLIC_URL: "/react-ant-admin",// 静态文件路径
13 | BUILD_PATH: "react-ant-admin", // 打包 文件夹名称
14 | }
15 |
16 | /**
17 | * env-cmd 文档地址 https://github.com/toddbluhm/env-cmd#-help
18 | * 命令行使用: env-cmd --verbose -e mode_name node file.js
19 | * mode_name: 对应 mode 里面的 属性(key) 例如 development development_color
20 | * 运行结果:
21 | * 取出 对应 mode_name 的 值(value) Object.keys方法 把 key-value 绑定到 process.env 上
22 | * 如 : development(mode_name): { test : "123" } => process.env.test = "123"
23 | * 最终能够在整个项目中 使用 process.env.test
24 | */
25 | const mode = {
26 |
27 | // 本地接口正常运行 没有mock 没有 主题色
28 | development: devConfig,
29 |
30 | // 本地接口 启用主题色运行
31 | development_color: {
32 | ...devConfig,
33 | COLOR: "true", // "true" 为 启动
34 | },
35 |
36 | // 本地mock 运行
37 | development_mock: {
38 | ...devConfig,
39 | REACT_APP_MOCK: "1", // 1 为开启mock
40 | },
41 |
42 | // 主题色 和 本地mock 运行
43 | development_color_mock: {
44 | ...devConfig,
45 | COLOR: "true",
46 | REACT_APP_MOCK: "1",
47 | },
48 |
49 | // 打包 :无主题 无mock
50 | production: proConfig,
51 |
52 | // 打包 : 有主题 无mock
53 | production_color: {
54 | ...proConfig,
55 | COLOR: "true", // "true" 为 启动
56 | },
57 |
58 | // 打包 : 有主题 有mock 纯本地模式打包
59 | production_color_mock: {
60 | ...proConfig,
61 | COLOR: "true",
62 | REACT_APP_MOCK: "1",
63 | },
64 |
65 | // GitHub pages 打包 博主使用
66 | production_github: {
67 | ...proConfig,
68 | COLOR: "true",
69 | REACT_APP_API_BASEURL: "https://z3web.cn/api/react-ant-admin",
70 | REACT_APP_ROUTER_ISHASH: "1", // 启用哈希模式
71 | REACT_APP_ROUTERBASE: "/"
72 | }
73 | }
74 |
75 |
76 | module.exports = Promise.resolve(mode)
--------------------------------------------------------------------------------
/.github/workflows/updatePages.yml:
--------------------------------------------------------------------------------
1 | name: update pages
2 |
3 | on:
4 | push:
5 | branches: [webpack]
6 | paths: ["src/**","public"]
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 |
12 | strategy:
13 | matrix:
14 | node-version: [12]
15 | steps:
16 | - uses: actions/checkout@v3
17 |
18 | - name: Use Node.js ${{ matrix.node-version }}
19 | uses: actions/setup-node@v3
20 | with:
21 | node-version: ${{ matrix.node-version }}
22 |
23 | - name: Build
24 | run: |
25 | npm install
26 | ./node_modules/.bin/env-cmd --verbose -e production_github --use-shell 'node color.js && node scripts/build.js'
27 |
28 | - name: Deploy 🚀
29 | uses: JamesIves/github-pages-deploy-action@v4.3.0
30 | with:
31 | branch: gh-pages # The branch the action should deploy to.
32 | folder: react-ant-admin # The folder the action should deploy.
33 | clean-exclude: | # exclude files
34 | .gitignore
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | yarn.lock
8 | package-lock.json
9 | /color.js*
10 | /src/assets/theme/*.json
11 | # testing
12 | /coverage
13 | /src/router/auto*
14 |
15 | # production
16 | /react-ant-admin
17 | /public/color.less
18 | /public/index.html
19 | # misc
20 | .DS_Store
21 | .env.local
22 | .env.development.local
23 | .env.test.local
24 | .env.production.local
25 |
26 | npm-debug.log*
27 | yarn-debug.log*
28 | yarn-error.log*
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 孔乙己拉夫米
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-ant-admin
2 |
3 | [](https://github.com/kongyijilafumi/react-ant-admin)
4 | [](https://github.com/kongyijilafumi/react-ant-admin/network/members)
5 | [](https://gitee.com/kong_yiji_and_lavmi/react-ant-admin/stargazers)
6 | [](https://gitee.com/kong_yiji_and_lavmi/react-ant-admin/members)
7 | 
8 |
9 | TypeScript 版[GitHub(国外地址)](https://github.com/kongyijilafumi/react-ant-admin-ts) |
10 | TypeScript 版[码云(国内镜像)](https://gitee.com/kong_yiji_and_lavmi/react-ant-admin-ts)
11 |
12 | JavaScript 版[GitHub(国外地址)](https://github.com/kongyijilafumi/react-ant-admin) |
13 | JavaScript 版[码云(国内镜像)](https://gitee.com/kong_yiji_and_lavmi/react-ant-admin)
14 |
15 | 此框架使用与二次开发,前端框架使用 react,UI 框架使用 ant-design,全局数据状态管理使用 redux,ajax 使用库为 axios。用于快速搭建中后台页面。欢迎各位提[issue](https://github.com/kongyijilafumi/react-ant-admin/issues)
16 |
17 | - [react](https://react.docschina.org/)
18 | - [react-router-cache-route](https://www.npmjs.com/package/react-router-cache-route)
19 | - [ant-design](https://ant.design/index-cn)
20 | - [redux](https://redux.js.org/)
21 | - [axios](http://www.axios-js.com/)
22 |
23 | ## 预览地址
24 |
25 | [react-ant-admin](http://z3web.cn/react-ant-admin/)
26 |
27 | nodejs 后台 web 服务:[react-ant-admin-server](https://gitee.com/kong_yiji_and_lavmi/react-ant-admin-server)
28 |
29 | ## 二次开发视频讲解地址
30 |
31 | - [百度云视频下载地址](https://pan.baidu.com/s/1aJHIhCnv0q1wojUdJknidQ?pwd=y9mx )
32 | - [阿里云视频下载地址](https://www.aliyundrive.com/s/kvfHSoa7fP3)
33 |
34 |
35 | ## 文档地址
36 |
37 | [react-ant-admin 文档地址](https://z3web.cn/doc-react-ant-admin/)
38 |
39 | 更多建议欢迎骚扰~
40 | [qq 交流群:564048130](https://jq.qq.com/?_wv=1027&k=pzP2acC5)
41 |
42 | 欢迎各位提出建议与问题!
43 |
44 | ## [接口文档地址](https://www.apifox.cn/apidoc/project-927261)
45 |
46 | ## 特性
47 |
48 | - 菜单配置:扁平化数据组织,方便编写,存库,页面菜单,标题,侧边栏,顶部导航栏同步
49 | - 页面懒加载:使用[@loadable/component](https://loadable-components.com/docs/getting-started/)来解决首次打开页面过慢的问题.
50 | - Ajax 请求:restful 规范,自动错误提示,提示可配置;自动打断未完成的请求;
51 | - 权限控制: 根据不用角色的功能类型显示菜单,路由页面拦截.
52 | - 自定义主题,可以自己定义界面颜色。
53 | - 代理转发,解决前端请求跨域问题。
54 | - 路由自动生成,去中心化。
55 |
56 | 系统提供了一些基础的页面
57 |
58 | - 登录页
59 | - 详情页
60 | - 表单页
61 | - 列表页
62 | - 权限管理
63 | - 结果页
64 |
65 | ## 切换 Vite 版本
66 |
67 | 1. 切换分支
68 |
69 | ```bash
70 | D:\react-ant-admin>git checkout vite
71 | ```
72 |
73 | 2. 安装依赖
74 |
75 | ```bash
76 | D:\react-ant-admin>cnpm i
77 | ```
78 |
79 | 3. 启动
80 |
81 | ```bash
82 | D:\react-ant-admin>npm run dev
83 | ```
84 |
85 | ## 快速使用
86 |
87 | 1. 下载本项目到本地
88 |
89 | ```bash
90 | D:> git clone https://github.com/kongyijilafumi/react-ant-admin.git #github地址 慢
91 | D:> git clone https://gitee.com/kong_yiji_and_lavmi/react-ant-admin.git #码云地址 快
92 | ```
93 |
94 | 2. 安装依赖
95 |
96 | ```bash
97 | # npm 慢
98 | npm i
99 | # cnpm 国内镜像 快
100 | cnpm i
101 | ```
102 |
103 | 3. 启动
104 |
105 | ```bash
106 | npm run "start:mock" # 启动本地mock数据 (暂时没有后台接口,请用此模式预览项目)
107 | npm run start # 启动本地API接口来获取数据
108 | ```
109 |
110 | 浏览器打开 `http://localhost:3000` 即可
111 |
112 | ## 创建一个新的页面
113 |
114 | 1. 在 src/pages 文件夹下创建一个 test.js 文件,代码如下
115 |
116 | ```js
117 | // 函数组件
118 | import React from "react";
119 |
120 | export default function Test() {
121 | return
test页面
;
122 | }
123 |
124 | // 类组件
125 | export default class Test extends React.Component {
126 | render() {
127 | return test页面
;
128 | }
129 | }
130 |
131 | /**
132 | * MENU_* 开头信息在package.json 文件中找到
133 | * 给 pages 组件追加路由信息
134 | * export default 组件的原型上添加route信息,或者向外暴露一个 route
135 | * 会被webpack的webpack-router-generator插件捕获信息
136 | */
137 |
138 | // 1.被捕获 export default 原型上的route
139 | Test.route={
140 | [MENU_TITLE] : "test页面",
141 | [MENU_KEY] : 11,
142 | [MENU_PATH]: "/test"
143 | }
144 |
145 | // 2.被捕获 暴露的route信息 优先级比上面高
146 | export const route = {
147 | [MENU_TITLE] : "test页面",
148 | [MENU_KEY] : 11,
149 | [MENU_PATH]: "/test"
150 | }
151 | ```
152 |
153 | 2. 浏览器访问 `http://localhost:3000/react-ant-admin/test` 即可
154 |
155 | ## 创建一个菜单
156 |
157 | 该添加方式适用于 `npm run "start:mock"`启动的项目
158 |
159 | 1. 在`src/mock/index.js` 找到`menu`变量,往里添加一条菜单信息.代码如下所示
160 |
161 | ```js
162 | let menu = [
163 | {
164 | [MENU_TITLE]: "列表页",
165 | [MENU_PATH]: "/list",
166 | [MENU_KEY]: 9, // 菜单的唯一标识
167 | [MENU_PARENTKEY]: null,
168 | [MENU_ICON]: "icon_list",
169 | [MENU_KEEPALIVE]: "false",
170 | [MENU_LAYOUT]:"FULLSCREEN" // 页面内容主题全屏显示 布局
171 | [MENU_ORDER]: 1,
172 | },
173 | {
174 | [MENU_TITLE]: "卡片列表",
175 | [MENU_PATH]: "/card",
176 | [MENU_KEY]: 10,
177 | [MENU_PARENTKEY]: 9, // 父菜单的唯一标识
178 | [MENU_ICON]: null,
179 | [MENU_LAYOUT]:"TWO_COLUMN" // 拥有侧边栏的 布局 此属性默认可以不填 在 src/layout/index.js defualt 项导出一个默认布局
180 | [MENU_KEEPALIVE]: "false",
181 | [MENU_ORDER]: 5485,
182 | },
183 | // .... 开始添加菜单信息 ....
184 | {
185 | [MENU_TITLE]: "test", // 标题
186 | [MENU_PATH]: "/test", // 访问路径
187 | [MENU_KEY]: 11, // 菜单的唯一标识
188 | [MENU_PARENTKEY]: null, // 空表示 为主菜单而非子菜单
189 | [MENU_ICON]: "icon_infopersonal", // 菜单图标
190 | [MENU_ORDER]: 1, // 菜单排序 越小越靠前 number
191 | [MENU_KEEPALIVE]: "true", // 页面保持状态
192 | },
193 | // .....
194 | ];
195 | ```
196 |
197 | 2. 由于菜单会走本地会话存储`window.sessionStorage`,所以保存代码后需要关闭当前窗口,重新打开地址 `http://localhost:3000/react-ant-admin`
198 |
199 | > 打开之后,会发现菜单会多出一个`test`栏目,点击会打开之前我们创建的 test 页面.这样就完成了菜单和页面的编写.
200 |
201 | ## 脚本启动
202 |
203 | 在完成依赖安装之后,有以下几种启动方式。
204 |
205 | - npm run start
206 |
207 | 请求接口数据,通过后台返回数据显示项目信息
208 |
209 | - npm run "start:color"
210 |
211 | 请求接口数据,通过后台返回数据显示项目信息,并且开启主题色配置。
212 |
213 | - npm run "start:mock"
214 |
215 | 本地模拟数据,假数据来显示项目信息
216 |
217 | - npm run "start:mock_color"
218 |
219 | 本地模拟数据,假数据来显示项目信息,并且开启主题色配置。
220 |
221 | - npm run build
222 |
223 | 普通打包模式。
224 |
225 | - npm run "build:color"
226 |
227 | 打包主题色。项目体积会有所增加。
228 |
229 | ### vscode 快速启动项目
230 |
231 | 使用[vscode 编辑器](https://code.visualstudio.com/)[下载地址](https://blog.csdn.net/bielaiwuyang1999/article/details/117814237)
232 |
233 | 把此项目文件夹拖入`vscode编辑器`,找到左下角`npm 脚本栏目`选择快速启动,免命令。
234 | 
235 |
236 | ## 项目截图
237 |
238 | - 登录
239 |
240 | 
241 |
242 | - 详情页
243 |
244 | 
245 |
246 | - 列表
247 |
248 | 
249 |
250 | - 权限管理
251 |
252 | 
253 |
254 | - 结果页
255 |
256 | 
257 |
--------------------------------------------------------------------------------
/color.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const fs = require("fs");
3 | const { generateTheme, getLessVars } = require("ant-theme-generator");
4 |
5 | const showColorSet = process.env.COLOR === "true";
6 |
7 | // 变量文件夹
8 | const varFile = path.join(__dirname, "./src/assets/theme/var.less");
9 | const varJsonPath = path.join(__dirname, "./color.json.js");
10 | const outputFilePath = path.join(__dirname, "./public/color.less");
11 | // antd 默认主题 json 文件
12 | const defaultPath = path.join(__dirname, "./src/assets/theme/default.json");
13 | const darkPath = path.join(__dirname, "./src/assets/theme/dark.json");
14 | // antd 主题 less文件
15 | const antdDefaultPath = "./node_modules/antd/lib/style/themes/default.less";
16 | const antdDarkPath = "./node_modules/antd/lib/style/themes/dark.less";
17 | const antdLightPath = "./node_modules/antd/lib/style/themes/compact.less";
18 |
19 | function colorStart() {
20 | try {
21 | var varStr = fs.readFileSync(varFile, "utf-8");
22 | } catch (error) {
23 | throw error;
24 | }
25 |
26 | // 读取less变量文件 提取变量 信息
27 | let varStrArr = varStr.split(/\n/);
28 | let scipteReg = /\/\/\s+script/g;
29 | let slice = [];
30 | varStrArr.forEach((i, index) => {
31 | if (scipteReg.test(i)) {
32 | slice.push(index);
33 | }
34 | });
35 | varStrArr = varStrArr.slice(...slice).filter((i) => i[0] === "@");
36 | let colorsReg = /(.*?)\s*:\s*(.*?);\s*\/\/\s*([\u4e00-\u9fa5]*)/g;
37 | let varColors = [];
38 | varStrArr.forEach((item) => {
39 | colorsReg.lastIndex = 0;
40 | let execRes = colorsReg.exec(item);
41 | if (execRes) {
42 | varColors.push({
43 | title: execRes[3],
44 | key: execRes[1],
45 | value: execRes[2],
46 | });
47 | }
48 | });
49 | // 变量配置信息 写入 color.json.js 文件
50 | var tips = "\n// 本文件由脚本自动生成";
51 | let exportStr = "module.exports=" + JSON.stringify(varColors) + tips;
52 | fs.writeFileSync(varJsonPath, exportStr);
53 | const defaultVars = getLessVars(antdDefaultPath);
54 | const darkVars = {
55 | ...getLessVars(antdDarkPath),
56 | "@primary-color": defaultVars["@primary-color"],
57 | "@picker-basic-cell-active-with-range-color": "darken(@primary-color, 20%)",
58 | };
59 | const lightVars = {
60 | ...getLessVars(antdLightPath),
61 | "@primary-color": defaultVars["@primary-color"],
62 | };
63 | const configVars = reduceMap(varColors, "key", "value");
64 | try {
65 | // 写入json文件
66 | fs.writeFileSync(
67 | defaultPath,
68 | JSON.stringify({
69 | ...defaultVars,
70 | ...lightVars,
71 | ...configVars,
72 | })
73 | );
74 | fs.writeFileSync(
75 | darkPath,
76 | JSON.stringify({
77 | ...defaultVars,
78 | ...darkVars,
79 | ...configVars,
80 | })
81 | );
82 | } catch (error) {
83 | throw error;
84 | }
85 |
86 | // 使用 antd-theme-generator
87 | const options = {
88 | antDir: path.join(__dirname, "./node_modules/antd"),
89 | stylesDir: path.join(__dirname, "./src"),
90 | varFile,
91 | themeVariables: Array.from(
92 | new Set([
93 | ...Object.keys(darkVars),
94 | ...Object.keys(lightVars),
95 | ...Object.keys(defaultVars),
96 | ...varColors.map((i) => i.key),
97 | ])
98 | ), //需要动态切换的主题变量
99 | indexFileName: "index.html",
100 | outputFilePath,
101 | };
102 |
103 | generateTheme(options)
104 | .then((less) => {
105 | console.log("Theme generated successfully");
106 | })
107 | .catch((error) => {
108 | console.log("Error", error);
109 | });
110 | }
111 |
112 | function reduceMap(listObj, key, value) {
113 | return listObj.reduce((a, c) => {
114 | a[c[key]] = c[value];
115 | return a;
116 | }, {});
117 | }
118 |
119 | function delFile(path) {
120 | if (typeof path === "string") {
121 | if (fs.existsSync(path)) {
122 | fs.unlinkSync(path);
123 | }
124 | return;
125 | }
126 | if (Array.isArray(path)) {
127 | path.forEach((item) => delFile(item));
128 | }
129 | }
130 |
131 | if (showColorSet) {
132 | colorStart();
133 | } else {
134 | delFile([varJsonPath, outputFilePath, defaultPath, darkPath]);
135 | }
136 |
--------------------------------------------------------------------------------
/config/env.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const fs = require("fs");
4 | const path = require("path");
5 | const paths = require("./paths");
6 | const appPackageJson = require(paths.appPackageJson)
7 | const showColorSet = process.env.COLOR === "true";
8 | try {
9 | var varColors = require("../color.json.js");
10 | } catch (error) { }
11 | // Make sure that including paths.js after env.js will read .env variables.
12 | delete require.cache[require.resolve("./paths")];
13 |
14 | const NODE_ENV = process.env.NODE_ENV;
15 | if (!NODE_ENV) {
16 | throw new Error(
17 | "The NODE_ENV environment variable is required but was not specified."
18 | );
19 | }
20 |
21 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
22 | const dotenvFiles = [
23 | `${paths.dotenv}.${NODE_ENV}.local`,
24 | // Don't include `.env.local` for `test` environment
25 | // since normally you expect tests to produce the same
26 | // results for everyone
27 | NODE_ENV !== "test" && `${paths.dotenv}.local`,
28 | `${paths.dotenv}.${NODE_ENV}`,
29 | paths.dotenv,
30 | ].filter(Boolean);
31 |
32 | // Load environment variables from .env* files. Suppress warnings using silent
33 | // if this file is missing. dotenv will never modify any environment variables
34 | // that have already been set. Variable expansion is supported in .env files.
35 | // https://github.com/motdotla/dotenv
36 | // https://github.com/motdotla/dotenv-expand
37 | dotenvFiles.forEach((dotenvFile) => {
38 | if (fs.existsSync(dotenvFile)) {
39 | require("dotenv-expand")(
40 | require("dotenv").config({
41 | path: dotenvFile,
42 | })
43 | );
44 | }
45 | });
46 |
47 | // We support resolving modules according to `NODE_PATH`.
48 | // This lets you use absolute paths in imports inside large monorepos:
49 | // https://github.com/facebook/create-react-app/issues/253.
50 | // It works similar to `NODE_PATH` in Node itself:
51 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
52 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
53 | // Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
54 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
55 | // We also resolve them to make sure all tools using them work consistently.
56 | const appDirectory = fs.realpathSync(process.cwd());
57 | process.env.NODE_PATH = (process.env.NODE_PATH || "")
58 | .split(path.delimiter)
59 | .filter((folder) => folder && !path.isAbsolute(folder))
60 | .map((folder) => path.resolve(appDirectory, folder))
61 | .join(path.delimiter);
62 |
63 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
64 | // injected into the application via DefinePlugin in webpack configuration.
65 | const REACT_APP = /^REACT_APP_/i;
66 |
67 | function getClientEnvironment(publicUrl) {
68 | const raw = Object.keys(process.env)
69 | .filter((key) => REACT_APP.test(key))
70 | .reduce(
71 | (env, key) => {
72 | env[key] = process.env[key];
73 | return env;
74 | },
75 | {
76 | NODE_ENV: process.env.NODE_ENV || "development",
77 | PUBLIC_URL: publicUrl,
78 | WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
79 | WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
80 | WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
81 | FAST_REFRESH: process.env.FAST_REFRESH !== "false",
82 | varColors: varColors || [],
83 | showColorSet,
84 | }
85 | );
86 | const menuStringified = Object.keys(appPackageJson.MENUDATA).reduce((a, key) => {
87 | a[key] = JSON.stringify(appPackageJson.MENUDATA[key])
88 | return a
89 | }, {})
90 | const stringified = {
91 | "process.env": Object.keys(raw).reduce((env, key) => {
92 | env[key] = JSON.stringify(raw[key]);
93 | return env;
94 | }, {}),
95 | ...menuStringified
96 | };
97 |
98 | return { raw, stringified };
99 | }
100 |
101 | module.exports = getClientEnvironment;
102 |
--------------------------------------------------------------------------------
/config/getHttpsConfig.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const crypto = require('crypto');
6 | const chalk = require('react-dev-utils/chalk');
7 | const paths = require('./paths');
8 |
9 | // Ensure the certificate and key provided are valid and if not
10 | // throw an easy to debug error
11 | function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
12 | let encrypted;
13 | try {
14 | // publicEncrypt will throw an error with an invalid cert
15 | encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
16 | } catch (err) {
17 | throw new Error(
18 | `The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
19 | );
20 | }
21 |
22 | try {
23 | // privateDecrypt will throw an error with an invalid key
24 | crypto.privateDecrypt(key, encrypted);
25 | } catch (err) {
26 | throw new Error(
27 | `The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
28 | err.message
29 | }`
30 | );
31 | }
32 | }
33 |
34 | // Read file and throw an error if it doesn't exist
35 | function readEnvFile(file, type) {
36 | if (!fs.existsSync(file)) {
37 | throw new Error(
38 | `You specified ${chalk.cyan(
39 | type
40 | )} in your env, but the file "${chalk.yellow(file)}" can't be found.`
41 | );
42 | }
43 | return fs.readFileSync(file);
44 | }
45 |
46 | // Get the https config
47 | // Return cert files if provided in env, otherwise just true or false
48 | function getHttpsConfig() {
49 | const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
50 | const isHttps = HTTPS === 'true';
51 |
52 | if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
53 | const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
54 | const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
55 | const config = {
56 | cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
57 | key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
58 | };
59 |
60 | validateKeyAndCerts({ ...config, keyFile, crtFile });
61 | return config;
62 | }
63 | return isHttps;
64 | }
65 |
66 | module.exports = getHttpsConfig;
67 |
--------------------------------------------------------------------------------
/config/jest/babelTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const babelJest = require('babel-jest');
4 |
5 | const hasJsxRuntime = (() => {
6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
7 | return false;
8 | }
9 |
10 | try {
11 | require.resolve('react/jsx-runtime');
12 | return true;
13 | } catch (e) {
14 | return false;
15 | }
16 | })();
17 |
18 | module.exports = babelJest.createTransformer({
19 | presets: [
20 | [
21 | require.resolve('babel-preset-react-app'),
22 | {
23 | runtime: hasJsxRuntime ? 'automatic' : 'classic',
24 | },
25 | ],
26 | ],
27 | babelrc: false,
28 | configFile: false,
29 | });
30 |
--------------------------------------------------------------------------------
/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/en/webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const camelcase = require('camelcase');
5 |
6 | // This is a custom Jest transformer turning file imports into filenames.
7 | // http://facebook.github.io/jest/docs/en/webpack.html
8 |
9 | module.exports = {
10 | process(src, filename) {
11 | const assetFilename = JSON.stringify(path.basename(filename));
12 |
13 | if (filename.match(/\.svg$/)) {
14 | // Based on how SVGR generates a component name:
15 | // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
16 | const pascalCaseFilename = camelcase(path.parse(filename).name, {
17 | pascalCase: true,
18 | });
19 | const componentName = `Svg${pascalCaseFilename}`;
20 | return `const React = require('react');
21 | module.exports = {
22 | __esModule: true,
23 | default: ${assetFilename},
24 | ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
25 | return {
26 | $$typeof: Symbol.for('react.element'),
27 | type: 'svg',
28 | ref: ref,
29 | key: null,
30 | props: Object.assign({}, props, {
31 | children: ${assetFilename}
32 | })
33 | };
34 | }),
35 | };`;
36 | }
37 |
38 | return `module.exports = ${assetFilename};`;
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/config/modules.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const paths = require('./paths');
6 | const chalk = require('react-dev-utils/chalk');
7 | const resolve = require('resolve');
8 |
9 | /**
10 | * Get additional module paths based on the baseUrl of a compilerOptions object.
11 | *
12 | * @param {Object} options
13 | */
14 | function getAdditionalModulePaths(options = {}) {
15 | const baseUrl = options.baseUrl;
16 |
17 | if (!baseUrl) {
18 | return '';
19 | }
20 |
21 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
22 |
23 | // We don't need to do anything if `baseUrl` is set to `node_modules`. This is
24 | // the default behavior.
25 | if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
26 | return null;
27 | }
28 |
29 | // Allow the user set the `baseUrl` to `appSrc`.
30 | if (path.relative(paths.appSrc, baseUrlResolved) === '') {
31 | return [paths.appSrc];
32 | }
33 |
34 | // If the path is equal to the root directory we ignore it here.
35 | // We don't want to allow importing from the root directly as source files are
36 | // not transpiled outside of `src`. We do allow importing them with the
37 | // absolute path (e.g. `src/Components/Button.js`) but we set that up with
38 | // an alias.
39 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
40 | return null;
41 | }
42 |
43 | // Otherwise, throw an error.
44 | throw new Error(
45 | chalk.red.bold(
46 | "Your project's `baseUrl` can only be set to `src` or `node_modules`." +
47 | ' Create React App does not support other values at this time.'
48 | )
49 | );
50 | }
51 |
52 | /**
53 | * Get webpack aliases based on the baseUrl of a compilerOptions object.
54 | *
55 | * @param {*} options
56 | */
57 | function getWebpackAliases(options = {}) {
58 | const baseUrl = options.baseUrl;
59 |
60 | if (!baseUrl) {
61 | return {};
62 | }
63 |
64 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
65 |
66 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
67 | return {
68 | src: paths.appSrc,
69 | };
70 | }
71 | }
72 |
73 | /**
74 | * Get jest aliases based on the baseUrl of a compilerOptions object.
75 | *
76 | * @param {*} options
77 | */
78 | function getJestAliases(options = {}) {
79 | const baseUrl = options.baseUrl;
80 |
81 | if (!baseUrl) {
82 | return {};
83 | }
84 |
85 | const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
86 |
87 | if (path.relative(paths.appPath, baseUrlResolved) === '') {
88 | return {
89 | '^src/(.*)$': '/src/$1',
90 | };
91 | }
92 | }
93 |
94 | function getModules() {
95 | // Check if TypeScript is setup
96 | const hasTsConfig = fs.existsSync(paths.appTsConfig);
97 | const hasJsConfig = fs.existsSync(paths.appJsConfig);
98 |
99 | if (hasTsConfig && hasJsConfig) {
100 | throw new Error(
101 | 'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
102 | );
103 | }
104 |
105 | let config;
106 |
107 | // If there's a tsconfig.json we assume it's a
108 | // TypeScript project and set up the config
109 | // based on tsconfig.json
110 | if (hasTsConfig) {
111 | const ts = require(resolve.sync('typescript', {
112 | basedir: paths.appNodeModules,
113 | }));
114 | config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
115 | // Otherwise we'll check if there is jsconfig.json
116 | // for non TS projects.
117 | } else if (hasJsConfig) {
118 | config = require(paths.appJsConfig);
119 | }
120 |
121 | config = config || {};
122 | const options = config.compilerOptions || {};
123 |
124 | const additionalModulePaths = getAdditionalModulePaths(options);
125 |
126 | return {
127 | additionalModulePaths: additionalModulePaths,
128 | webpackAliases: getWebpackAliases(options),
129 | jestAliases: getJestAliases(options),
130 | hasTsConfig,
131 | };
132 | }
133 |
134 | module.exports = getModules();
135 |
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebook/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
13 | // "public path" at which the app is served.
14 | // webpack needs to know it to put the right
109 |
110 | <%}%>
111 |
112 |
124 |