资讯专栏INFORMATION COLUMN

发布一个自己的npm包之wxh-tools

smartlion / 1243人阅读

摘要:工作中经常重复写一些方法整理起来托管到仓库中搭建一个包每次使用时按需下载打包成一个文件方便使用项目地址地址工具截图项目目录执行包命令所有下方法列表由创建打包时使用的配置打包目录临时目录,用于存放从下载到本地的资源存放

工作中经常重复写一些方法, 整理起来托管到 GitHub仓库中 ,
搭建一个npm包, 每次使用时, 按需下载打包成一个文件, 方便使用;

项目地址
NPM地址: https://www.npmjs.com/package/wxh-tools;

GITHUB: https://github.com/Wxh16144/wxh-tools;

工具截图:

项目目录

bin

www // 执行包命令

config

methods_list.json // 所有/src/tools/下方法列表, 由create_methods_list.js 创建

webpack.config.js // 打包时使用的webpack配置

dist // 打包目录

reoisutiry // 临时目录,用于存放从git下载到本地的资源

src

tools // 存放平常使用的方法(全部)

utils

create_file_by_user_select.js // 根据用户选择的方法,创建文件夹

get_json_file.js // 读取json文件内容并序列化

read_dir_file.js // 读取某一个目录下的所有文件

webpack_build.js // webpack配置

get.js // 从git上下载文件

index.js // 获取用户选择config

main.js // 入口文件

.babelrc

create_methods_list.js // 读取src/tools/所有方法并生成文件

安装依赖
  npm install @babel/cli@7.5.5  @babel/core@7.5.5  @babel/preset-env@7.5.5  babel-loader@8.0.0-beta.0  core-js@3.1.4  download@7.1.0  inquirer@6.5.0  ora@3.4.0  rimraf@2.6.3  shelljs@0.8.3  webpack@4.37.0  webpack-cli@3.3.6 --save
列举出来的npm 语句太长, 为了偷懒我也使用了 src/utils/get_json_file.js 方法;

Demo:

  const method = require("./src/utils/get_json_file");
  const json_file = method("./package.json");
  const dep = json_file.dependencies;
  const res = Object.keys(dep).reduce((str, key) => {
    return `${str}  ${key}@${(dep[key]).slice(1)}`
  }, "")
  console.log(res);
  // @babel/cli@7.5.5  @babel/core@7.5.5  @babel/preset-env@7.5.5  babel-loader@8.0.0-beta.0  core-js@3.1.4  download@7.1.0  inquirer@6.5.0  ora@3.4.0  rimraf@2.6.3  shelljs@0.8.3  webpack@4.37.0  webpack-cli@3.3.6
工具封装

get_json_file.js

读取json文件, 并且序列化
  const fs = require("fs");
  /**
  *读取*.JSON文件,并序列化返回
  *
  * @param {*} filepath 文件地址
  * @returns 文件内容
  */
  module.exports = (filepath) => {
    if (!filepath) return "";
    const _Json = fs.readFileSync(filepath);
    return JSON.parse(_Json);
  };

read_dir_file.js

读取某一个目录下的所有文件(不包括文件夹, 不进行递归)
  const path = require("path");
  const path_join = path.join;
  const fs = require("fs");

  /**
  *获取目录下的所有文件(不包括文件夹)
  *
  * @param {*} [dir=path_join(__dirname)] 目录
  * @param {*} [reg=/./] 正则表达死
  * @returns 文件数组
  */
  module.exports = (dir = path_join(__dirname), reg = /./) => {
    // 读取所有的文件
    let files = fs.readdirSync(dir);
    return files.reduce((arr, item) => {
      // 获取文件路径
      let fPath = path_join(dir, item);
      // 读取
      let stat = fs.statSync(fPath);
      // 判断是否为文件
      let isFile = stat.isFile();
      // 过滤正则表达式条件
      return isFile && reg.test(item) ? [...arr, item] : arr
    }, []);
  };

get.js

从远程github仓库下载文件
使用download下载文件包; download npm 地址;
const path = require("path");
const path_join = path.join;
const fs = require("fs");
const download = require("download");

/**
 *从远程github仓库下载文件
 *
 * @param {array} files 文件名
 * @param {string} [savePath=path_join(__dirname, "../repository")] 文件下载保存地址
 * @returns Promise
 */
module.exports = (files, savePath = path_join(__dirname, "../repository")) => {
  const URL = "https://raw.githubusercontent.com/Wxh16144/wxh-tools/master/";
  return Promise.all((Array.isArray(files) ? files : [])
    .map(file_name => download(URL + file_name, savePath)));
};
工具准备完成, 开始构建CONFIG(index.js)
使用inquirer控制台交互包; inquirer npm 地址;
使用ora加载动画包; ora npm 地址;

