npm script を調べる


なぜ npm script  に興味を持ったか

Sass を CSS にコンパイルしたり、ES6 を ES5 に変換したり、こまごました作業を今は Gulp で実行する人が多いと思います。Gulp は Node.js 上で動いており、Gulp で require() している対象は Node のモジュール = Node Package Module = npm  です。ということは npm のことがもっとわかれば Gulp のこともわかるはずだ、というのが npm についてもっと調べようと思った理由の一つです。

もう一つの理由は、これが直背的な理由なのですが、Gulp で Gulp 用のプラグインを使うためには、Gulp に特化した記法の学習が必要で(基本的な用途であればそこまで難しくないのですが)、それよりも CLI(コマンドラインインターフェイス、つまり Mac ならターミナルからコマンドで実行する方法など) のほうが楽だという流れがあるらしく、たしかにいくつかの作業は CLI から直接 npm を実行したほうが簡単にできました。(例えば Browserify のビルドを、対象のファイルをウォッチして、さらに差分だけをビルドする作業は、Wachify を CLI から実行すると非常に簡単です。しかし Gulp-watchify を使って Gulp のタスクを書くのは私には非常に複雑に思えました) そしてこの CLI で実行するためのコマンドは、package.json に npm script という形で記述すれば、CLI から npm start といった簡略したコマンドで実行できることもわかりました。ですので、この npm script という仕組みをより学べば、npm を実行する方法をより理解することができると思いました。

さらに具体的には、一部の npm は CLI で実行する際に明記するオプションを、どうやら package.json の中にかけるのですが、これがどういった仕組みで参照されているのかわからなかったので、npm script についての理解をもっと根本的にする必要を感じました。具体的には次のような packgage.json ファイルです。(引用元)

babel, browserify といった項目があり、これが明らかに CLI で npm を実行する際に必要なオプションの内容であるのは間違いないのですが、なぜここに書いて参照されるのか謎でした。

{
  "name": "front-end-starter",
  "version": "1.2.0",
  "description": "This is a starter kit of the Web front-end development.",
  "author": "akabeko",
  "license": "MIT",
  "main": "index.js",
  "keywords": [
    "web",
    "frontend",
    "starter"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/akabekobeko/examples-web-app"
  },
  "babel": {
    "presets": [
      "latest"
    ],
    "env": {
      "development": {
        "presets": [
          "power-assert"
        ]
      }
    }
  },
  "browserify": {
    "transform": [
      "babelify"
    ]
  },
  "esdoc": {
    "source": "./src/js",
    "destination": "./esdoc",
    "test": {
      "type": "mocha",
      "source": "./test"
    }
  },
  "scripts": {
    "test": "mocha --compilers js:babel-register test/**/*.test.js",
    "start": "npm run watch",
    "esdoc": "esdoc",
    "build:css": "stylus -c --include-css ./src/stylus/App.styl -o ./src/assets/bundle.css -m --sourcemap-base ../stylus",
    "build:js": "browserify ./src/js/App.js -d | exorcist ./src/assets/bundle.js.map > ./src/assets/bundle.js",
    "build": "npm-run-all -p build:css build:js",
    "watch:css": "stylus -c -w --include-css ./src/stylus/App.styl -o ./src/assets/bundle.css -m --sourcemap-base ../stylus",
    "watch:js": "watchify ./src/js/App.js -v -o \"exorcist ./src/assets/bundle.js.map > ./src/assets/bundle.js\" -d",
    "watch:server": "browser-sync start --server ./ --startPath src/assets/",
    "watch": "npm-run-all -p watch:css watch:js watch:server",
    "release:css": "stylus -c --include-css ./src/stylus/App.styl -o ./dist/bundle.css",
    "release:js": "cross-env NODE_ENV=production browserify ./src/js/App.js | uglifyjs -c warnings=false -m > ./dist/bundle.js",
    "release:clean": "rimraf ./dist",
    "release:copy": "cpx \"./src/assets/**/!(*.js|*.css|*.map)\" ./dist",
    "release": "npm-run-all -s release:clean release:copy -p release:css release:js"
  },
  "dependencies": {
    "normalize.css": "^5.0.0"
  },
  "devDependencies": {
    "babel-preset-latest": "^6.16.0",
    "babel-preset-power-assert": "^1.0.0",
    "babel-register": "^6.18.0",
    "babelify": "^7.3.0",
    "browser-sync": "^2.18.6",
    "browserify": "^13.3.0",
    "cpx": "^1.5.0",
    "cross-env": "^3.1.4",
    "esdoc": "^0.5.2",
    "exorcist": "^0.4.0",
    "mocha": "^3.2.0",
    "npm-run-all": "^4.0.0",
    "power-assert": "^1.4.2",
    "rimraf": "^2.5.4",
    "stylus": "^0.54.5",
    "uglify-js": "^2.7.5",
    "watchify": "^3.8.0"
  }
}

