基于Webpack和ES6构建NPM包

7,790 阅读3分钟

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…

相关链接