【npm】使用verdaccio和cnpm分别部署npm私服

前言

  • verdaccio看起来比cnpm要轻量,反正先部署着玩玩。

官网

  • verdaccio https://github.com/verdaccio/verdaccio
  • 这个文档有中文的:https://verdaccio.org/docs/en/configuration
  • cnpm https://github.com/cnpm/cnpmjs.org

Verdaccio

  • 先搞这个,这个看官网有docker,直接拉docker就能部署成功,实在太方便了。
docker pull verdaccio/verdaccio
docker run -itd --rm --name verdaccio -p 4873:4873 verdaccio/verdaccio
  • 如果有配置需要,加入数据卷,这玩意用/bin/bash进不去:
V_PATH=/path/for/verdaccio; docker run -it --rm --name verdaccio \
  -p 4873:4873 \
  -v $V_PATH/conf:/verdaccio/conf \
  -v $V_PATH/storage:/verdaccio/storage \
  -v $V_PATH/plugins:/verdaccio/plugins \
  verdaccio/verdaccio
  • 然后访问4873则会显示画面:
    【npm】使用verdaccio和cnpm分别部署npm私服_第1张图片
  • 然后我们试着在私服上发个包。
  • 使用命令:
 npm adduser --registry http://localhost:4873
  npm publish --registry http://localhost:4873
  • 然后刷新,就看见发布成功了:
    【npm】使用verdaccio和cnpm分别部署npm私服_第2张图片
  • 然后找个空文件夹下载下来试试
npm install  yehuozhili  --registry=http://localhost:4873
  • 然后ok
    在这里插入图片描述

CNPM

  • cnpm也提供docker的方式,太方便了。
  • 直接clone代码后使用docker-compose up d即可自己拉取镜像部署。
  • 完成后会启动2个docker,一个是内网3306的mysql一个是web,这个web可以用/bin/bash进去,那就想咋整咋整了。私服地址是7001,访问地址是7002,所以npm配地址时候就配7001
  • 要关就:
$docker-compose rm
$docker volume rm cnpmjsorg_cnpm-files-volume
$docker volume rm cnpmjsorg_cnpm-db-volume
  • 访问7002即可看见:
    【npm】使用verdaccio和cnpm分别部署npm私服_第3张图片
  • 我们试着发个包上去。这里不能发送普通包,要发送作用域包否则会报403:
 [no_perms] only allow publish with @cnpm, @cnpmtest, @cnpm-test scope(s)
  • 作用域包不限定名字,但是搜索的话,只能搜到上述开头的作用域包:
    【npm】使用verdaccio和cnpm分别部署npm私服_第4张图片
  • 下载倒是都可以下载

配置文件

verdaccio

#
# 这是默认的配置文件. 它会允许我们做任何事情,
# 所以不要在生产环境(系统)使用它.
#
# 在这里可以看见更多的配置示例:
# https://github.com/verdaccio/verdaccio/tree/master/conf
#

# 包含所有包的目录路径,npm私服包的存放目录以及缓存地址
storage: ./storage
# 包含plugins的目录路径,默认插件的文件位置,一般只对docker部署有关系
plugins: ./plugins

web:  #verdaccio的界面
  title: Verdaccio
  # comment out to disable gravatar support 注释掉gravatar禁止使用
  # gravatar: false
  # by default packages are ordercer ascendant (asc|desc)  默认的packages是准备好的两个选择
  # sort_packages: asc
  # convert your UI to the dark side  用户界面是黑夜模式
  # darkMode: true

# translate your registry, api i18n not available yet  看看下你的注册表,i18n api还不能使用
# i18n:
# list of the available translations 查看可以使用的注册列表的地址:https://github.com/verdaccio/ui/tree/master/i18n/translations
#   web: en-US

auth:  
  htpasswd:
    file: ./htpasswd  #保存用户的账号信息比如用户名,密码等,还没有注册或者登录的话暂时看不到
    # Maximum amount of users allowed to register, defaults to "+inf".允许注册的最大用户数量,可以是无穷大
    # You can set this to -1 to disable registration. 你可以设置-1去禁止用户通过 npm adduser 去注册
    # max_users: 1000  #默认注册人数最大数量是1000

