Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

使用指南

npm 地址

1
2
3
4
5
6
7
8
9
# global install
npm i react-client-create -g
# and then run
create-cli create [name]

# or
npm i react-client-create
#then run
npx create-cli create [name]

like this

选择第一个是常见空的脚手架,可以选择 js 或者 ts(ts 还没写完)
选择第二个是 react+antd 的中后台管理模板 详情
选择第二个是 react+typescript+ant-mobile h5 模板(仅提供常见配置) 详情

脚手架搭建

项目源码

webpack 配置贴这里,里面有注释解释了各个 loader 或者插件的作用,也可以参考webpack 优化指南来详细了解其中的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
// 需要通过 cross-env 定义环境变量
const isProduction = process.env.NODE_ENV === "production";

const getStyleLoaders = (preProcessor) => {
return [
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
preProcessor,
].filter(Boolean);
};

module.exports = {
entry: "./src/index.js",
output: {
path: isProduction ? path.resolve(__dirname, "../dist") : undefined,
filename: isProduction
? "static/js/[name].[contenthash:10].js"
: "static/js/[name].js",
chunkFilename: isProduction
? "static/js/[name].[contenthash:10].chunk.js"
: "static/js/[name].chunk.js",
assetModuleFilename: "static/js/[hash:10][ext][query]",
clean: true,
},
module: {
rules: [
{
oneOf: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleLoaders("stylus-loader"),
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
},
{
test: /\.(jsx|js)$/,
include: path.resolve(__dirname, "../src"),
loader: "babel-loader",
options: {
presets: ["react-app"],
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
plugins: [
// "@babel/plugin-transform-runtime", // presets中包含了
!isProduction && "react-refresh/babel",
].filter(Boolean),
},
},
],
},
],
},
plugins: [
new ESLintWebpackPlugin({
extensions: [".js", ".jsx"],
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
isProduction &&
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
!isProduction && new ReactRefreshWebpackPlugin(),
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
toType: "dir",
noErrorOnMissing: true, // 不生成错误
globOptions: {
// 忽略文件
ignore: ["**/index.html"],
},
info: {
// 跳过terser压缩js
minimized: true,
},
},
],
}),
].filter(Boolean),
optimization: {
minimize: isProduction,
// 压缩的操作
minimizer: [
// 压缩css
new CssMinimizerPlugin(),
// 压缩js
new TerserWebpackPlugin(),
// 压缩图片
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
// 代码分割配置
splitChunks: {
chunks: "all",
cacheGroups: {
react: {
test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
name: "chunk-react",
priority: 40,
},
antd: {
test: /[\\/]node_modules[\\/]antd[\\/]/,
name: "chunk-antd",
priority: 30,
},
libs: {
test: /[\\/]node_modules[\\/]/,
name: "chunk-libs",
priority: 20,
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
},
resolve: {
extensions: [".jsx", ".js", ".json"],
},
devServer: {
host: "localhost",
port: 3000,
hot: true,
compress: true,
historyApiFallback: true,
client: {
overlay: {
errors: true,
warnings: false,
},
},
},
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "cheap-module-source-map",
};

脚手架工具

项目源码

大概步骤就是

  1. 创建执行文件,npm link链接到本地 方便调试
  2. 下载 commander,通过一下 api 实现
    • command:自定义执行的命令
    • option:可选参数
    • alias:用于 执行命令的别名
    • description:命令描述
    • action:执行命令后所执行的方法
    • usage:用户使用提示
    • parse:解析命令行参数,注意这个方法一定要放到最后调用
  3. 下载 child_process,子进程,在 process.exec()中可执行 git 命令和 shell 命令
  4. 通过 inquirer 提供可视化选项
  5. 使用 ora,figlet 等等优化细节,美化界面

贴个代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/usr/bin/env node
const program = require("commander");
const { promisify } = require("util");
const figlet = promisify(require("figlet"));
const chalk = require("chalk");
const inquirer = require("inquirer");
const process = require("child_process");
const ora = require("ora");
const spinner = ora("try to get the registry ...");

const getClone = (type, name) => {
let url;
switch (type) {
case "javascript": {
url = "https://github.com/liufashi-Mr/react-cli.git ";
break;
}
case "typescript": {
url = "https://github.com/liufashi-Mr/react-cli.git ";
break;
}
case "2": {
url = "https://github.com/liufashi-Mr/react-antd-admin.git ";
break;
}
case "3": {
url = "https://github.com/liufashi-Mr/h5-react-typescript.git ";
break;
}
}
spinner.start();
process.exec("git clone " + url + name, (error, stdout, stderr) => {
if (error !== null) {
spinner.fail("exec error: " + error);
console.log(stdout);
return;
}
console.log(stdout);
process.exec(
`cd ${name} && rm -rf .git && git init && git add . && git commit -m "init with create-cli"`,
(error, stdout, stderr) => {
if (error !== null) {
spinner.fail("exec error: " + error);
console.log(stdout);
return;
}
console.log(stdout);
spinner.succeed("download successfully!!!");
}
);
});
};
program
.version(require("../package.json").version)
.command("create <name>")
.alias("c")
.action((name) => {
figlet(`react - client`).then((data) => {
console.log(chalk.yellow(data));
inquirer
.prompt([
{
type: "list",
name: "type",
message: "which do you want",
choices: [
"1. only react-cli ( you can user-defined )",
"2. admin template ( with react + ant-design )",
"3. h5 template (with react + ant-mobile )",
],
filter: function (val) {
return val.toLowerCase();
},
},
])
.then(({ type }) => {
const typeNo = type.slice(0, 1);
if (typeNo === "1") {
inquirer
.prompt([
{
type: "list",
name: "lang",
message: "work with javascript or typescript",
choices: ["javascript", "typescript"],
filter: function (val) {
return val.toLowerCase();
},
},
])
.then(({ lang }) => {
if (lang === "javascript") {
getClone(lang, name);
} else {
spinner.fail("还没有写!!!");
}
})
.catch((err) => console.log(err));
} else {
getClone(typeNo, name);
}
})
.catch((error) => {
console.log(error);
});
});
});
program.parse(process.argv);

最后发布到 npm 中npm 地址

评论

填写正确的邮箱更便于接收消息!



本站总访问量为 访客数为