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

新建一个组件库模板

发布一个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/**']
})
相关推荐
baozongwi7 分钟前
ctfshow web入门 nodejs web334--web337
web安全·node.js
托尼沙滩裤34 分钟前
【js面试题】js的数据结构
前端·javascript·数据结构
不熬夜的臭宝39 分钟前
每天10个vue面试题(一)
前端·vue.js·面试
不如喫茶去1 小时前
VUE自定义新增、复制、删除dom元素
前端·javascript·vue.js
长而不宰1 小时前
vue3+electron项目搭建,遇到的坑
前端·vue.js·electron
阿垚啊2 小时前
vue事件参数
前端·javascript·vue.js
过去式的美好3 小时前
vue前端通过sessionStorage缓存字典
前端·vue.js·缓存
Simaoya3 小时前
vue判断元素滚动到底部后加载更多
前端·javascript·vue.js
头顶一只喵喵3 小时前
Vue基础知识:Vue3.3出现的defineOptions,如何使用,解决了什么问题?
前端·javascript·vue.js·vue3
掘金安东尼3 小时前
上周前端发生哪些新鲜事儿?#370
前端·javascript·面试