基於Webpack和ES6構建NPM包

ETEPLUS發表於2019-03-04

ES6編寫程式碼,使用Webpack打包匯出模組,併發布到NPM社群,新增基於Travis-CICoveralls的持續整合到Github專案中

特性

  1. 基於Webpack 4
  2. 使用ES6編寫原始碼
  3. 模組支援:
    • 在瀏覽器環境下使用,通過<script>標籤來引入這個類庫
    • 通過NPM安裝使用
    • 相容 ES6(ES2015) 的模組系統、CommonJSAMD 模組規範
  4. 使用 AVA 自動化測試,並通過 nyc 測試程式碼覆蓋率
  5. 持續整合(Travis-CI + Coveralls)
  6. 使用 ESLint + Standrad 檢測程式碼質量

專案初始化

1. 建立repository並clone到本地

$ git clone https://github.com/eteplus/typeof
複製程式碼

2. 新增.editorconfig

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.yml]
indent_style = space
indent_size = 2
複製程式碼

3. 建立目錄

+-- src 原始碼目錄
|   +-- typeof.js
|   +-- types.js
+-- test 測試用例
|   +--- test.js
+-- dist 輸出目錄
.
.
複製程式碼

4. 建立package.json

使用NPM作用域管理髮布模組,避免同名模組,一般使用使用者名稱來註冊私有模組(@eteplus/<package name>)

$ npm init --scope=eteplus
複製程式碼
package name: (@eteplus/typeof)
version: (1.0.0) 0.1.0
description: The typeOf method returns a string indicating the type of the value
entry point: (index.js) dist/typeof.js
test command:
git repository: https://github.com/eteplus/typeof.git
keywords: node,javascript,typeof
author: eteplus
license: (ISC) MIT
About to write to /Users/eteplus/Workspace/Node/study/typeof/package.json:

{
  "name": "@eteplus/typeof",
  "version": "0.1.0",
  "description": "The typeOf method returns a string indicating the type of the value",
  "main": "dist/typeof.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/eteplus/typeof.git"
  },
  "keywords": [
    "node",
    "javascript",
    "typeof"
  ],
  "author": "eteplus",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/eteplus/typeof/issues"
  },
  "homepage": "https://github.com/eteplus/typeof#readme"
}
複製程式碼

5. ESLint 初始化

自動生成.eslintrc.js檔案並安裝相關依賴(可根據自己喜好選擇程式碼規範)

  1. 安裝ESlint
# or use yarn
$ npm install eslint -D
複製程式碼
$ npm install eslint -g # 全域性安裝ESLint
$ eslint --init

? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Standard
? What format do you want your config file to be in? JavaScript
複製程式碼
  1. 新增.eslintignore檔案忽略對輸出目錄的程式碼檢測
dist/
複製程式碼

6. 建立webpack和babel的配置檔案

  1. 安裝相關依賴:
$ npm install webpack webpack-cli uglifyjs-webpack-plugin -D
$ npm install babel-loader babel-core babel-plugin-transform-runtime babel-preset-env -D
$ npm install eslint-loader eslint-friendly-formatter -D
複製程式碼
  1. 建立 webpack.config.js

webpack output 配置項說明 webpack.js.org/configurati…

'use strict'

const path = require('path')
const webpack = require('webpack')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

const resolve = dir => path.join(__dirname, '.', dir)

const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  entry: {
    typeof: './src/typeof.js'
  },
  output: {
    path: resolve('dist'), // 輸出目錄
    filename: '[name].js', // 輸出檔案
    libraryTarget: 'umd', // 採用通用模組定義
    library: 'typeOf', // 庫名稱
    libraryExport: 'default', // 相容 ES6(ES2015) 的模組系統、CommonJS 和 AMD 模組規範
    globalObject: 'this' // 相容node和瀏覽器執行,避免window is not undefined情況
  },
  devtool: '#source-map',
  module: {
    rules: [
      {
        test: /\.(js)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /(node_modules)/
      }
    ]
  },
  plugins: isProd
    ? [
      new UglifyJsPlugin({
        parallel: true,
        uglifyOptions: {
          compress: {
            warnings: false
          },
          mangle: true
        },
        sourceMap: true
      })
    ]
    : [
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NamedModulesPlugin(),
      new webpack.NoEmitOnErrorsPlugin()
    ]
}
複製程式碼
  1. 建立 .babelrc

