如何使用grunt, bower與npm製做js package - part 1 - 概觀、bower.json與package.json
2014-10-08 11:26:48

最近想把自己寫的angular module(Github - sibevin/angular-tau-utils)包成package,這樣除了可以方便安裝,程式碼也比較好管理。其實一開始還真不知道要怎麼開始(繞口令…),於是就找了網路上的別人的package(Github - chieffancypants/angular-loading-bar)來偷學(open source的好處),以下是不負責筆記。

需求

對我來說,我希望可以盡可能簡化打包package的流程,所以想要做到:

  • package management,也就是可以管理package的相依性,只要下一個指令就可以把js或是開發環境需要用到的package都裝好。=> bower, npm
  • 自動化測試:當修改完程式碥的時候,可以自動做測試。而且因為是用coffeescript寫js,所以當然是希望可以在測試前就能先自動compile。另外也要能自動計算並產生coverage的報表。=> grunt, karma
  • 類似makefile的東東可以自行組一系列的指令來處理build, test與clean的功能。=> grunt

目錄架構

我規劃的目錄結構如下,除了bower.json, package.json與Gruntfile.js這些設定檔名字不能亂取之外,其它目錄名稱其實可以隨便取,只要在設定Gruntfile位置指對就好了。

  • src/ - angular module的原始碼(.coffee檔)
  • test/ - 測試的原始碼(.coffee檔)
  • lib/ - (自動生成)angular module的js檔,尚未合併與壓縮(uglfiy)
  • build/ - (自動生成)最後要包在package的js檔與min.js檔,也就是lib中的js合併與壓縮(uglfiy)後的結果
  • coverage/ - (自動生成)用來放coverage的結果
  • bower.json - bower package的設定檔
  • package.json - npm package的設定檔
  • Gruntfile.js - grunt的設定檔

基本上能自動生成的目錄與檔案都不應該commit到repo中,不過因為要包成package,build的目錄還是要commit。

Bower ? Npm ?

首先我知道bower這個package management,所以自然會想包成bower package,但是在看bower的文件發現還要處理另一個npm的package。這就讓我有點困惑,這兩個到底差在哪?我又要包成哪一個?查了一下G大(bower npm),果然也有很多人跟我有同樣的問題(SO1, SO2),簡單來說:

  • bower:bower package比較像是用在frontend的package,除了js外,像是css或是圖片檔都可以包進package當中。所以如果是要包angular module,肯定是要包成bower package。
  • npm:npm package其實就是nodejs專用的package,如果是frontend的js,就沒有必要放進npm。但npm可以用在管理開發所需要的其它package的相依性,像是grunt與karma等,也就是說包成的npm package實際上只用到它的package dependence management,npm裡的js並不會用在nodejs之中。

從零開始建package

當然不是從零開始,至少要把node js與bower裝好。這些準備好之後,接下來的步驟會先建立package root folder, bower.json與package.json這兩個檔案。

建立package root folder

一開始先建立一個folder用來放package所有的內容(也就是目錄結構中提到的檔案與目錄),我們把這個目錄稱作package root folder,所有的操作都會在這個目錄下執行。

$ mkdir angular-tau-utils
$ cd angular-tau-utils

準備source code與test

將source code放在src/,測試檔則是放在test/。這兩個目錄的檔案與資料夾要怎麼放也是隨個人喜好,不過如果是angular相關的程式碼,我還是習慣會將controller, service, directive等這些類別分開放置,比較清楚也方便管理。

angular-tau-utils/
├── src
│   ├── angular_tau_utils.coffee
│   ├── tau-switcher
│   │   └── services
│   │       ├── bool_switcher.coffee
│   │       ├── cycle_switcher.coffee
│   │       └── tab_switcher.coffee
│   └── tau_switcher.js.coffee
└── test
    ├── angualr_tau_utils.coffee
    ├── tau-switcher
    │   └── services
    │       ├── bool_switcher.coffee
    │       ├── cycle_switcher.coffee
    │       └── tab_switcher.coffee
    └── tau_switcher.coffee

建立bower.json

建立bower.json其實很簡單,只要執行bower init就可以了,它會問你一些問題,填完bower.json就會幫你生好了,真方便啊。(詳細使用方式可以參考bower - Creating packages這份文件)

$ bower init
? name: angular-tau-utils
? version: 1.0.0
? description: Utilitis for AngularJS app
? main file: build/angular-tau-utils.js
? what types of modules does this package expose?: globals
? keywords: angular angularjs tau tau-utils utility
? authors: Sibevin Wang
? license: MIT
? homepage: https://github.com/sibevin/angular-tau-utils
? set currently installed components as dependencies?: No
? add commonly ignored files to ignore list?: Yes
? would you like to mark this package as private which prevents it from being accidentally published to the registry?: No
{
  name: 'angular-tau-utils',
  version: '1.0.0',
  authors: [
    'Sibevin Wang'
  ],
  description: 'Utilitis for AngularJS app',
  main: 'build/angular-tau-utils.js',
  moduleType: [
    'globals'
  ],
  keywords: [
    'angular',
    'angularjs',
    'tau',
    'tau-utils',
    'utility'
  ],
  license: 'MIT',
  homepage: 'https://github.com/sibevin/angular-tau-utils',
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}
? Looks good?: Yes

bower.json的設定值可以參考bower.json specification,要注意的是某些設定值有一定的規定與建議,所以別亂取啊。其中幾個重要的設定這邊說明一下

  • name - 就是你的package name,也是註冊在bower的唯一名稱。(別人先用掉的話就哭哭了)
  • main - 就是要包在package的js檔案路徑。
  • moduleType - 請參考Module Metadata for Bower Packages或是這篇SO
  • ignore - 在進行bower install時會省略的檔案,格式跟gitignore一樣。

建立package.json

之前提到我們還要另外準備npm package的設定檔,也就是package.json。建立package.json跟bower.json一樣簡單,只要執行npm init就可以了,它同樣會問你一些問題,填完package.json就會幫你生好了,一樣方便啊。

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install  --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (test) angular-tau-utils
version: (0.0.0) 1.0.0
description: Utilitis for AngularJS app
entry point: (index.js) build/angular-tau-utils.js
test command: grunt test
git repository: git@github.com:sibevin/angular-tau-utils.git
keywords: angular angularjs tau tau-utils utility
author: Sibevin Wang
license: (ISC) MIT
About to write to /Users/wangkaito/workspace/angular/dev/test/package.json:
{
  "name": "angular-tau-utils",
  "version": "1.0.0",
  "description": "Utilitis for AngularJS app",
  "main": "build/angular-tau-utils.js",
  "scripts": {
    "test": "grunt test"
  },
  "repository": {
    "type": "git",
    "url": "git@github.com:sibevin/angular-tau-utils.git"
  },
  "keywords": [
    "angular",
    "angularjs",
    "tau",
    "tau-utils",
    "utility"
  ],
  "author": "Sibevin Wang",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/sibevin/angular-tau-utils/issues"
  },
  "homepage": "https://github.com/sibevin/angular-tau-utils"
}
Is this ok? (yes)

package.json的設定值可以參考package.json,內容跟bower.json大同小異,所以就不再贅述。

NEXT

目前我們已經建立好bower與npm package的設定檔,會先建立這兩個檔案是因為在接下來的流程都會用到。下一篇會開始處理package dependence,並使用grunt建立自動化流程。