脚手架安装自定义模板和组件模板功能实现

新建一个组件库模板

发布一个npm包

js 复制代码
git clone https://github.com/imooc-lego/lego-components.git

cd lego-components/

//用cnpm会报错
npm i

// 启动项目
npm run serve

将lego-components放至mj-cli-dev-template/mj-cli-dev-lego-components/template目录下;

修改tempalte文件夹里的package.json为ejs模板;

template/package.json 复制代码
{
  "name": "<%= className %>",
  "version": "<%= version %>"
}

template文件夹同级的package.json修改:

js 复制代码
{
  "name": "mj-cli-dev-lego-compoments",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

接着npm publish这个mj-cli-dev-lego-compoments包;

mongodb插入一条数据

我这里是用命令插入数据的;增加一个tag的标志,分为project和component;还可以增加一个ignore字段,是用来ejs模板转换时忽略某些文件;

js 复制代码
db.project.insert({name: '乐高组件库模版', 
    npmName: 'mj-cli-dev-lego-compoments',
    version: '1.0.0',
    type: 'normal',
    tag: ['component'],
    installCommand: 'npm install --registry=https://registry.npm.taobao.org',
    startCommand: 'npm run serve',
    ignore: '**/public/**'
})

项目和组件模版数据隔离

根据项目和组件的选择对数据做筛选;

js 复制代码
// getProjectInfo方法
this.template = this.template.filter((template) =>
    template.tag.includes(type)
);

从接口获取ignore进行拼装;

js 复制代码
//installNormalTemplate方法
const opts = {
    ignore: ["**/node_modules/**"],
};
if (this.templateInfo.ignore) {
    opts.ignore = opts.ignore.concat(this.templateInfo.ignore);
}

获取组件信息功能

组件和项目的逻辑基本一致;组件比项目多一个输入描述信息的命令;

先来修改一下mj-cli-dev-lego-components/template/package.json文件中;

js 复制代码
"description": "<%= description %>"

// 删除files,它会限制上传的文件数量

然后发布mj-cli-dev-lego-components@1.0.1版本;

安装模板时会报错,如下图:

这里我们可以在ignore中去忽略png格式的文件,修改一下mongodb中的数据;

js 复制代码
db.project.update({'name':'乐高组件库模版'},{$set:{'ignore': ['**/public/**', '**.png']}})

此时已经成功启动项目了;

自定义模板开发

在mj-cli-dev-template/mj-cli-dev-template-custom-vue3目录下复制一份mj-cli-dev-template-vue3;可以去本地install的目录地址下本地调试mj-cli-dev-template-custom-vue3模板的代码;最后将调试成功的代码发布npm;

mj-cli-dev-template-custom-vue3/package.json 复制代码
{
  "name": "mj-cli-dev-template-custom-vue3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

创建mj-cli-dev-template-custom-vue3/index.js文件;

mj-cli-dev-template-custom-vue3/index.js 复制代码
const fse = require("fs-extra");
const inquirer = require("inquirer");
const ejs = require("ejs");

async function ejsRender(options) {
  const dir = options.targetPath;
  const { projectInfo } = options;
  return new Promise((resolve, reject) => {
    require("glob")(
      "**",
      {
        cwd: dir,
        ignore: options.ignore,
        nodir: true,
      },
      (err, files) => {
        if (err) {
          reject(err);
        }
        Promise.all(
          files.map((file) => {
            const filePath = path.join(dir, file);

            return new Promise((resolve1, reject1) => {
              ejs.renderFile(filePath, projectInfo, {}, (err, result) => {
                if (err) {
                  reject1(err);
                } else {
                  // ejs模板转换不成功,渲染结果需重新写入
                  fse.writeFileSync(filePath, result);
                  resolve1(result);
                }
              });
            });
          })
        )
          .then(() => {
            resolve();
          })
          .catch((err) => {
            reject(err);
          });
      }
    );
  });
}

async function install(options) {
  const projectPrompt = [];
  const descriptionPrompt = {
    type: "input",
    name: "componentDescription",
    message: "请输入项目描述信息",
    default: "",
    validate: function (v) {
      const done = this.async();

      setTimeout(function () {
        if (!v) {
          done("请输入项目描述信息");
          return;
        } else {
          done(null, true);
        }
      }, 0);
    },
  };
  projectPrompt.push(descriptionPrompt);
  const obj = await inquirer.prompt(projectPrompt);
  options.projectInfo.description = obj.componentDescription;
  try {
    //拷贝模版代码至当前目录
    const { sourcePath, targetPath } = options;

    // 确保目录存在,不存在会创建一个
    fse.ensureDirSync(sourcePath);
    fse.ensureDirSync(targetPath);
    fse.copySync(sourcePath, targetPath);
    const opts = {
      ignore: ["**/node_modules/**"],
      targetPath,
      projectInfo: options.projectInfo,
    };
    if (options.templateInfo.ignore) {
      opts.ignore = opts.ignore.concat(options.templateInfo.ignore);
    }
    await ejsRender(opts);
  } catch (e) {
    throw e;
  }
}
module.exports = install;
mj-cli-dev-template-custom-vue3/template/package.json 复制代码
{
  "name": "<%= className %>",
  "version": "<%= version %>",
  "description": "<%= description %>",

npm publish新的包mj-cli-dev-template-custom-vue3;

mongodb中插入一条数据:

js 复制代码
db.project.insert({name: 'vue3自定义模板', 
    npmName: 'mj-cli-dev-template-custom-vue3',
    version: '1.0.0',
    type: 'custom',
    tag: ['project'],
    installCommand: 'cnpm install',
    startCommand: 'npm run serve',
    ignore: ['**/public/**']
})
相关推荐
子兮曰4 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰4 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万4 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝4 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋5 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁5 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95275 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大5 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师5 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学5 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端