发布一个 npm 包,构建自己的第三方库

发布一个npm包,构建自己的第三方库

前言

小生在需要发布自己npm包时,见网上诸多教程,皆无法满足所思需求;不是太简单,就是缺三少四,故前往各大厂商之GitHub,耐心翻阅其源码,始有心得;特此做博客以记,与诸君共勉。

如果你需要进行快速搭建自己的第三方库,请移步:npm-plugins-building-shell 或者 借用shell,快速搭建一个npm插件库

申请一个npm 账号 以及创建好相关 github 项目

前往申请 npm 账号: https://www.npmjs.com/

此处本人创建的 github 项目名字为my-npm-libs,你需要另外重新起个名字。

本地创建 npm 项目

我们需要创建自己npm项目。


mkdir my-npm-libs # 创建文件夹,注意此处的名字和你上面创建的GitHub项目名称保持一致
cd my-npm-libs # 进入文件
# 此处使用 -y 可以跳过后面让你填写内容操作,所有内容都是用默认值就好,有需要的话回头可以在package.json 文件中进行修改
npm init -y # 默认配置

这里我们选择的是默认配置npm init -y,如果,你需要进行更详细的配置请使用:

npm init

使用npm init的结果如图:

npm init result

查看npm init文档,以查看更多详细内容。

npm 项目目录

mkdir examples lib src test # 创建所需目录
touch .babelrc .gitignore README.md # 创建所需文件
touch examples/index.html src/index.js test/index.js

目录如下:

.
├── examples/                         // 目录: 放置案例文件
│   ├── index.html                    // 文件: 案例运行结果
├── lib/                              // 目录: 放置 script 引用的文件
├── src/                              // 目录: 库目录
│   ├── index.js                      // 文件: 库内容
├── test/                             // 目录: 放置单元测试文件
│   ├── index.js                      // 文件: 测试内容
.babelrc
.gitignore
package.json
README.md

相关配置(请按照顺序进行配置)

src/index.js 库内容

我们的包需要支持如下三种引用方式:

import引用

import ... from '...'

require引用

const ... = require('...')

标签引用

<script src="..."></script>

此处我们使用自己写的,获取数据类型的方法:

// 获取数据类型
(function (root, globalName, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD:
    define([], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node:
    module.exports = factory();
    // Use module export as simulated ES6 default export:(将模块导出用作模拟ES6默认导出)
    module.exports.default = module.exports;
  } else {
    // Browser:
    window[globalName] = factory();
  }
}(this, 'dataType', function () {
  'use strict';

  return function dataType (data) {
    return ({}).toString.call(data).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
  }
}));

babel配置

由于,目前绝大部分的浏览器只支持ES5,故此我们需要把ES5以上的语法�转换为ES5,我们需要引用babel。不了解babel的请移步babel 官网

如果你不需要进行语法转换则跳过此babel配置步骤。

我们需要配置babel,这里由于babel的更新babel的配置基本分为两类:
1.babel6.X 以及其以下版本
2.babel7.X 以及其以上版本

babel6.X以及其以下版本的配置

安装 Babel 命令行工具(babel-cli)以及一种 Babel preset

npm install --save-dev babel-cli babel-preset-env

创建一个 .babelrc 文件(或者使用你的 package.json 文件):我们上面已经创建过了的话,此处不必再进行创建。

{
  "presets": ["env"]
}

由于 Babel 只进行语法转换(如箭头函数),你可以使用 babel-polyfill 来支持新的全局变量,如 Promise 或新的原生方法,如 String.padStart(left-pad)。它使用了 core-jsregenerator
安装 babel-polyfill

npm install --save-dev babel-polyfill

运行此命令将所有代码从 src 目录编译到 lib

./node_modules/.bin/babel src --out-dir lib

babel7.X以及其以上版本的配置

安装 Babel 命令行工具(@babel/cli)、Babel核心以及一种 @babel preset :

npm install --save-dev @babel/core @babel/cli @babel/preset-env

在项目的根目录中创建名为 babel.config.js 的配置文件:

const presets = [
  ["@babel/env", {
    targets: {
      edge: "17",
      firefox: "60",
      chrome: "67",
      safari: "11.1"
    },
    useBuiltIns: "usage"
  }]
]; // 上面的浏览器列表只是用于展示的示例。你必须根据想要支持的浏览器进行调整。