# a list of other known repositories we can talk to  我们需要了解其他相关有名的存储库
uplinks: #配置上游的npm服务器,主要用于请求的库不存在时可以去到上游服务器去获取,可以多配置下上游链路的链接
  npmjs:
    url: https://registry.npmjs.org/
    agent_options:  #代理的配置项
      keepAlive: true 
      maxSockets: 40
      maxFreeSockets: 10

packages: # 配置模块,access访问下载权限,pushlish包的发布权限
  '@*/*': # 一种是@/表示某下面所属的某项目,关键字匹配
    # scoped packages   配置权限管理
    access: $all # 表示哪一类用户可以对匹配的项目进行安装(install)和查看包的信息
    publish: $authenticated # 表示哪一类用户可以对匹配的项目进行发布(publish)
    unpublish: $authenticated # 表示哪一类用户可以对匹配的项目进行卸载(publish)
    proxy: npmjs # 这里的值是对应于 uplinks 的名称,如果本地不存在,允许去对应的uplinks去拉取

  '**': # 另一种是*匹配项目名称(名称在package.json中有定义)
    # allow all users (including non-authenticated users) to read and
    # publish all packages
    # 允许所有用户(包括未经身份验证的用户)读取和发布所有包
    # you can specify usernames/groupnames (depending on your auth plugin) 您可以指定用户名/组织名称(取决于验证身份的插件)
    # and three keywords: "$all", "$anonymous", "$authenticated" 三个关键字:所有的,匿名的,验证过的  也可以使用具体的用户名或者组织名称(公司私有的名字)和配置的用户表 htpasswd 有关
    access: $all

    # allow all known users to publish/publish packages 允许所有用户去发布包
    # (anyone can register by default, remember?)  任何人都可以默认注册
    publish: $authenticated
    unpublish: $authenticated

    # if package is not available locally, proxy requests to 'npmjs' registry 如果包不允许在本机使用,可以用proxy请求npmjs注册表的代理
    proxy: npmjs

# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections. 传入的指定连接的HTTP/1.1服务器保持活跃状态直到超时,以秒为单位
# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.  值为0的时候的服务表现行为和8.0.0之前版本的nodejs链接的时候没有保持活跃状态导致超时
# WORKAROUND: Through given configuration you can workaround following issue  解决办法:通过已知的配置,你可以解决这些问题: https://github.com/verdaccio/verdaccio/issues/301. Set to 0 in case 60 is not enough.  如果60不够的话可以设置为0
server:
  keepAliveTimeout: 60 

middlewares:
  audit:
    enabled: true

# log settings  设置日志
logs:
  - {
      type: stdout, format: pretty, level: http }
  #- {
     type: file, path: verdaccio.log, level: info}
#experiments: 实验性的
#  # support for npm token command  支持npm的token令牌
#  token: false
#  # support for the new v1 search endpoint, functional by incomplete read more on ticket 1732
#  search: false
#  # disable writing body size to logs, read more on ticket 1912
#  bytesin_off: false

# This affect the web and api (not developed yet) 这些会影响web和api(尚未开发的功能)
#i18n:
#web: en-US

#默认是没有的,只能在本机访问,添加后可以通过外网访问
listen:0.0.0.0:4873

cnpm

/*
 * server configure //服务器配置
 */

registryPort: 7001,         //仓库访问端口(执行发布安装)
webPort: 7002,              //展示查询站点访问端口
bindingHost: '',            //监听绑定的 Host,默认127.0.0.1,外网访问注释掉此项即可


/**
* database config           //数据库相关设置
*/