例えば CLI で Browserify を実行するためには、次のように transform オプションを入力しますが、上記の npm script “build:js”には全く書いておらず、そのかわりにそれに相当する文言は繰り返しになりますが package.json に書かれています。

$ browserify main.js -o app.js -transform [ babelify --presets [ es2015 ] ] --debug

ということで、npm と npm script への理解を深めれば、環境構築のための基礎知識が深まり、根本的な理解をすることができるようになる、というのが今回の動機です。

npm とは

例によって公式ドキュメントを勝手に日本語にします。(もちろん日本語で npm を詳細に解説しているサイトは無限にあるのですが、最終的には自分で公式ドキュメントを読まなくてはいけないフェーズが必ずくるので、なるべくは公式を読むようにしています)

What is npm?

npm makes it easy for JavaScript developers to share and reuse code, and it makes it easy to update the code that you’re sharing.

npm は JavaScript 開発者がコードを共有したり、使いまわすことを簡単にしてくれます。またシェアしているコードをアップデートすることも簡単にしてくれます。

If you’ve been working with Javascript for a while, you might have heard of npm: npm makes it easy for Javascript developers to share the code that they’ve created to solve particular problems, and for other developers to reuse that code in their own applications.

JavaScript の開発をしている人であれば npm のことは聞いたことがあるはずです。npm を使えば、開発者は問題を解決するために使ったコードを多くの人と簡単に共有することが出来るので、他の開発者はそれを自分のアプリケーションで使うことができるようになります。

Once you’re depending on this code from other developers, npm makes it really easy to check to see if they’ve made any updates to it, and to download those updates when they’re made.

npm によって管理されているコードを使えば、そのコードにアップデートがある場合、すぐに確認してダウンロードすることができます。

These bits of reusable code are called packages, or sometimes modules. A package is just a directory with one or more files in it, that also has a file called “package.json” with some metadata about this package. A typical application, such as a website, will depend on dozens or hundreds of packages. These packages are often small. The general idea is that you create a small building block which solves one problem and solves it well. This makes it possible for you to compose larger, custom solutions out of these small, shared building blocks.

これらの再利用可能なコードの断片を「Packages」と呼びます。もしくはモジュールという場合もあります。パッケージは単なるディレクトリで、その中にはファイルがあります。この中には package.json というファイルもあります。これにはそのパッケージに関するメタデータが記録されています。例えばウェブサイトのような典型的なアプリケーションは、何百ものパッケージを用いています。これらのパッケージ一つ一つは大抵の場合、小さなものです。一般的な考えとして次のようなものがあります。問題一つをうまく解決してくれる小さなブロックを作るのがよい。そしてその小さなブロックをつかってより大きく、個別性の高い問題の解決策を作ることが出来ます。

There’s lots of benefits to this. It makes it possible for your team to draw on expertise outside of your organization by bringing in packages from people who have focused on particular problem areas. But even if you don’t reuse code from people outside of your organization, using this kind of module based approach can actually help your team work together better, and can also make it possible to reuse code across projects.