@babel/polyfill 模块包括 core-js 和自定义 regenerator runtime 来模拟完整的 ES2015+ 环境。
这意味着你可以使用像 PromiseWeakMap 这样的新内置函数,像 Array.fromObject.assign 这样的静态方法,像 Array.prototype.includes 这样的实例方法,以及 generator 函数(提供给你使用 regenerator 插件)。
安装@babel/polyfill

npm install --save @babel/polyfill

运行此命令将所有代码从 src 目录编译到 lib

./node_modules/.bin/babel src --out-dir lib

.gitignore的配置

.DS_Store
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln

package.json的配置

{
  "name": "my-npm-libs",
  "description": "发布一个npm包,构建自己的第三方库",
  "version": "1.0.1",
  "author": "nongshuqiner <ym1185509297@163.com>",
  "license": "MIT",
  "main": "src/index.js",
  "files": [
    "examples",
    "lib",
    "src",
    "test"
  ],
  "private": false,
  "scripts": {
    "test": "mocha --recursive",
    "examples": "open ./examples/index.html",
    "build": "./node_modules/.bin/babel src --out-dir lib"
  },
  "keywords": [
    "my-npm-libs"
  ],
  "homepage": "https://github.com/nongshuqiner/my-npm-libs.git",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/nongshuqiner/my-npm-libs.git"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "chai": "^4.2.0",
    "mocha": "^5.2.0"
  }
}

examples/index.html的配置

在配置 examples/index.html 前需要运行如下命令:

./node_modules/.bin/babel src --out-dir lib
# 或者,由于我们在 package.json 中,已经配置了,故此也可以使用下面这个命令构建
npm run build

examples/index.html的内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>my-npm-libs</title>
  </head>
  <body>
    <div id="examples">
      <div class="">
        var a = [1, 2, 3, 4, 1, 5, 1, 7],a的数据类型是什么?
      </div>
      <div id="result"></div>
    </div>
    <script src="../lib/index.js"></script>
    <script>
      console.log(window.dataType);
      var a = [1, 2, 3, 4, 1, 5, 1, 7];
      var result = document.getElementById('result');
      result.innerHTML = dataType(a);
    </script>
  </body>
</html>

我们可以通过如下命令进行案例查看:

npm run examples

README.md的配置

# XXX(组件名)

## 概述

...

## Install(安装)

npm install --save ...

## Usage(使用)

...

... 其他内容 ...

## Donation

...

## Contact me(联系我)

...

## License