引入所需模块

// 路径处理
const path = require("path");
const path_join = path.join;

// 控制台交互
const inquirer = require("inquirer");
const prompt = inquirer.createPromptModule();
// 加载动画
const ora = require("ora");

// 获取下载文件
const download_methods_list = require("./get");
控制台交互, 一个Promise数组;
// 询问需要添加的方法
const Ask_the_task = [
  // 询问用户需要使用那些方法
  async () => {
    // 添加动画
    const spinner = ora("正在获取所有方法列表...").start();
    // 下载所有方法列表
    const res = await download_methods_list(["config/methods_list.json"]);
    // 读取方法列表
    const methods_list = require("./utils/get_json_file")(path_join(__dirname, "../repository/methods_list.json"));
    // 停止动画
    spinner.stop();
    const ALL_TOOLS_SERVER = (methods_list.methods_list || []).map(filename => {
      return filename.replace(/.js$/, "");
    });
    // 创建问题
    return prompt({
      type: "checkbox",
      name: "tools_key",
      message: "请选择您所需要的方法",
      default: [],
      choices: ALL_TOOLS_SERVER
    })
  },
  // 询问用户保存名字
  () => prompt({
    type: "input",
    name: "save_file_name",
    message: "保存文件名",
    default: "utils.js",
  }),
  // 询问用户是否需要打包
  () => prompt({
    type: "confirm",
    name: "is_build",
    message: "是否需要使用webpack打包",
    default: true
  }),
];
从上往下询问问题
并合并用户选择的CONFIG, 导出执行方法
/**
 *循环提出询问
 *
 * @returns 用户配置
 */
const task = async () => {
  const config = {};
  for (const fn of Ask_the_task) {
    const P = fn();
    const res = await P;
    Object.assign(config, res)
  }
  return config;
};

// 导出提问方法
module.exports = task;
根据用户选择下载对应方法 (main.js)
使用rimraf删除文件包; rimraf npm 地址;

加载模块

const path = require("path");
const path_join = path.join;
const fs = require("fs");

// 删除文件
const rimraf = require("rimraf");

// 获取下载文件
const download_methods_list = require("./get");

// 加载动画
const ora = require("ora");

// webpack 打包
const webpack_build_function = require("./utils/webpack_build");

// 交互问题
const task = require("./index");
询问用户, 下载方法到本地, 合并方法文件, 使用webpack 打包
// 所有问题
const task = require("./index");
(async function () {
  const CONFIG = await task();
  // 获取用户配置
  const { tools_key = [], is_build = true } = CONFIG;
  // 临时目录
  const DIRECTORY = path_join(__dirname, "../temporary/");
  rimraf.sync(DIRECTORY);
  // 添加下载动画
  const download_spinner = ora("正在下载所选方法数据...").start();
  // 根据所选方法收集
  // 下载所有方法列表
  const load_select_methods = await download_methods_list(
    tools_key.map(key => `src/tools/${key}.js`),
    path_join(__dirname, "../temporary")
  );
  // 下载完成
  download_spinner.succeed("所需方法下载完成");
  // 添加创建文件动画
  const create_file_spinner = ora("创建并生成文件中...").start();
  const create_file_by_user_select = require("./utils/create_file_by_user_select");
  const create_file = await create_file_by_user_select(CONFIG);
  create_file_spinner.succeed("创建完成");

  // 添加打包动画
  const build_spinner = ora("处理文件中...").start();
  const build_res = await webpack_build_function(CONFIG);
  build_spinner.succeed(`处理成功,地址:${build_res}`);
}());
创建合并文件(create_file_by_user_select.js)
处理 github 下载到本地 temporary 目录的方法;
打包好的文件会在 window 有一个全局的方法集为 WT
const path = require("path");
const path_join = path.join;
const fs = require("fs");

/**
 *创建合并文件
 *
 * @param {*} CONFIG 用户输入配置
 */
module.exports = async CONFIG => {
  // 获取临时目录路径
  const DIRECTORY = path_join(__dirname, "../../temporary/");
  const { tools_key = [] } = CONFIG;
  let javascript = "";
  tools_key.forEach(fileN => {
    // 逐个导入方法
    javascript += `import ${fileN}  from "./${fileN}.js";
    `
  });
  const myexport = tools_key.map(String).join(",");
  // 绑到window上
  // 导出方法
  javascript += `
  window.WT = { ${myexport} };
  export { ${myexport} };`
  // 写到临时目录
  fs.writeFileSync(path_join(DIRECTORY, "utils.js"), javascript);
}
使用webpack打包(webpack_build.js)
传入用户CONFIG配置; 通过 --build 标识是否使用@babel/preset-env打包;
使用shell下载文件包; shell npm 地址;
这里有个方法 process.cwd() 是获取用户执行方法的目录; 使用这个作为webpack打包出口;

