npm 发包和管理包及镜像源管理
将撸好的轮子发到NPM(node package manager)上很简单,只需要几个步骤 ,
登录账号
如果连账号都没有的话,点此创建。
使用 npm login
登录
根据命令行提示,输入用户名、密码、邮件地址:
$ npm login
Username: chuchur
Password:
Email: (this IS public) chuchur@qq.com
Logged in as chuchur on https://registry.npmjs.org/.
发包
如果连包都没, 那赶紧撸一个。
搞个目录, 进到里头,npm init
初始化一下
# 搞个目录
mkdir test-pkg
# 进到里头
cd tets-pkg
# 初始化
npm init
最终生成一个 package.json文件, 这个文件包含发布项目所需的必要项。
package name: (test-pkg)
version: (1.0.0)
description: this is a test pgk.
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
最后一步,用 npm publish发布该项目
npm publish
如果一个同名的包已经存在 NPM,你将发布失败!
可通过npm search 命令看是否被占用:
npm search test-pkg
非要用这个名字怎么办,发布包到scope下,可以二选一:
- 在
package.json
中,手动的修改name
为@username/package-name
- 替代
npm init
为npm init --scope=username
username 就是你的 npm 账号名
如果你的仓库有一个scope,你需要调整发布命令:
npm publish --access public
一个粗糙的发包流程就搞完了。
版本管理
升级包
发的包有bug ,我要更新包,就得重新发一个高一点的版本。
先更新版本 ,再发布
major (大版本),minor(版本),patch(小修复)
# 从 0.0.1 更新到 1.0.0
npm version major
# 从 0.0.1 更新到 0.1.0
npm version minor
# 从 0.0.1 更新到 0.0.2
npm version patch
执行版本命令之后,再发布
npm publish
废弃包
这个包, 不想维护了, 有其它的替代方案, 那......就废了它。
npm deprecate test-pkg "包有毒,不建议安装"
注意, 这个时候不是说包没有, 包还在的,在npm网站上仍然能够查到已废弃的npm包 。
废弃状态,是不能进行更新的。
删除包
这包我不要了,屎山代码见不得人,爱谁谁。
npm unpublish test-pkg -fore
# or
npm unpublish test-pkg -f
那么这个包就不见了,npm上 也找不到,屎山代码终于不被人所见, 好开森。
版本撤回
我操, 刚更新了一个小版本, 发现又造成了另外一个新的bug ,这可咋办,难不成我又要再发一个"打死不改版本2.0"吗,那要是这样, 是不是后面还有 "打死不改版本最终版本1000.0"版本呢。
不可能, 绝对不可能。。把这个有bug 的版本撤回即可。
npm unpublish test-pkg@2.0.3
以上撤回有bug的2.0.3 版本。
发包前的准备和辅助工具NP
- 首先得有个包
- 包 remote了 git仓库
- 至少已经push到 remote 至少一次
- 工作目录是干净的(已经commit and push)
- 更新版本号
- 给代码(屎山)创建 git tag
- 给代码(屎山)创建 release notes
以上这准备做好了, 才可以发一个正式的包。
发包的流程都已经熟悉了, 代码没问题, npm version
然后npm publish
, 这个包就发上去了。
有一个辅助工具可以帮我们做这个事情 :NP
全局安装 np
npm install --g np
安装完成之后,准备发包前执行即可:
np
他能辅助你做的工作, - 更新版本号 - 检查test 错误 - 检查是否已经得交了代码 - 给包打tag - 发包 - 提示你写release notes
当然,你也可以不用它。自己能做的事情, 不麻烦别人。
镜像源管理(nrm)
有时候我们装一个包 , 死活安装不了, 网络问题和被墙的问题,那么一定知道cnpm
,
cnpm 是 npm 镜像源其中的一种。
npm 默认的镜像源 是 https://registry.npmjs.org/
安装 nrm
npm install -g nrm
执行 nrm ls
就可以看到:
*npm ---------- https://registry.npmjs.org/
yarn --------- https://registry.yarnpkg.com/
tencent ------ https://mirrors.cloud.tencent.com/npm/
cnpm --------- https://r.cnpmjs.org/
taobao ------- https://registry.npmmirror.com/
npmMirror ---- https://skimdb.npmjs.com/registry/
有 腾讯 淘宝镜像源 。
切换镜像源
nrm use taobao #切换成taobao的源
nrm 的一些命令:
nrm -V #查看当前nvm版本; (即:是 ‘nrm -Version’ 简写);
nrm -h #显示所有命令; (即:是 ‘nrm -help’ 简写);
nrm current #显示当前源名称;
nrm add <registry> <url> [home] #添加一个源; (比如:公司自己的私有源);
nrm set-auth <registry> <value> [always]:#设置自定义源的授权信息;
nrm set-email <registry> <value> #给自定义源设置路径;
nrm set-hosted-repo <registry> <value> #设置发布到自定义源的 ‘npm’ 托管仓储
nrm home <registry> [browser] #浏览器中打开源首页;
nrm publish [options] [<tarball>|<folder>] #发布包到自定义源,如果没有使用自定义源,则直接发布到npm;
nrm ls #查看所有的支持源(有*号的表示当前所使用的源,以下[name]表示源的名称)
nrm use [name] #将npm下载源切换成指定的源
nrm use taobao #切换成taobao的源
nrm help #查看nrm帮助
nrm home [name] #跳转到指定源的官网
nrm add name http://registry.npm.frp.trmap.cn/ #增加特定源
nrm del name #删除源
nrm test npm #测试速度
nrm test #测试所有源的速度
如果你用了cnpm 或者 其它 的源, 这个时候你发包是发不了的, 你得把源切回到npm 才可以
当然不用这个逼 ,你也可以手动设置呀,
npm config set registry http://registry.npmjs.org
那是不是切换之后,就没法改变,当然不用它,你还可以零时指定源呀
npm i kui-vue --registry http://registry.npmjs.org
这个东西是备用的,就以防不时之需。 正常时候不推荐使用。 更新不及时,会造成很多问题。
npm 常用命令
npm -v #查看版本号
npm --help #查看npm所有命令
npm adduser #添加npm账号,也可以去npm官网注册
npm owner ls <package_name> #查看模块拥有者
npm owner add <user> <package_name> #添加一个发布者
npm owner rm <user> <package_name> #删除一个发布者
npm init #构建项目说明,生成package.json文件,如果有刚安装依赖
npm view gulp versions #查看历史版本信息(最多只能显示100条)
npm view gulp versions --json #查看所有版本信息
npm view gulp version #查看最新版本信息
npm info gulp #查看所有版本及gulp的信息
npm ls gulp #查看本地安裝的gulp版本
npm ls gulp -g #查看全局安裝的gulp版本
npm i gulp@3.2.3 #安裝指定版本
npm i gulp #安装推荐的版本
npm i gulp@latest #安裝指定、最新版本
npm i A B C #同时安裝ABC三个包
npm install gulp -D #安裝到开发依赖(devDependencies字段中)
npm install gulp --save-dev #同上缩写
npm install gulp -S #安裝到生产依赖(dependencies字段中)
npm install gulp --save #同上缩写
npm install gulp@3.0.0 --save
npm update gulp #更新包
npm update gulp -g #全局更新包
npm uninstall gulp@3.0.0 --save #卸载依赖
npm un gulp@3.0.0 --save #同上缩写
npm install cnpm -g --registry=https://registry.npm.taobao.org #安装淘宝镜像
npm config list #查看npm的配置
npm config set registry https://registry.npm.taobao.org #设置淘宝镜像源
npm config set registry https://registry.npmjs.org #设置npm源
npm set disturl https://npm.taobao.org/dist #设置资源库从淘宝库获取
npm cache clean --force #清空npm本地缓存 ,用于对付使用相同版本号发布新版本代码的人
npm run dev/test/build #执行script命令
npm login #发布包时登录npm账号用的
npm publish #发布包到npm官方库
npm unpublish test #撤销已发布的包
npm unpublish test --force #强制撤销
npm unpublish test@1.0.2 #可以撤销发布自己发布过的某个版本代码
npm list -g --depth 0 #查看全局安装过的包
npm dist-tag ls #查看当前的tag和对应的version
npm dist-tag add <package_name>@<version> latest #把版本打名为 latest的tag
模块化/规范/打包
前端模块化演进
前端的模块化是一个演进的过程,经历了 4 个阶段:
- 全局 function模式 : 将不同的功能封装成不同的全局函数
- namespace模式 : 简单对象封装
- IIFE模式:匿名函数自调用(闭包)
- IIFE模式增强: 引入依赖
基本原理是将模块挂载在 window 属性下。到 IIFE 增强阶段,现在的模块化规范基本已经成型,有了明显的引入导出。如下代码的引入 jQuery 和暴露 myModule:
// module.js文件
(function(window, $) {
let data = 'www.baidu.com';
// 操作数据的函数
function foo() {
// 用于暴露有函数
console.log(`foo() ${data}`);
$('body').css('background', 'red');
otherFun(); // 内部调用
}
function otherFun() {
// 内部私有的函数
console.log('otherFun()');
}
// 暴露行为
window.myModule = { foo };
})(window, jQuery) // jQuery 作为参数引入
在此基础上,逐渐演化出了 AMD、CommonJS、CMD、UMD 等规范。
AMD(Asynchromous Module Definition - 异步模块定义)
AMD 更多用于浏览器端,需要异步加载各模块,然后再去执行内部代码。是 RequireJS 在推广过程中对模块定义的规范化产出,推崇依赖前置。
// 定义没有依赖的模块
define(function(){ return 模块 });
// 定义有依赖的模块
define(['module1', 'module2'], function(m1, m2){ return 模块 });
// 引入使用模块
require(['module1', 'module2'], function(m1, m2){ 使用m1/m2 });
CommonJS 规范
CommonJS 是服务端模块的规范,由于Node.js被广泛认知。根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的module.exports对象。
//module1.js
moudle.exports = { value: 1 };
//module2.js
var module1 = require('./module1');
var value2 = module1.value + 2;
module.exports ={ value: value2 };
CommonJS 加载模块是同步的,所以只有加载完成才能执行后面的操作。
CMD(Common Module Definition - 公共模块定义)
CMD 是 SeaJS 在推广过程中对模块定义的规范化产出,同时 CMD 也是延自 CommonJS Modules/2.0 规范。对于模块的依赖,CMD 是延迟执行,推崇依赖就近。
define((require, exports, module) => {
module.exports = {
fun1: () => {
var $ = require('jquery'); // 执行 fun1 时,再加载
return $('#test');
}
};
});
如上代码,只有当真正执行到fun1方法时,才回去执行jquery。
UMD 规范
同时同时兼容 AMD 和 CommonJS,既可以适用浏览器端,有可以适用于服务器端.
UMD 规范甚至都不能称作一个规范,它是 AMD 和 CommonJS 的一个糅合。是一段固定的代码写法。如下的工厂模式:
((root, factory) => {
if (typeof define === 'function' && define.amd) {
//AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
//CommonJS
var $ = requie('jquery');
module.exports = factory($);
} else {
//都不是,浏览器全局定义
root.testModule = factory(root.jQuery);
}
})(this, ($) => {
//do something... 这里是真正的函数体
});
ES module 规范
另一种支持服务端和浏览器端的规范就是 ES module 了,即我们现在最常用的import 和 export:
export default ...;
import xxx from '';
export ...;
import { xxx } from '';
但目前也仅是大于 13.2 的 Node.js 版本才支持 ES 模块化,还需要等待很长的时间全面使用。
所以,出于兼容性考虑,我们仍然选择 UMD 规范进行开发。(处于淘汰边缘的UMD、CMD、AMD这些规范,大家不需要理解,只需要知道有这么一回事即可)
Webpack 打包
新建 webpack 配置文件,webpack.config.js。用 webpack 给组件库打包输出符合 UMD 规范的代码,只需要在基本配置稍作修改即可:
// webpack.config.js
const path = require('path');
module.exports = {
mode: 'production',
entry: './index.js',
externals: 'lodash', // library包中有引入lodash,打包时不将lodash打进去,用户在引入该library时,需自己再引入lodash,避免用户重复引入lodash,导致文件过大。
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'library.js',
library: 'library', // 全局挂载包的引用名
libraryTarget: 'umd', //通用模式:支持用户通过es、common.js、AMD的方式引入npm包
globalObject: 'this' // node 等环境运行时需要设置为 this
}
}
要修改的地方如下:
- filename:打包产物library的名称;
- externals: ‘lodash’, library 包中有引入 lodash,打包时不将 lodash 打进去,用户在引入该 library 时,需自己再引入 lodash,避免用户重复引入 lodash,导致文件过大;
- libraryTarget: ‘umd’ 使用 UMD规范 支持用户通过 es、common.js、AMD 的方式引入 npm 包;
- library: ‘library’ 会在全局变量中增加一个liabray的变量,用于挂载该包,主要用于通过脚本形式全局引入时的配置;
- globalObject: 'this',为 webpack 4 新增属性,需要指定 global 的值为
this
,否则会为默认值self
,无法在 nodejs 环境中使用。