こういった考え方を推進するにあたって npm は大きな貢献します。パッケージを使用することで、外部のある特定の問題についての専門家の助言を採用するのと同じ利益を享受します。もちろん誰か他の人が作ったパッケージを使用しなくても、自分の組織内でうまく再利用可能なコードを作るためにも npm は役に立ちます。

You can find packages to help you build your application by browsing the npm website. When you’re browsing the website, you’ll find different kinds of packages. You’ll find lots of node modules. npm started as the node package manager, so you’ll find lots of modules which can be used on the server side. There are also lots of packages which add commands for you to use in the command line. And at this point you can find a number of packages which can be used in the browser, on the front end.

自分に役立ちそうなパッケージを探すためには npm のウェブサイト検索してください。たくさんのパッケージがありますが、npm は node 用のパッケージとしてスタートしたものなので、サーバーサイドで動くモジュールがたくさんあります。またコマンドラインで実行できるコマンドを増やすパッケージもあります。また現在ではブラウザーで動く、つまりフロントエンド用のパッケージもあります。

So now that you have an idea of what npm can do, let’s talk about how it works. When people talk about npm, they can be talking about one of three things. They could be talking about the website, which we’ve just been looking at. Or they could be talking about the registry, which is a big database of information about packages that people are sharing. Or the third thing they could be talking about is the client: when a developer decides to share their code, they use the npm client which is installed on their computer to publish that code up to the registry. And once there’s an entry for this package in the registry, then other developers can use their npm clients to install the package from the registry. The entry in the registry for this package is also reflected on the website, where there’s a page dedicated to this new package.

さあ npm がどんなことをしてくれるか概要がわかったと思うので、今度は npm がどのように機能しているのかについてお話しします。npm について誰かが話題にしていたら、これは次の3項目のうちのどれかについて話をしています。まずはウェブサイトについてです。これについては今までお話してきましたね。次に、レジストリについて話してる場合もあります。ここでいうレジストリとは、公開されたパッケージに関する膨大な情報をもったデータベースのことです。最後にクライアントについてです。開発者がコードを共有する場合に npm クライアントを用いてレジストリにコードを公開します。そして他の人が npm クライアントを用いてそのコードを使います。公開されたコードウェブサイトに使われます。

So that’s what npm is. It’s a way to reuse code from other developers, and also a way to share your code with them, and it makes it easy to manage the different versions of code.

npm がどのようなものかわかりましたね。npm は第三者が開発したコードを再利用する方法であり、開発者がコードを共有するための方法であり、そしてそれらのコードのバージョンを管理しやすくしてくれるシステムです。

Package と module の違いとは

https://docs.npmjs.com/how-npm-works/packages

One of the key steps in becoming immersed in an ecosystem is learning its vocabulary. Node.js and npm have very specific definitions of packages and modules, which are easy to mix up. We’ll discuss those definitions here, make them distinct, and explain why certain default files are named the way they are.

ある生態系について詳しくなるためには用語を学ぶことが重要です。Node.js と npm はパッケージとモジュールについてかなり詳細な定義をしています。そしてこれは混同しやすいです。これらの定義について説明しながら、明確にし、なぜ module と呼ばれるものと package と呼ばれるものがあるのかを説明します。

Quick Summary

  • A package is a file or directory that is described by a package.json. This can happen in a bunch of different ways! For more info, see “What is a package?, below.
  • A module is any file or directory that can be loaded by Node.js’ require(). Again, there are several configurations that allow this to happen. For more info, see “What is a module?”, below.
  • パッケージは package.json によって記述されるファイルもしくはディレクトリです。これは様々な方法でブランチを作ります。
  • モジュールは Node.js の require() によってロードされるファイルもしくはでょレクトリです。

What is a package?

平たくいってa)だけが重要。package.json を含んでいるということ。それを圧縮したり、url だったり色々形式はあるとのこと。

A package is any of the following:

a) a folder containing a program described by a package.json file
b) a gzipped tarball containing (a)
c) a url that resolves to (b)
d) a <name>@<version> that is published on the registry with (c)
e) a <name>@<tag> that points to (d)
f) a <name> that has a latest tag satisfying (e)
g) a git url that, when cloned, results in (a).
Noting all these package possibilities, it follows that even if you never publish your package to the public registry, you can still get a lot of benefits of using npm:

if you just want to write a node program, and/or
if you also want to be able to easily install it elsewhere after packing it up into a tarball
Git urls can be of the form:

git://github.com/user/project.git#commit-ish
git+ssh://user@hostname:project.git#commit-ish
git+http://user@hostname/project/blah.git#commit-ish
git+https://user@hostname/project/blah.git#commit-ish

The commit-ish can be any tag, sha, or branch which can be supplied as an argument to git checkout. The default is master.

What is a module?

A module is anything that can be loaded with require() in a Node.js program. The following are all examples of things that can be loaded as modules:

モジュールは Node.js の require() によってロードされるものです。次リストはモジュールとしてロードされるものの例です。

  • A folder with a package.json file containing a main field.
  • main フィールドを持つ package.json があるフォルダー
  • A folder with an index.js file in it.
  • index.js ファイルを持つフォルダー
  • A JavaScript file.
  • ただのJavaScript ファイル

Most npm packages are modules

Generally, npm packages that are used in Node.js program are loaded with require, making them modules. However, there’s no requirement that an npm package be a module!

大抵の場合 npm パッケージは Node.js の中でロードされます。ということはモジュールだということです。しかしながら、npm パッケージが必ずしも module である必要はありません。

Some packages, e.g., cli packages, only contain an executable command-line interface and don’t provide a main field for use in Node.js programs. These packages are not modules.

パッケージには、例えばCLI 用のパッケージなどは、コマンドラインで実行できるコマンドを含んでいるだけで、Node.js が使う main フィールドがないものがあります。こういったパッケージはモジュールではありません。

Almost all npm packages (at least, those that are Node programs) contain many modules within them (because every file they load with require() is a module).

ほとんどすべての npm パッケージは、(少なくともノードプログラムの場合には) たくさんのモジュールを内部に持っています。(なぜならノードの require() によってロードされるファイルはモジュールだからです。)

In the context of a Node program, the module is also the thing that was loaded from a file. For example, in the following program:

ノードのプラグラムにおいては、モジュールはファイルからロードされるものでもあります。例えば次のコードをみてください。

var req = require(‘request’)

we might say that “The variable req refers to the request module”.

このコードは「変数 rew は request モジュールを参照している」ということをいています。

File and Directory Names in the Node.js and npm Ecosystem

So, why is it the node_modules folder, but package.json file?
Why not node_packages or module.json?

なぜ node_modules フォルダーという名前で、そしてその中には package.json ファイルがあるのでしょうか。またなぜ node_package というファイルに module.json というファイルがあってはだめだったのでしょうか。

The package.json file defines the package. (See “What is a package?”, above.)

package.json ファイルはパッケージを定義しています。

The node_modules folder is the place Node.js looks for modules. (See “What is a module?”, above.)

node_modules フォルダは Node.js が「モジュールを探しに行く場所」です。

For example, if you create a file at node_modules/foo.js and then had a program that did var f = require(‘foo.js’), it would load the module. However, foo.js is not a “package” in this case because it does not have a package.json.

例えば node_modules の中に foo.js というファイルを作って、さらにそれを var f = require(‘foo.js’) とロードするプログラムを書いたとすると、これはモジュールをロードしていることになります。しかしながら、foo.js はパッケージではありません。なぜならpackage.json を持っていないからです。

Alternatively, if you create a package which does not have an index.js or a “main” field in the package.json file, then it is not a module. Even if it’s installed in node_modules, it can’t be an argument to require().

またパッケージを作ったとしても、index.js をもたないか、もしくはpackage.json に main フィールドを持たない場合、これはモジュールではありません。例え node_modules の中にあったとしても、require() の対象にはなりません。

 

代表的なNode Module

  • Babel
  • Node-Sass
  • Browserify

Leave a Reply

Your email address will not be published. Required fields are marked *