执行webpack 打包, 使用配置config/webpack.config.js文件

const path = require("path");
const path_join = path.join;
const fs = require("fs");
const shell = require("shelljs");


/**
 *检查用户输入的文件名是否合法
 *
 * @param {*} filename 文件名
 * @returns 文件名
 */
const get_File_Name = filename => {
  if (/.js$/.test(filename)) {
    return filename
  } else {
    return filename + ".js"
  }
}

/**
 *使用webpack打包文件
 *
 * @param {*} CONFIG 用户配置
 * @returns 结果
 */
module.exports = async CONFIG => {
  // 配置参数
  const { tools_key = [], is_build = true, save_file_name } = CONFIG;
  // 获取到webpack配置地址
  const CONFIG_PATH = path_join(__dirname, "../../config/");
  // 打包输出路径地址 // 用户打开控制台的地址
  const OUTPUT_PATH = path_join(process.cwd(), get_File_Name(save_file_name));
  // 拼接 webpack 命令行
  const CMD = `npx webpack ${is_build ? "--build" : ""}  --output ${OUTPUT_PATH}`;
  // 返回异步结果(shells是同步的)
  return new Promise((resovle, reject) => {
    shell.cd(CONFIG_PATH);
    const EXEC_RES = shell.exec(CMD);
    if (EXEC_RES.code === 0) {
      resovle(OUTPUT_PATH); //返回成功地址
    } else {
      reject(EXEC_RES); //失败
    }
  });
};
配置文件

.babellrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "10"
        },
        "modules": "umd",
        "useBuiltIns": "usage",
        "corejs": 3,
      }
    ]
  ],
  "plugins": [],
  "ignore": [
    "src/tools"
  ]
}

config/webpack.config.js

const path = require("path");
// 判断是否有 --build 标识
const IS_BUILD = (Array.isArray(process.argv) ?process.argv : []).includes("--build");
// babel
const BABEL_BUILD = {
  test: /.js$/,
  exclude: /(node_modules|bower_components)/,//排除掉node_module目录
  use: {
    loader: "babel-loader",
    options: {
      presets: [
        ["@babel/preset-env", {
          modules:false,
          useBuiltIns: "usage",
          corejs: 3,
        }]
      ],
      plugins: [],
    }
  }
};
module.exports = {
  entry: path.resolve(__dirname, "../temporary/utils.js"),
  mode: "production",
  output: {
    filename: "utils.js",
    path: path.resolve(__dirname, "../temporary/dist")
  },
  module: {
    rules: [
      (IS_BUILD ? BABEL_BUILD : {}) // --build
    ]
  }
};

bin/www

#! /usr/bin/env node
require("../src/main.js");
发布到NPM
先修改package.json 文件, 添加 bin 属性
代表全局方法名为: wxh
"bin": {
  "wxh": "./bin/www"
},
登录自己的npm账号
npm adduser
推送包到npm仓库中
npm publish
推送npm包注意事项

检查自己的包在npm库中有没有重命名

每一次推送包都要修改package.jsonversion 字段

写在最后

到这里我们整个包都已经写好了, 只需要安装到全局, 我们就可以使用了;
之后的日常维护, 我们只需要在 src/tools 目录下添加一个个方法就好了;
偷懒写一个方法 create_methods_list.js;
方法根据 /src/tools目录下的方法文件, 生成 methods_list.json 文件到config目录;

const fs = require("fs");
const path = require("path");
const path_join = path.join;
const read_dir_file = require("./src/utils/read_dir_file");
// 读取
const fileArr = read_dir_file(path_join(__dirname, "./src/tools"));
fs.writeFileSync(path_join(__dirname, "./config/methods_list.json"),
  JSON.stringify({ methods_list: fileArr })
);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106295.html

相关文章

  • 开发基于 Laravel 项目自动化部署扩展包之 laravel-unideploy

    摘要:关于使用部署项目,我后来在社区看到了的一篇文章,总结的很好,方便以后查阅,再此我记一下链接,文中把整个部署过程讲的很通透,下面的评论也有一些可能会在未来遇到的问题,总体来说很赞 showImg(https://segmentfault.com/img/remote/1460000016566097); 实际项目开发中,对于自动化部署 php 项目市面上鲜有比较不错的方案,比如瓦力,比...

    SmallBoyO 评论0 收藏0

发表评论

0条评论

smartlion

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<