Skip to content
On this page

CLI 介绍

React@18-hooks 风格的 typescript 项目,构建工具采用了 vite

配备了标准的大厂规范的 prettier + eslint + stylelint

路由采用 react-router-dom@6

工具库采用 yjr-utils

状态管理采用 mobx

下载安装

cmd
> npm i yjr-cli -g

验证下载是否成功

cmd
> yjrcli -v

如何使用

创建项目

cmd
> yjrcli create-app myApp

启动项目查看

cmd
> cd myApp
> npm i --no-fund
> npm run dev

全局状态管理

store.ts

具体使用可参考 mobx 文档 以及 mobx-react

js
import { observable, configure } from "mobx";
// 将 proxy 包装过的数据转换为 js 数据
export { toJS } from "mobx";
/**
 * 用到全局状态的组件需要用 observer 包一下
 * 如果上游组件能带你上一起更新则不需要用 observer 包裹
 */
export { observer } from "mobx-react-lite";

configure({
  enforceActions: "never",
});

// 在此处定义公共状态数据
const globalData = {
  count: 0,
};

// 后续通过 $store 来访问全局状态
export const $store = observable(globalData);

路由

RouteViews.tsx

路由配置文件,可随意更改位置,默认为 BrowserRouter(history 模式)

可在 main.ts 中更改为 HashRouter(hash 模式)

js
import ReactDOM from 'react-dom/client';
import App from './App';
import { HashRouter } from 'react-router-dom';
import './main.scss';

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <HashRouter>
    <App />
  </HashRouter>,
);

具体用法可参考 react-router-dom 文档

文件中示例做了简单的配置和路由懒加载示范

js
import { Route, Routes } from "react-router-dom";
import { lazy, Suspense } from "react";

const Home = lazy(async () => await import("@cpt/Home"));
const Error = (): React.ReactElement => <div className="notFound">404</div>;

export default function RouteViews(): React.ReactElement {
  return (
    <>
      <Routes>
        <Route
          path="/"
          element={
            <Suspense>
              <Home></Home>
            </Suspense>
          }
        ></Route>
        <Route path="*" element={<Error></Error>}></Route>
      </Routes>
    </>
  );
}

package.json 介绍

版本号中 * 意为始终使用最新版本

json
{
  "scripts": {
    // 开发环境  -m注入环境 -c指定配置文件
    "dev": "vite -m=dev -c=cli.config.ts",
    // 打包 -m注入环境 -c指定配置文件
    "build": "npm run lintFix && vite build -m=prod -c=cli.config.ts",
    // 预览,运行前确保已有dist目录
    "preview": "vite preview -c=cli.config.ts",
    // 自动修复和检查项目中出现的lint错误
    "lintFix": "tsc && stylelint \"**/*.scss\" --fix && eslint --fix src"
  },
  "dependencies": {
    "mobx": "^6.9.0",
    "mobx-react-lite": "^3.4.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.14.0",
    "yjr-utils": "*"
  },
  "devDependencies": {
    // 开发环境依赖包,里面包含了开发环境下所需要的 31 个依赖包
    "yjrcli-env": "*"
  }
}

cli.config.ts 介绍

脚手架配置 具体配置可参考 vite 官网 已预设好了常用的配置

打包产物默认兼容 overrideBrowserslist 中声明的浏览器类型版本

根据需要可自行配置 代理 移动端适配 手动分包等

js
export default defineConfig({
  // 打包后资源路径
  base: "./",
  server: {
    // 控制台暴露ip
    host: "0.0.0.0",
    // 启动后自动打开浏览器
    open: true,
    // 端口号
    port: 4399,
  },
  // 环境变量命名需要以 yjr_ 开头
  envPrefix: "yjr",
  css: {
    postcss: {
      plugins: [
        // postcss预设
        postcssPresetEnv(),
        // 自动加css前缀
        autoprefixer({
          overrideBrowserslist,
        }),
      ],
    },
    // 默认导入全局scss文件,无需引入
    preprocessorOptions: {
      scss: {
        additionalData: `@import '@/global.scss';`,
      },
    },
    // 开发环境下开启css-sourcemap
    devSourcemap: true,
  },
  resolve: {
    // 路径别名
    alias: {
      "@": resolve(__dirname, "./src"),
      "@cpt": resolve(__dirname, "./src/components"),
      "@store": resolve(__dirname, "./src/store.ts"),
    },
  },
  // 插件
  plugins: [
    // 旧浏览器支持
    legacy({
      targets: overrideBrowserslist,
    }),
    pluginReact(),
    vitePluginEslint({
      failOnError: false,
    }),
  ],
  build: {
    minify: "terser",
    terserOptions: {
      // 打包会移除代码中的日志和debug
      compress: {
        drop_console: true,
        drop_debugger: true,
      },
    },
    // 每个chunk不能超过244kb
    chunkSizeWarningLimit: 244,
    // rollup配置
    rollupOptions: {
      output: {
        // 手动分包
        manualChunks(id) {
          if (id.includes("node_modules")) {
            return id.split("node_modules/")[1].split("/")[0];
          }
        },
        // 入口文件改名
        entryFileNames: "js/entry.[hash].js",
        // chunk改名
        chunkFileNames: "js/chunks/[name].[hash].js",
        // asset改名
        assetFileNames: "[ext]/[name].[hash].[ext]",
      },
    },
  },
});

.eslintrc.cjs 介绍

配置来自 yjrcli-env,可根据需求自行修改、覆盖、替换 rules 中的配置

js
const { eslintConfig } = require("yjrcli-env");
module.exports = eslintConfig;

自定义规则示范

开启规则 "arrow-body-style"

js
const { eslintConfig } = require("yjrcli-env");
eslintConfig.rules["arrow-body-style"] = "error";
module.exports = eslintConfig;

.stylelintrc.cjs 介绍

配置来自 yjrcli-env,可根据需求自行修改、覆盖、替换 rules 中的配置

js
const { stylelintConfig } = require("yjrcli-env");
module.exports = stylelintConfig;

自定义规则示范

修改规则 "selector-max-id" 的值为 0

js
const { stylelintConfig } = require("yjrcli-env");
stylelintConfig.rules["selector-max-id"] = 0;
module.exports = stylelintConfig;

.env 文件

.dev 为开发环境 .prod 为线上环境 可根据需求添加其他环境 如灰度、日常、预发等

脚本也要同步环境,比如你配置了预发环境 pre, 那么脚本中的-m=dev 就要替换成-m=pre,并再配置一份 .env.pre 的文件

json
{
  "scripts": {
    // 新增脚本
    "pre": "vite -m=pre -c=cli.config.ts",
    "build:pre": "npm run lintFix && vite build -m=pre -c=cli.config.ts"
  }
}

新增的变量要在 src/env.d.ts 中声明 且变量命名默认以 yjr_开头,可在 cli.config 中修改

ts
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly yjr_environment: string;
  // 新增环境变量 yjr_demo
  readonly yjr_demo: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}