◆ 公開はすごく簡単にできる 

普段 JavaScript ばかりいじってますが 基本的にブラウザのもので node.js はたまに使うくらいです
node.js で使われる npm もたまに npm install で試してみるものがあるくらいであんまり使ってません

普段コードはブログか gist においていますが ブログは記事数が多くなってくると探すのがちょっと大変です
再利用しそうなコードを書いた記事以外が多すぎますからね

gist もあんまり検索に向いてないです

何か無いかなと考えていると npm を思いつきました
npm だと npm install でインストールできるし ちょっと試す分には そのまま node.js でやってしまってもいいですし インストールされた node_modules から js ファイル持ってきて HTML からロードすることもできます

とりあえず使ってみようということで たまに使いそうなライブラリ公開してみた
のですが このことをブログに書く想定で公開してなかったので 公開に使ったアカウント名を伏せるために公開したのとは別のを使って説明します

何か作る

実際に公開してみたのを例にするとぐぐったらアカウントがわかるので 何か別に作ります

たまに思うのですが
!function(){
if(1){
var text = `
a
  b
c
  d
e
   f
`
console.log(text)
}
}()
a
  b
c
  d
e
   f

こういうインデントがちょっと深いところでテンプレートストリング (`) を使うとインデントが気持ち悪くなります
コードの見た目を重視すると
!function(){
if(1){
var text = `
a
  b
c
  d
e
   f
`
console.log(text)
}
}()
a
  b
c
  d
e
   f

インデントがそのままでるのでこうなります
これをどうにかしたくてこう書けるようにしてみます
!function(){
if(1){
var text = alignFirst `
a
  b
c
  d
e
   f
`
console.log(text)
}
}()
a
  b
c
  d
e
   f

コードはこうなりました
function alignFirst(parts, ...pieces){
const lines = join(parts, pieces).split("\n").slice(1, -1)
if(lines.length === 0) return ""
const indent = lines[0].length - lines[0].trimLeft().length
const re = new RegExp(String.raw `^\s{0,${indent}}`)
return lines.map(e => e.replace(re, "")).join("\n")
}

function join(arr, betweens){
var g = loop(betweens)
return arr.reduce((a, b) => a + g.next().value + b)
}

function* loop(arr){ while(true) yield* arr }

では とりあえずこのコードを align-first.js というファイル名で保存します

このファイルを公開する用のフォルダを作って入れておきます
-- align-first\
   -- align-first.js

node.js で使える形にする

npm は node.js のパッケージなので node.js で使える形にします
いまだに ES2015 の ES module が使えるようになったという話は聞かないので これまでどおりの node.js の module の作り方にします

export したいデータを exports のプロパティに設定します
exports オブジェクトが require したときの返り値になります
function alignFirst(parts, ...pieces){
const lines = join(parts, pieces).split("\n").slice(1, -1)
if(lines.length === 0) return ""
const indent = lines[0].length - lines[0].trimLeft().length
const re = new RegExp(String.raw `^\s{0,${indent}}`)
return lines.map(e => e.replace(re, "")).join("\n")
}

function join(arr, betweens){
var g = loop(betweens)
return arr.reduce((a, b) => a + g.next().value + b)
}

function* loop(arr){ while(true) yield* arr }

exports.alignFirst = alignFirst

最後の行が増えただけです

require で動くか確認します
同じ align-first フォルダの中に require-test.js というファイルを作って
const align_first = require("./align-first")
const alignFirst = align_first.alignFirst

if(1){
const text = alignFirst `
a
b
c
d
`
console.log(text)
}

node で実行します
C:\Users\user\Desktop\align-first>node require-test.js
a
        b
c
        d

ちゃんとロードできています

最初に
align_first.alignFirst

とやっていますが これは exports のプロパティに alignFirst を入れていて require した返り値は exports 自身になるからです
exports 自身を alignFirst にしてしまえばもうちょっと短くできますが 将来的に関数増やしたいときに使い方が変わるのでこうしてます
一応公開する以上 使い方が変わるのはできるだけ避けたほうがいいと思うので 1 つしかプロパティなくてもこうしてるパッケージは結構あると思います

どうしても require の返り値を関数にしたいなら
module.exports = alignFirst

とすれば
const text = require("./align-first")`
    a
    b
`

こう使えます

ブラウザでも使えるようにする

個人的にはブラウザで使うほうが多いのでブラウザでも動くようにしておきます
module だと module のトップレベルで定義しても global ではないのですが ブラウザではそうはいかないので export するもの以外見えないようにします
!function(){
function alignFirst(parts, ...pieces){
const lines = join(parts, pieces).split("\n").slice(1, -1)
if(lines.length === 0) return ""
const indent = lines[0].length - lines[0].trimLeft().length
const re = new RegExp(String.raw `^\s{0,${indent}}`)
return lines.map(e => e.replace(re, "")).join("\n")
}

function join(arr, betweens){
var g = loop(betweens)
return arr.reduce((a, b) => a + g.next().value + b)
}

function* loop(arr){ while(true) yield* arr }

typeof exports !== "undefined" && (exports.alignFirst = alignFirst)
typeof window !== "undefined" && (window.alignFirst = alignFirst)
}()

パッケージ作る

JavaScript 的には準備ができたので公開用のパッケージを作って試しにローカルのパッケージをインストールしてみます
パッケージを作ると言っても公開用のフォルダに package.json を置くだけです
{
  "name": "align-first",
  "version": "1.0.0",
  "main": "align-first.js"
}

最低限これだけあれば大丈夫
これで公開用のフォルダがパッケージになります

みんなに使ってもらうことを前提にしてるなら description に説明書いたり script に実行用のコマンド書いたり もっと色々書いた方がいいと思います
https://docs.npmjs.com/files/package.json

あと README 置いたり ですね


手動で書かなくても
npm init
コマンドを実行すると 対話型で色々聞いてくれてそれにそって入力すると コマンドを実行したフォルダに package.json ができます
聞かれる項目がちょっと多いのでどこかのパッケージをコピペしてきて それをテンプレートに編集したほうが楽な場合もあります

ローカルインストールする

公開用のフォルダがデスクトップにあるならこんな構造になってるはずです
-- デスクトップ\
   -- align-first\
      -- align-first.js
      -- package.json

このパッケージをインストールするために別のフォルダを作ります
-- デスクトップ\
   -- align-first\
      -- align-first.js
      -- package.json
   -- test\

test フォルダで
C:\Users\user\Desktop\test>npm install ..\align-first

test フォルダの中に node_modules フォルダができて その中に align-first フォルダがあるはずです

試しに test フォルダに test.js ファイルを↓の中身で作ります
const align_first = require("align-first")
const alignFirst = align_first.alignFirst

if(1){
const text = alignFirst `
a
b
c
d
`
console.log(text)
}

実行してみると
C:\Users\user\Desktop\test>node test.js
a
        b
c
        d

ちゃんと動きますね

公開する

ローカルで問題無いことを確認したらアップロードして完了です

まずは npm にサインアップします

ユーザ名とパスワードとメールアドレスくらいのシンプルなものです
メールアドレスは公開されるので注意です
メールアドレスに送られてきたリンクをクリックする必要もないので 見た人が間違ってメールしてしまうことがない明らかなダミーアドレスを入れておいても問題はなさそう

そのまま 公開まで web で出来るのかと思っていたらどこにもボタンがなくて調べてみると npm コマンドが必要でした

最初は npm adduser でアカウント設定が必要です
C:\Users\user\Desktop\align-first>npm adduser
Username: username
Password:
Email: (this IS public) mail.address@mail.address
Logged in as username on https://registry.npmjs.org/.

対話型でユーザ名とパスワードとメールアドレスを聞かれます
メールアドレスはサインアップしたものと違っても大丈夫でした


終わったら npm publish コマンドで公開できます
C:\Users\user\Desktop\align-first>npm publish
+ align-first@1.0.0

最後に npm install でインストールされることを確認しておしまい
C:\Users\user\Desktop\test>rmdir node_modules /S /Q
C:\Users\user\Desktop\test>npm install align-first

※ 実際にはこのパッケージを公開してないので探しても見つかりません


adduser ができていない状態で publish してしまってもエラーになるだけです
メッセージにあるように npm adduser しましょう
C:\Users\user\Desktop\align-first>npm publish
npm ERR! Windows_NT 6.1.7601
npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "publish"
npm ERR! node v6.10.1
npm ERR! npm  v3.10.10
npm ERR! code ENEEDAUTH

npm ERR! need auth auth required for publishing
npm ERR! need auth You need to authorize this machine using `npm adduser`

npm ERR! Please include the following file with any support request:
npm ERR!     C:\Users\user\Desktop\align-first\npm-debug.log

まとめ

公開したいもの作る

nodejs で require 出来る形にする(ブラウザでも同じコード使うなら window へのエクスポートも)

公開用フォルダに package.json をおいて最低限の設定を書き込む

(初めてなら) npm にサインアップ (web) して npm adduser で登録したユーザ情報を npm に設定 (コマンド)

package.json のあるところで npm publish コマンドを実行して公開


まとめるとすごく簡単にできるようになってます

おまけ

どうして module.exports を書き換えれるのに exports をそのまま書き換えれないの?
とか
module のトップレベルで定義したのが global にないの?

って思う人はこちらをどうぞ
Node.js 7 が出てたのでなんとなく module の読み込みを調べてみた

簡単にいってしまうと
(function (exports, require, module, __filename, __dirname) { 【ここにファイルの中身】\n});

として実行されてるから というだけですけど