工具函数库 + 自动化新增和导出 | 青训营笔记

134 阅读2分钟

这是我参与「第四届青训营」笔记创作活动的第7天

此篇文章将会介绍前端工具函数库的开发, 这个在B站上可以找到很多, 但本文的重点主要是在自动化新增和导出上

相信自己最初建函数库的时候都会碰到这个问题, 我一次性写了10几个函数, 到最后却要一个一个的暴露出去, 文件少的话还好, 一旦多了, 添加、修改都比较麻烦。

那么本文在后面将会介绍 如何自动化新增和导入, 即我们只用管工具函数的功能, 其余的都用脚本来自动实现, 我们只需一行命令即可

前端工具函数库的架构

这里为了要适合后面的自动化导入,我的目录结构如下

|-- build  存放构建脚本
|-- packages  存放各个函数, 一个文件就是一个功能
    DeBounce.js
    BlobToFile.js
|-- src   存放index.js
    index.js
components.json  存放函数数据

自动导入到 index.js 文件

这个我们要用到 components.jsonbuild/bin/build-entry.js 这两个文件

components.json

存放函数名和对应的文件名, 样例如下

{
  "throttle": "throttle.js",
  "mySetInterval": "setInterval.js",
  "handleLimitTask": "promiseLimit.js",
  "Debounce": "Debounce.js"
}

build/bin/build-entry.js

这里就是 自动化导入的核心功能, 其步骤如下:

    1. 创建 index.jsimport,export 语句的文件模板
    1. 获取并解析 components.json 并把相应数据填入模板中
    1. 写入文件

这里面用到了几个工具包

  • json-templater 字符串模板库
  • uppercamelcase 将字符串转为大驼峰形式

每一步的详细解释看代码

  1. 创建 index.jsimport,export 语句的文件模板
  • output_path: 最后输出的路径, 为 src/index.js
  • IMPORT_TEMPLATE: import 语句模板
    • name: 函数名
    • package: 函数文件的路径,如 throttle.js
  • MAIN_TEMPLATE: 文件模板
    • include: import 语句列表
    • version: 版本号
    • list: export 列表
// 输出路径
var OUTPUT_PATH = path.join(__dirname, '../../src/index.js');
// import语句模板, name就是大驼峰形, package连字符形式
// 
var IMPORT_TEMPLATE = "import {{name}} from '../packages/{{package}}';";
// 文件模板
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */

{{include}}

export default {
  version: '{{version}}',
{{list}}
};
`;
  1. 获取 components.json
let Components = require('../../components.json');
let fs = require('fs');
// 字符串模板库
var render = require('json-templater/string');
// 连字符形式的字符串转换为大驼峰形式
var uppercamelcase = require('uppercamelcase');
var path = require('path');
var endOfLine = require('os').EOL;

// 包名组成的数组
var ComponentNames = Object.keys(Components);

// import语句组成的数组
var includeComponentTemplate = [];

// export 导出的数组, 模板中的List
var listTemplate = [];

ComponentNames.forEach((name) => {
  // 将连字符形式的包名转换为大驼峰
  var componentName = uppercamelcase(name);
  
  // 替换掉name和package, 生成import语句
  includeComponentTemplate.push(
    render(IMPORT_TEMPLATE, {
      name: componentName,
      package: Components[name],
    }),
  );
  listTemplate.push(`  ${componentName}`);
});

var template = render(MAIN_TEMPLATE, {
  // import语句
  include: includeComponentTemplate.join(endOfLine),
  // 版本号
  version: process.env.VERSION || require('../../package.json').version,
  // 导出列表
  list: listTemplate.join(',' + endOfLine),
});
// 写文件
fs.writeFileSync(OUTPUT_PATH, template);
console.log('[build entry] DONE:', OUTPUT_PATH);

自动新增一个函数

以上已经实现了自动导入到index.js, 但是如果就到这里结束的话, 那还是得要手动改 components.json 文件, 所以这里我就又加了个自动新增的功能, 它会自动在 packages里新建函数文件,和在components.json 添加一条记录。

原理: 通过 node xxx 来实现的, 用 process.argv 获取到需要新建的函数名后, 在packages里新建函数文件,和在components.json 添加一条记录。具体代码如下

console.log();
process.on('exit', () => {
  console.log();
});

if (!process.argv[2]) {
  console.error('[组件名]必填 - Please enter new component name');
  process.exit(1);
}

const path = require('path');
const fs = require('fs');
const fileSave = require('file-save');
const uppercamelcase = require('uppercamelcase');

// 组件名
const ComponentName = uppercamelcase(process.argv[2]); // 驼峰式

// 组件存放路径
const PackagePath = path.resolve(__dirname, '../../packages');

// 添加到 components.json
const componentsFile = require('../../components.json');
if (componentsFile[ComponentName]) {
  console.error(`${ComponentName} 已存在.`);
  process.exit(1);
}
// 添加到 components.json中
componentsFile[ComponentName] = `${ComponentName}.js`;
// 写入文件
fileSave(path.join(__dirname, '../../components.json'))
  .write(JSON.stringify(componentsFile, null, '  '), 'utf8')
  .end('\n');

// 创建 package
// 这里主要是加入
let content = `export default function ${ComponentName} () {}`;
fileSave(path.join(PackagePath, `${ComponentName}.js`))
  .write(content, 'utf8')
  .end('\n');

console.log('DONE!');

总结

以上就是对自动新增和导入的一个简单实现, 这是最基本的原理, 其实现参考的 elementui 源码。

且它不仅可以用在工具函数库, 像UI组件库, 低代码的物料管理都可以这样实现, 只要设计好项目架构, 很多事都可以用一行命令实现。