12
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JSer のためのタスクランナー MEMI

Last updated at Posted at 2018-09-13

TL;DR

NPM

  • https://github.com/3846masa/memi
  • JSer のためのタスクランナー MEMI
  • ES module で 1タスク 1Function で書ける
  • 依存関係を自動でインストールしてくれる

なんで作ったのか

きっかけは mimorisuzuko/memi

要約すると,

  • JavaScript で書けるタスクランナーが欲しい
    • Makefile やシェルスクリプトは,凝った処理を書くのが怠い
  • どのディレクトリでも手間なく使いたい
    • Node.js に関係ないディレクトリで node_modulespackage.json を置きたくない
  • タスクで使うモジュールのグローバルインストールは避けたい
    • npm root -g の場所とは別のところに置きたい

既存のタスクランナーと問題点

  • Makefile
    • シェルスクリプトで書かないといけないので,ちょっと複雑なことをしようとすると怠い
    • Windows で make を入れるのが怠い
  • npm scripts
    • package.json を置きたくない
  • gulp
    • 使うモジュールもグローバルかローカルに入れないといけない
      • node_modules を置きたくない
      • グローバルインストールは増やしたくない

JSer のためのタスクランナー MEMI

Memifile.js でタスクを定義できる.

import fs from 'fs-extra';
import path from 'path';
import execa from 'execa';

export default {
  async clean() {
    await fs.remove(path.join(__dirname, 'dist'));
  },
  async build() {
    await this.clean();
    await execa.shell('webpack');
  },
};

ネストが気になる人や Default export 排除派は, Named exports でも書ける.

import fs from 'fs-extra';
import path from 'path';
import execa from 'execa';

export async function clean() {
  await fs.remove(path.join(__dirname, 'dist'));
}

export async function build() {
  await clean();
  await execa.shell('webpack');
}

ついでに, CommonJS 方式でも書ける.

const fs = require('fs-extra');
const path = require('path');
const execa = require('execa');

module.exports = {
  async clean() {
    await fs.remove(path.join(__dirname, 'dist'));
  },
  async build() {
    await this.clean();
    await execa.shell('webpack');
  },
};

タスクは,memi <taskname> で実行する.例えば, build したいなら memi build とすれば動く.
もちろんサブディレクトリ内にいても,Memifile.js を再帰的に探しに行くので問題ない.
これを応用すると,ホームディレクトリに Memifile.js を入れておくことで,どこでも使えるコマンドも作れる.

memi <taskname> arg1 arg2 ... とすると,Function の引数に arg1 などが渡されるので,ちゃんとしたコマンドを作ることもできる.
Inquirer なども使えるので,対話式のコマンドも難なく作れる.

import inquirer from 'inquirer';
import cowsay from 'cowsay';

export default {
  async echo(text) {
    if (!text) {
      const res = await inquirer.prompt([{
        name: 'text',
        message: "How's it going?",
      }]);
      text = res.text;
    }
    console.log(cowsay.say({ text }));
  },
};

さらにここからが MEMI の真骨頂で,依存するモジュールを自動でインストールしてくれる
例えば,上の Memifile.js では, fs-extraexeca がインストールされる.
インストール先は $HOME/.memi%USERPROFILE%\.memi になるので,グローバルと混ざらないし,ローカルに入れる必要もない.


MEMI は 小さいスクリプトを手間なく書き始められて ,出来が良ければ そのままホームディレクトリに突っ込んで,いつでも使える CLI コマンドにできる

気軽にも使えるし,本格的にも使えるタスクランナー.
ぜひ使ってみてほしい.

余談: Qiita API と MEMI

この記事は VSCode から書いて API 経由で投稿したが,それも MEMI でざっくりコマンドを作った.

import 'dotenv/config';
import fs from 'fs-extra';
import fm from 'front-matter';
import axios from 'axios';
import opn from 'opn';

export async function qiita(file) {
  if (!file) {
    return;
  }

  const { attributes, body } = fm(await fs.readFile(file, 'utf8'));
  const { data: res } = await axios.request({
    method: 'post',
    url: 'https://qiita.com/api/v2/items',
    data: {
      body,
      title: attributes.title,
      tags: attributes.tags.map(name => ({ name })) || [],
      private: true,
    },
    headers: {
      Authorization: `Bearer ${process.env.QIITA_TOKEN}`,
      'Content-Type': 'application/json',
    },
  });

  console.log(res.url);
  opn(res.url);
}

memi qiita filename.md とすれば,投稿されて URL がブラウザで開く.
しっかり作るなら更新機能とかも欲しくなるが,取っ掛かりとしてはこの程度から始めるのでも良い気がする.

余談: MEMI とは

発案者曰く,

柿崎芽実さんはけやき坂46のメンバーで,memiとmakeが似てるから選びました.推しは齊藤京子です.

12
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?