database: {
     
    db: 'cnpmjs',           //数据库名称
    username: 'root',       //数据库访问账号
    password: '123456',     //数据库访问密码

    // the sql dialect of the database  数据库支持的类型
    // - currently supported: 'mysql', 'sqlite', 'postgres', 'mariadb'
    dialect: 'mysql',       //使用数据库,默认sqlite,这里我们改成mysql

    // custom host; default: 127.0.0.1
    host: '127.0.0.1',      //数据库访问IP,通常127.0.0.1

    // custom port; default: 3306
    port: 3306,             //数据库访问端口,通常3306

  // 数据库连接池使用默认配置就好
  // 目前只支持  mysql 和 postgresql (since v1.5.0)
  pool: {
     
    maxConnections: 10,
    minConnections: 0,
    maxIdleTime: 30000
//...

// 模块文件存储,默认将发布的私有模块跟缓存公共模块存储在本地文件系统中,路径~/.cnpmjs.org/nfs ,也就是模块文件都存储在这个目录下;或者可以选择三方储存方式比如七牛等,着这里配置插件;也支持接口开发扩展储存;

nfs: require('fs-cnpm')({
     
    dir: path.join(dataDir, 'nfs')
}),

// registry url name        //模块注册列表访问域名,默认r.cnpmjs.org,安装模块时会到这个域名下查找,这个默认设置略坑,建议没有外网域名的先清空回头再配
registryHost: '',


// default system admins    //默认管理员账号
  admins: {
     
    // name: email
    //fengmk2: '[email protected]',
    admin: '[email protected]',
    //dead_horse: '[email protected]',
  },


/*
 * registry mode config  私有模块发布相关配置
*/

  //是否开启私有模式,默认为 false;
  //私有模式下只有管理员能发布模块,其他账号只有同步权限
  //非私有模式,注册用户都可以发布模块
  enablePrivate: false, 

  // registry scopes
  //若为非私有模式发布则此项必填,非管理员发布模块式命名必须以scopes字段开头,模块命名示例“@cnpm/packagename”
  //更多了解npm-scope请查阅https://docs.npmjs.com/misc/scope
  scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test' ],

  // 私有模块非scopes白名单,各种非以scope方式发布的老模块的白名单管理,数组形式维护
  privatePackages: [],


/**
* sync configs 同步源仓库相关设置
*/

//npm官方registry地址,不会直接从这个地址同步模块,但有时会从这里获取模块信息,除非必要请勿更改
officialNpmRegistry: 'https://registry.npmjs.com',
officialNpmReplicate: 'https://replicate.npmjs.com',

//同步模块上游registry地址
sourceNpmRegistry: 'https://registry.npm.taobao.org',

//上游registry是否是cnpm,默认true,若要使用npm官方地址作为同步上游,请设置为false
sourceNpmRegistryIsCNpm: true,

//若安装时模块不存在,是否向源registry进行同步,默认true
syncByInstall: true,

// 同步模式选项
// none: 不进行同步,只管理用户上传的私有模块,公共模块直接从上游获取
// exist: 只同步已经存在于数据库的模块
// all: 定时同步所有源registry的模块
syncModel: 'none', // 'none', 'all', 'exist'

// 同步时间间隔,默认10分钟
syncInterval: '10m',


// 是否同步模块中devDependencies,默认false
syncDevDependencies: false,

//用户账号系统接入,可以扩展接入公司的账号系统
//详见https://github.com/cnpm/cnpmjs.org/wiki/Use-Your-Own-User-Authorization
userService: null,
enableAbbreviatedMetadata: true,
'use strict';

var mkdirp = require('mkdirp');
var copy = require('copy-to');
var path = require('path');
var fs = require('fs');
var os = require('os');
var utility = require('utility');

var version = require('../package.json').version;

var root = path.dirname(__dirname);
var dataDir = path.join(process.env.HOME || root, '.cnpmjs.org');

var config = {
     
  version: version,
  dataDir: dataDir,

  /**
   * Cluster mode   集群模式
   */
  enableCluster: false,   //是否启用 cluster-worker 模式启动服务,默认 false,生产环节推荐为 true;
  numCPUs: os.cpus().length,

  /*
   * server configure  服务器配置
   */

  registryPort: 7001,   //仓库访问端口(执行发布安装的网址)
  webPort: 7002,        //展示查询站点访问端口(可视化页面的查询)
  bindingHost: '127.0.0.1', // only binding on 127.0.0.1 for local access 监听绑定的 Host,默认127.0.0.1,外网访问注释掉此项即可
  // default is ctx.protocol  
  protocol: '',

  // debug mode  调试模式
  // if in debug mode, some middleware like limit wont load  如果在调试模式下,某些中间件如限制负载
  // logger module will print to stdout 日志模块打印出来
  debug: process.env.NODE_ENV === 'development',
  // page mode, enable on development env
  pagemock: process.env.NODE_ENV === 'development',
  // session secret
  sessionSecret: 'cnpmjs.org test session secret',
  // max request json body size
  jsonLimit: '10mb',
  // log dir name  日志目录
  logdir: path.join(dataDir, 'logs'),
  // update file template dir 临时上传文件
  uploadDir: path.join(dataDir, 'downloads'),
  // web page viewCache  视图模板缓存是否开启,默认是false
  viewCache: false,

  // registry http response cache control header
  // if you are using CDN, can set it to 'max-age=0, s-maxage=10, must-revalidate'
  // it meaning cache 10s on CDN server and no cache on client side.
  registryCacheControlHeader: '',
  // if you are using CDN, can set it to 'Accept, Accept-Encoding'
  registryVaryHeader: '',
  // disable package search
  disableSearch: false,

  // view files directory
  viewDir: path.join(root, 'view', 'web'),

  customRegistryMiddlewares: [],
  customWebMiddlewares: [],

  // config for koa-limit middleware
  // for limit download rates
  limit: {
     
    enable: false,
    token: 'koa-limit:download',
    limit: 1000,
    interval: 1000 * 60 * 60 * 24,
    whiteList: [],
    blackList: [],
    message: 'request frequency limited, any question, please contact [email protected]',
  },

  enableCompress: false, // enable gzip response or not  是否开启 gzip 压缩,默认为 false

  // default system admins 默认系统管理员
  admins: {
     
    // name: email 
    fengmk2: '[email protected]',
    admin: '[email protected]',
    dead_horse: '[email protected]',
  },

  // email notification for errors  错误时会用电子邮件通知
  // check https://github.com/andris9/Nodemailer for more informations
  mail: {
     
    enable: false,   
    appname: 'cnpmjs.org',
    from: 'cnpmjs.org mail sender ',
    service: 'gmail',
    auth: {
     
      user: '[email protected]',
      pass: 'your password'
    }
  },

  logoURL: 'https://os.alipayobjects.com/rmsportal/oygxuIUkkrRccUz.jpg', // cnpm logo image url
  adBanner: '',
  customReadmeFile: '', // you can use your custom readme file instead the cnpm one
  customFooter: '', // you can add copyright and site total script html here
  npmClientName: 'cnpm', // use `${name} install package`
  packagePageContributorSearch: true, // package page contributor link to search, default is true

  // max handle number of package.json `dependencies` property
  maxDependencies: 200,
  // backup filepath prefix
  backupFilePrefix: '/cnpm/backup/',

  /**
   * database config  数据库配置
   */

  database: {
     
    db: 'cnpmjs_test',  //数据库名称
    username: 'root',   //数据库访问账号
    password: '',       //数据库访问密码

    // the sql dialect of the database  //使用数据库,默认sqlite
    // - currently supported: 'mysql', 'sqlite', 'postgres', 'mariadb'
    dialect: 'sqlite',

    // custom host; default: 127.0.0.1  数据库访问IP,通常127.0.0.1
    host: '127.0.0.1',

    // custom port; default: 3306
    port: 3306,   //数据库访问端口,通常3306

    // use pooling in order to reduce db connection overload and to increase speed
    // currently only for mysql and postgresql (since v1.5.0)
    pool: {
      //数据库连接池相关配置,为一个对象;
      maxConnections: 10, //最大连接数,默认为 10
      minConnections: 0,  //最小连接数,默认为 0
      maxIdleTime: 30000  //单条链接最大空闲时间,默认为 30000 毫秒
    },

    dialectOptions: {
     
      // if your server run on full cpu load, please set trace to false 如果您的服务器在满cpu负载下运行,请将trace设置为false
      trace: true,
    },
	//仅对 SQLite 配置有效,数据库地址,默认为 ~/.cnpmjs/data.sqlite
    // the storage engine for 'sqlite'
    // default store into ~/.cnpmjs.org/data.sqlite
    storage: path.join(dataDir, 'data.sqlite'),

    logging: !!process.env.SQL_DEBUG,
  },

  // enable proxy npm audits request or not
  enableNpmAuditsProxy: true,
  //包文件系统处理对象,为一个 Node.js 对象,默认是 fs-cnpm 这个包,并且配置在 ~/.cnpmjs/nfs 目录下,也就是说默认所有同步的包都会被放在这个目录下
  // package tarball store in local filesystem by default 默认情况下,包存储在本地文件系统中
  nfs: require('fs-cnpm')({
     
    dir: path.join(dataDir, 'nfs')
  }),
  // if set true, will 302 redirect to `nfs.url(dist.key)`
  downloadRedirectToNFS: false,
  // don't check database and just download tgz from nfs
  downloadTgzDontCheckModule: false,
  // remove original tarball when publishing
  unpublishRemoveTarball: true,

  // registry url name
  registryHost: 'r.cnpmjs.org',  

  /**
   * registry mode config  私有模块发布相关配置
   */

  // enable private mode or not  是否开启私有模式,默认为 false
  // private mode: only admins can publish, other users just can sync package from source npm  私有模式下只有管理员能发布模块,其他账号只有同步权限
  // public mode: all users can publish  非私有模式,注册用户都可以发布模块
  enablePrivate: false,

    
   //非管理员发布包的时候只能用以 scopes 里面列举的命名空间为前缀来发布,如果没有设置就无法发布,也就是说这是一个必填项,默认为 [ '@cnpm', '@cnpmtest', '@cnpm-test' ],据苏千大大解释是为了便于管理以及让公司的员工自觉按需发布;更多关于 NPM scope 的说明请参见 npm-scope
  // registry scopes, if don't set, means do not support scopes
  scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test' ],

  // some registry already have some private packages in global scope  某些注册表在全局范围内已经有一些私有包
  // but we want to treat them as scoped private packages,  但我们希望将它们视为作用域私有包
  // so you can use this white list. 所以可以用这个白名单
  //出于历史包袱的原因,有些已经存在的私有包(可能之前是用 Git 的方式安装的)并没有以命名空间的形式来命名,而这种包本来是无法上传到 CNPM 的,这个配置项数组就是用来加这些例外白名单的,默认为一个空数组
  privatePackages: [],

  /**
   * sync configs  同步源仓库相关设置
   */

  // the official npm registry  npm官方注册
  // cnpm wont directly sync from this one  cnpm不会直接从这个地址同步模块
  // but sometimes will request it for some package infomations 但有时会要求它提供一些package信息
  // please don't change it if not necessary   如果没有必要性的话,请不要更改
  officialNpmRegistry: 'https://registry.npmjs.com',
  officialNpmReplicate: 'https://replicate.npmjs.com',
  cnpmRegistry: 'https://r.cnpmjs.com',

  // sync source, upstream registry  同步源,上游注册表
  // If you want to directly sync from official npm's registry  如果你想直接从官方npm的注册表同步
  // please drop them an email first  首先给他们发邮件
  sourceNpmRegistry: 'https://registry.npm.taobao.org',
  sourceNpmWeb: 'https://npm.taobao.org',

  // upstream registry is base on cnpm/cnpmjs.org or not  上游registry是否是cnpm,默认true
  // if your upstream is official npm registry, please turn it off 若要使用npm官方地址作为同步上游,请设置为false
  sourceNpmRegistryIsCNpm: true,

  // if install return 404, try to sync from source registry 若安装时模块不存在,是否向源registry进行同步,默认true
  syncByInstall: true,

  // sync mode select  同步模式选项
  // none: do not sync any module, proxy all public modules from sourceNpmRegistry
  //none: 不进行同步,只管理用户上传的私有模块,公共模块直接从上游获取
  // exist: only sync exist modules
  //exist: 只同步已经存在于数据库的模块
  // all: sync all modules
   //all: 定时同步所有源registry的模块
  syncModel: 'none', // 'none', 'all', 'exist'

  syncConcurrency: 1,
  // sync interval, default is 10 minutes  同步时间间隔,默认10分钟
  syncInterval: '10m',

  // sync polular modules, default to false
  // because cnpm can't auto sync tag change for now
  // so we want to sync popular modules to ensure their tags
  syncPopular: false,
  syncPopularInterval: '1h',
  // top 100
  topPopular: 100,

  // sync devDependencies or not, default is false 是否同步devDependencies,默认值为fals
  syncDevDependencies: false,
  // try to remove all deleted versions from original registry 尽量从原始注册表中删除所有已删除的版本
  syncDeletedVersions: true,

  // changes streaming sync
  syncChangesStream: false,
  syncDownloadOptions: {
     
    // formatRedirectUrl: function (url, location)
  },
  handleSyncRegistry: 'http://127.0.0.1:7001',

  // default badge subject
  badgeSubject: 'cnpm',  //包的 badge 显示的名字,默认为 cnpm
  // defautl use https://badgen.net/
  badgeService: {
     
    url: function(subject, status, options) {
     
      options = options || {
     };
      let url = `https://badgen.net/badge/${
       utility.encodeURIComponent(subject)}/${
       utility.encodeURIComponent(status)}`;
      if (options.color) {
     
        url += `/${
       utility.encodeURIComponent(options.color)}`;
      }
      if (options.icon) {
     
        url += `?icon=${
       utility.encodeURIComponent(options.icon)}`;
      }
      return url;
    },
  },

  packagephobiaURL: 'https://packagephobia.now.sh',
  packagephobiaSupportPrivatePackage: false,
  packagephobiaMinDownloadCount: 1000,

  // custom user service, @see https://github.com/cnpm/cnpmjs.org/wiki/Use-Your-Own-User-Authorization
  // when you not intend to ingegrate with your company's user system, then use null, it would
  // use the default cnpm user system
   //用户账号系统接入,可以扩展接入公司的账号系统
  userService: null,

  // always-auth https://docs.npmjs.com/misc/config#always-auth
  // Force npm to always require authentication when accessing the registry, even for GET requests.
    //是否始终需要用户验证,即便是 $ cnpm install 等命令
  alwaysAuth: false,

  // if you're behind firewall, need to request through http proxy, please set this
  // e.g.: `httpProxy: 'http://proxy.mycompany.com:8080'
    //代理地址设置,用于你在墙内源站在墙外的情况
  httpProxy: null,

  // snyk.io root url
  snykUrl: 'https://snyk.io',

  // https://github.com/cnpm/cnpmjs.org/issues/1149
  // if enable this option, must create module_abbreviated and package_readme table in database
  enableAbbreviatedMetadata: false,

  // global hook function: function* (envelope) {}
  // envelope format please see https://github.com/npm/registry/blob/master/docs/hooks/hooks-payload.md#payload
  globalHook: null,

  opensearch: {
     
    host: '',
  },

  // redis cache
  redisCache: {
     
    enable: false,
    connectOptions: null,
  },
};

if (process.env.NODE_ENV === 'test') {
     
  config.enableAbbreviatedMetadata = true;
  config.customRegistryMiddlewares.push(() => {
     
    return function* (next) {
     
      this.set('x-custom-middleware', 'true');
      yield next;
    };
  });

  config.customWebMiddlewares.push(() => {
     
    return function* (next) {
     
      this.set('x-custom-web-middleware', 'true');
      yield next;
    };
  });
}

if (process.env.NODE_ENV !== 'test') {
     
  var customConfig;
  if (process.env.NODE_ENV === 'development') {
     
    customConfig = path.join(root, 'config', 'config.js');
  } else {
     
    // 1. try to load `$dataDir/config.json` first, not exists then goto 2.
    // 2. load config/config.js, everything in config.js will cover the same key in index.js
    customConfig = path.join(dataDir, 'config.json');
    if (!fs.existsSync(customConfig)) {
     
      customConfig = path.join(root, 'config', 'config.js');
    }
  }
  if (fs.existsSync(customConfig)) {
     
    copy(require(customConfig)).override(config);
  }
}

mkdirp.sync(config.logdir);
mkdirp.sync(config.uploadDir);

module.exports = config;

config.loadConfig = function (customConfig) {
     
  if (!customConfig) {
     
    return;
  }
  copy(customConfig).override(config);
};

你可能感兴趣的:(npm)