[MIT](http://opensource.org/licenses/MIT) Copyright (c) 2018 - forever Naufal Rabbani

test 单元测试

至于单元测试你可以另外请自行选择相关库进行测试,也可以按照我的习惯进行测试。

在测试前你需要了解一下mochachai这两个库,这里放上教程你可以看看:测试框架 Mocha 实例教程

安装 mochachai

npm install --save-dev mocha chai

test/index.js:

// 断言库 chai.js
var expect = require('chai').expect;
var dataType = require('../src/index');

// 测试脚本里面应该包括一个或多个describe块,称为测试套件(test suite)
describe('基本数据类型', function () {
  // 每个describe块应该包括一个或多个it块,称为测试用例(test case)
  // 基本数据类型
  it('undefined-类型检测测试', () => {
    // 断言
    expect(dataType(undefined)).to.equal('undefined');
  });
  it('null-类型检测测试', () => {
    expect(dataType(null)).to.equal('null');
  });
  it('string-类型检测测试', () => {
    expect(dataType('abc')).to.equal('string');
  });
  it('boolean-类型检测测试', () => {
    expect(dataType(true)).to.equal('boolean');
  });
  it('number-类型检测测试', () => {
    expect(dataType(1)).to.equal('number');
  });
});

describe('引用数据类型', function () {
  it('array-类型检测测试', () => {
    expect(dataType([1])).to.equal('array');
  });
  it('object-类型检测测试', () => {
    expect(dataType({})).to.equal('object');
  });
  it('function-类型检测测试', () => {
    expect(dataType(function () {})).to.equal('function');
  });
});

describe('其他数据类型', function () {
  it('date-类型检测测试', () => {
    expect(dataType(new Date())).to.equal('date');
  });
  it('regex-类型检测测试', () => {
    expect(dataType(new RegExp("\\w+"))).to.equal('regexp');
  });
});

通过命令行测试:

npm run test

结果如下:

$ npm run test

> my-npm-libs@1.0.1 test /Users/yanmo/Public/mynpm/my-npm-libs
> mocha --recursive



  基本数据类型
    ✓ undefined-类型检测测试
    ✓ null-类型检测测试
    ✓ string-类型检测测试
    ✓ boolean-类型检测测试
    ✓ number-类型检测测试

  引用数据类型
    ✓ array-类型检测测试
    ✓ object-类型检测测试
    ✓ function-类型检测测试

  其他数据类型
    ✓ date-类型检测测试
    ✓ regex-类型检测测试


  10 passing (12ms)

至此一个基本的简单的npm第三方库构建完成。下面我们进行其他的发布工作。

发布 npm 包

进入项目根目录,登录刚刚申请的npm 账号。登录完成以后执行提交。

npm login # 登陆

npm publish # 发布

发布npm包的时候需要注意把npm仓库镜像库,从国内的淘宝源切换到npm国外源,不然无法提交。

这里我做了一个shell文件,用以简化你的提交操作,你在根目录下新建一个文件npm-publish.sh,内容如下:

#!/usr/bin/env bash

echo "\033[0;32m?\033[0m \033[36m请输入你的新发布的版本号(ex:1.0.0):\033[0m"

read version

# 处理 package.json
sed -i -e "s/\"version\": \(.*\)/\"version\": \"$version\",/g" 'package.json'
if [ -f "package.json-e" ];then
  rm 'package.json-e'
fi
echo '\033[36m版本号修改成功\033[0m'

npm config get registry # 检查仓库镜像库

npm config set registry=http://registry.npmjs.org # 设置仓库镜像库: 淘宝镜像https://registry.npm.taobao.org

echo '\033[36m请进行登录相关操作:\033[0m'

npm login # 登陆

echo "-------\033[36mpublishing\033[0m-------"

npm publish # 发布

npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像

echo "\033[36m 完成 \033[0m"
exit

然后,可以通过如下命令运行:

sh npm-publish.sh

执行效果如图:

sh npm-publish.sh结果

当你的npm包发布后,可以通过如下格式的内容访问到你的包:

unpkg.com/:package@:version/:file

访问结果如图:

unpkg.com

这也意味着你可以通过<script>标签的形式访问你的包,我猜你需要了解:UNPKG

git提交

git init
git add -A
git commit -m "first commit"
git remote add origin XXX
git push -u origin master

Usage(使用)

发布成功后就可以使用了。使用有两种形式,一种是 npm 安装,一种是 <script> 引用。

npm 安装:

npm install --save my-npm-libs
import myNpmLibs from 'my-npm-libs'
var a = [1, 2, 3, 4, 1, 5, 1, 7]
console.log(myNpmLibs(a)) // array
// 或者
const myNpmLibs = require('my-npm-libs')
var a = [1, 2, 3, 4, 1, 5, 1, 7]
console.log(myNpmLibs(a)) // array

<script>使用

<script src="//unpkg.com/my-npm-libs@1.0.2/lib/index.js"></script>
<script>
  console.log(window.dataType);
  var a = [1, 2, 3, 4, 1, 5, 1, 7];
  console.log(dataType(a));
</script>

run(运行)

# git clone ...
git clone https://github.com/nongshuqiner/my-npm-libs.git

# enter
cd my-npm-libs

# install dependencies
npm install

# open examples HTML
npm run examples

# 运行此命令将所有代码从 src 目录编译到 lib
npm run build

# 测试
npm run test

Donation(打赏)

payment-code.png

Contact me(联系我)

Just Contact Me At:

结语

至此,我们发布的包的工作就彻底完成了。

我参考学习了很多的其他的第三方库以及工具网站,这里放上一些链接供大家参考:

unpkg
b64-to-blob
The anatomy of a vanilla JavaScript plugin
如何定义一个高逼格的原生JS插件
How to write and build JS libraries in 2018
Building Your Own JavaScript Modal Plugin
How to write a frontend JavaScript plugin using ES6 + SASS + Webpack

在发布之前可以将这整个目录扔到另一个项目的 node_modules 文件夹中来测试我们写的功能是否正确。

提示:后面还有精彩敬请期待,请大家关注我的专题:web前端。如有意见可以进行评论,每一条评论我都会认真对待。觉得有用却不点赞的,隔壁老X送来问候。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容