heplers和polyfill根據實際情況開啟/關閉,具體配置參考(babel-plugin-transform-runtime

{
  "presets": ["env"],
  "plugins": [
    ["transform-runtime", {
      "helpers": false,
      "polyfill": false
      }
    ]
  ]
}
複製程式碼

7. 新增npm命令

在package.json上新增npm命令,通過npm run [name] 執行任務

{
  "scripts": {
    "dev": "NODE_ENV=development webpack --config webpack.config.js --mode=development -w",
    "build": "NODE_ENV=production webpack --config webpack.config.js --mode=production",
    "lint": "eslint ."
  }
}
複製程式碼

測試與程式碼覆蓋率

使用 AVA + nyc 自動化測試和測試程式碼覆蓋率

1. 安裝AVAnyc

$ npm install ava nyc -D
複製程式碼

2. 新增ava和nyc配置到package.json

AVA:

  • files:需要測試的用例檔案
  • verbose:開啟詳細輸出
  • babel:測試檔案的babel配置,'inherit'使用根目錄下的.babelrc
  • require:執行測試前需要額外的模組

其他配置項:

nyc:

{
  "ava": {
    "files": [
      "test/test.js"
    ],
    "verbose": true,
    "babel": "inherit",
    "require": [
      "babel-core/register"
    ]
  },
  "nyc": {
    "exclude": [
      "test/*.js"
    ]
  }
}
複製程式碼

3. 新增npm命令

{
  "scripts": {
    ...
    "test": "npm run lint && nyc ava",
    "test:watch": "ava --watch"
  }
}
複製程式碼

持續整合Travis CI

1. 登陸Travis-CI

travis-ci.org,使用Github授權登陸

2. 新增Repo

2018-04-04-13-54-44

3. 建立.travis.yml

在專案根目錄下新增.travis.yml

說明:

  • language 指定開發語言
  • node_js 指定node.js版本號

其它配置項:

language: node_js
node_js:
- '9'
- '8'
- '7'
複製程式碼

4. 提交.travis.yml

提交.travis.yml到Github, Travis-CI根據提交自動觸發持續整合,可在設定中取消根據提交自動觸發持續整合

2018-04-04-14-40-03

5. 獲取徽章

獲取持續整合結果徽章新增到README.md

2018-04-04-14-45-47

測試覆蓋率Coveralls

1. 登陸Coveralls

coveralls.io,使用Github授權登陸

2. 新增Repo

2018-04-04-14-27-17

3. 加密repo_token

安全起見,repo_token不應該明文寫到.travis.yml中,coveralls提供了非對稱加密repo_token的方法

2018-04-04-14-55-11
# 更改為國內的安裝源
$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$ gem sources -l
複製程式碼
# 安裝travis
$ sudo gem install travis -v 1.8.8 --no-rdoc --no-ri
$ travis version
1.8.8
複製程式碼
# 加密
travis encrypt COVERALLS_REPO_TOKEN=your_repo_token
複製程式碼
2018-04-04-15-28-22
  • 新增加密後的secure.travis.yml

修改.travis.yml,設定env環境變數(travis提供的repo_token安全方式之一),也可以使用 --add 自動新增到 .travis.yml中。

2018-04-04-15-33-53

4. 安裝coveralls並新增npm命令

  • 安裝coveralls
$ npm install coveralls -D
複製程式碼
  • 新增npm命令

nyc生成覆蓋率報告推送給coveralls

{
  "scripts": {
    ...
    "coverage": "nyc report --reporter=text-lcov | coveralls"
  }
}
複製程式碼

5. 修改.travis.yml

  • 新增 after_success: npm run coverage

after_success: script階段成功時執行, script階段預設指令碼為 npm test,可以省略

2018-04-04-16-23-41
  • 重新提交到Github,觸發持續整合,到coveralls.io檢視覆蓋率報告,並獲取徽章新增到README.md
2018-04-04-16-46-58

釋出模組到NPM社群

1. 打包程式碼

$ npm run build
複製程式碼

2. 新增賬號

需要先到www.npmjs.com註冊一個賬號

$ npm adduser
Username: your username
Password: your password
Email: your email
複製程式碼

3. 釋出

無作用域包始終是公開的。有作用域預設為受限制的,可以使用–-access public 釋出的時候設定許可權為公開

$ npm publish --access public
複製程式碼

npm社群版本號規則採用的是semver(語義化版本),主要規則如下:

版本格式:主版號.次版號.修訂號

版號遞增規則如下:

  • 主版號:當你做了不相容的 API 修改,
  • 次版號:當你做了向下相容的功能性新增,
  • 修訂號:當你做了向下相容的問題修正。
  • 先行版號及版本編譯資訊可以加到「主版號.次版號.修訂號」的後面,作為延伸

新增個性化徽章

推薦 shields.io/

為專案新增上各種各樣的徽章,例如:

  • 測試是否通過以及程式碼覆蓋率情況
  • 專案的最新版本
  • 專案的被使用情況
  • 程式碼風格
  • 專案的開源協議
2018-04-04-17-34-28

示例專案

該專案包含教程所有的完整配置

Github地址: github.com/eteplus/typ…

相關連結

相關文章