搭建公司前端脚手架

前言

公司的项目使用的都是 react + ts + mobx + antd 的技术栈,每次搞新组件或者重构组件的时候都要重复新建文件夹,比较麻烦,而且每个人的代码风格、习惯也有差异。所以搭建一个快速创建业务组件的脚手架方便开发。

初始化

项目根目录运行命令

js 复制代码
npm init -y

然后安装依赖包

js 复制代码
npm i await-to-js fs-extra inquirer@7.0.4

然后在 package.json 里面配置 添加 bin 节点 txCli 命令,配置脚手架的入口文件为根目录下 index.js

js 复制代码
//package.json
{
  "bin": {
    "txCli": "./index.js"
  },
}

创建项目目录如下

js 复制代码
  |-- 根目录
  |-- template                      //模板
      |--web  //web端模块
           |--组件模板1              
           |--组件模板2
           |--index.js              //web端模块的入口文件
      |--h5   //h5模块
           |--组件模板1
           |--组件模板2
           |--index.js              //h5端模块的入口文件
      |--wx   //微信小程序模块
           |--组件模板1
           |--组件模板2
           |--index.js              //微信小程序的入口文件
  |-- index.js                      //脚手架入口文件
  |-- tool.js                       //工具函数模块
  |-- package.json

组件模板的目录结构如下

js 复制代码
|--组件模板
   |--dom                          //写好的组件模板配置
   |--index.js                     //组件模板配置的入口文件

脚手架编写

以web端组件模块为例子

脚手架入口文件

在根目录下的 index.js 文件,顶部写上 #!/usr/bin/env node

js 复制代码
#!/usr/bin/env node

const args = process.argv.slice(2);
// type 可以拿到脚手架命令后的参数 比如 txCli --webComp 拿到的就是 --webComp
const type = args[0];
const { createWeb } = require("./template/web");

switch (type) {
  case "--webComp":
    {
      createWeb();
    }
    break;
  default: {
    console.log("无效操作参数");
  }
}

当我们运行 txCli --webComp 命令的时候,就会走到 createWeb() 里面

模块入口文件

在 template/web/index.js 中,这是创建 web端组件模块的入口文件

js 复制代码
const inquirer = require('inquirer');
const { to } = require("await-to-js");
const { createModal } = require("./Modal/index");

async function createWeb() {
  const [err, res] = await to(
    inquirer.prompt([
      {
        type: "list",
        name: "type",
        message: "请选择web组件模块",
        choices: [{ value: 1, name: "1-弹窗" }],
        default: 0,
      },
    ])
  );

  switch (res.type) {
    case 1:
      {
        createModal();
      }
      break;
  }
}

module.exports = { createWeb };

因为 web 端会有很多业务组件,这里拿创建一个 Modal 为例子,当我们选择 1-弹窗的时候,就会走到 createModal() 里面

组件模板配置

首先在 template/web/modal/dom 里面,写好组件的模板

比如这儿咱们用的 react + ts + mobx 来搞组件模板

比如 web 端 Modal 组件的编写如下:

tsx 复制代码
import { observer, useSyncProps } from "@quarkunlimit/qu-mobx";
import { Modal } from "antd";
import { forwardRef, useImperativeHandle } from "react";
import { IXXXProps, IXXXRef } from "./interface";
import { Provider, useStore } from "./store/RootStore";

const XXX = observer(
  forwardRef<IXXXRef, IXXXProps>(function XXX_(props, ref) {
    const root = useStore();
    useSyncProps(root, Object.keys(props), props);
    const { logic, PropsStore } = root;

    useImperativeHandle(ref, () => {
      return {
        openModal: logic.openModal,
        closeModal: logic.closeModal,
      };
    });

    return (
      <Modal
        open={logic.open}
        width={800}
        destroyOnClose
        onCancel={logic.closeModal}
        {
          ...PropsStore.props
        }
      >
        XXX
      </Modal>
    );
  })
);

export default observer(
  forwardRef<IXXXRef, IXXXProps>(function XXXPage(props, ref) {
    return (
      <Provider>
        <XXX {...props} ref={ref} />
      </Provider>
    );
  })
);

在 template/web/Modal/index.js 中,就是 web端 Modal 组件的入口创建文件了

js 复制代码
const { to } = require("await-to-js");
const { existsSync } = require("fs");
const fse = require("fs-extra");
const inquirer = require("inquirer");
const path = require("path");
const { replaceFileInfo } = require("../../../tool");

async function createModal() {
  const [err, res] = await to(
    inquirer.prompt([
      {
        type: "input",
        name: "page",
        message: "请输入页面文件夹名(首字母大写e.g:EditModal)",
      },
    ])
  );

  const Page = res.page?.trim?.();
  if (!Page) {
    console.log("请输入正确的页面名");
    return;
  }
  const workPath = process.cwd();
  const dirPath = path.join(workPath, Page);
  if (existsSync(dirPath)) {
    console.log("该页面已存在");
    return;
  }
  console.log("组件路径:", workPath);
  console.log("组件名称:", Page);
  try {
    await fse.copy(path.resolve(__dirname, "./dom"), dirPath);
  } catch (error) {
    console.log("发生了异常:");
    console.log(error);
    return;
  }
  // 替换页面名称
  replaceFileInfo(path.join(dirPath, "index.tsx"), "XXX", Page);
  // 替换interface名称
  replaceFileInfo(path.join(dirPath, "interface.ts"), "XXX", Page);
  // 替换store相关内容
  replaceFileInfo(path.join(dirPath, "store/RootStore/index.ts"), "XXX", Page);
  replaceFileInfo(
    path.join(dirPath, "store/RootStore/interface.ts"),
    "XXX",
    Page
  );
  console.log("web组件创建完成");
}

module.exports = { createModal };

上面做的事情就是

  • 用户输入这个组件的名称
  • 判断当前路径下有没有重复组件
  • 复制模板到指定路径下
  • 然后把模板里面的 XXX 替换成输入的组件名称

这里的 replaceFileInfo 就是一个文件内容替换的方法,在根目录下的 tool.js 中

js 复制代码
// tool.js
const fs = require("fs");

const fileConfig = {
  encoding: "utf-8",
};
const replaceFileInfo = (filePath, oldInfo, newInfo) => {
  //读取指定目录的文件内容
  let content = fs.readFileSync(filePath, fileConfig);
  //替换内容
  content = content.replaceAll(oldInfo, newInfo);
  //覆盖旧内容
  fs.writeFileSync(filePath, content, fileConfig);
};

module.exports = {
  replaceFileInfo,
};

脚手架实践

写好脚手架后,把代码推到 gitlab,然后本地执行 npm link

然后在项目里面执行命令即可

这样就可以去配置不同端的各种业务组件了

相关推荐
_OP_CHEN2 分钟前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒4 分钟前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
JMchen1235 分钟前
现代Android图像处理管道:从CameraX到OpenGL的60fps实时滤镜架构
android·图像处理·架构·kotlin·android studio·opengl·camerax
PHP武器库6 分钟前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_1800790524715 分钟前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
晓晓莺歌16 分钟前
vue3某一个路由切换,导致所有路由页面均变成空白页
前端·vue.js
Up九五小庞1 小时前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源
qq_177767371 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头88212 小时前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
Jing_jing_X3 小时前
CPU 架构:x86、x64、ARM 到底是什么?为什么程序不能通用?
arm开发·架构·cpu