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

新建一个组件库模板

发布一个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/**']
})
相关推荐
啦啦91188612 小时前
【版本更新】Edge 浏览器 v142.0.3595.94 绿色增强版+官方安装包
前端·edge
蚂蚁集团数据体验技术12 小时前
一个可以补充 Mermaid 的可视化组件库 Infographic
前端·javascript·llm
LQW_home12 小时前
前端展示 接受springboot Flux数据demo
前端·css·css3
q***d17312 小时前
前端增强现实案例
前端·ar
IT_陈寒12 小时前
Vite 3.0 重磅升级:5个你必须掌握的优化技巧和实战应用
前端·人工智能·后端
JarvanMo12 小时前
Flutter 3.38 + Firebase:2025 年开发者必看的新变化
前端
Lethehong13 小时前
简历优化大师:基于React与AI技术的智能简历优化系统开发实践
前端·人工智能·react.js·kimi k2·蓝耘元生代·蓝耘maas
华仔啊13 小时前
还在用 WebSocket 做实时通信?SSE 可能更简单
前端·javascript
鹏北海13 小时前
多标签页登录状态同步:一个简单而有效的解决方案
前端·面试·架构
_AaronWong13 小时前
基于 Vue 3 的屏幕音频捕获实现:从原理到实践
前端·vue.js·音视频开发