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

新建一个组件库模板

发布一个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/**']
})
相关推荐
2301_1472583691 分钟前
7月1日作业
java·前端·算法
汪子熙2 分钟前
Angular 应用中手动调用 subscribe 方法的时机与实践探讨
前端
csdn_aspnet10 分钟前
在 React 中使用 WebSockets 构建实时聊天应用程序
javascript·react.js·node.js
MiyueFE34 分钟前
14 个逻辑驱动的 UI 设计技巧,助您改善任何界面
前端·设计
啃火龙果的兔子38 分钟前
前端单元测试覆盖率工具有哪些,分别有什么优缺点
前端·单元测试
「、皓子~1 小时前
后台管理系统的诞生 - 利用AI 1天完成整个后台管理系统的微服务后端+前端
前端·人工智能·微服务·小程序·go·ai编程·ai写作
就改了1 小时前
Ajax——在OA系统提升性能的局部刷新
前端·javascript·ajax
凌冰_1 小时前
Ajax 入门
前端·javascript·ajax
京东零售技术1 小时前
京东小程序JS API仓颉改造实践
前端
老A技术联盟2 小时前
从小白入门,基于Cursor开发一个前端小程序之Cursor 编程实践与案例分析
前端·小程序