前言
- 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 adduser --registry http://localhost:4873
npm publish --registry http://localhost:4873
- 然后刷新,就看见发布成功了:
- 然后找个空文件夹下载下来试试
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即可看见:
- 我们试着发个包上去。这里不能发送普通包,要发送作用域包否则会报403:
[no_perms] only allow publish with @cnpm, @cnpmtest, @cnpm-test scope(s)
- 作用域包不限定名字,但是搜索的话,只能搜到上述开头的作用域包:
- 下载倒是都可以下载
配置文件
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
registryPort: 7001,
webPort: 7002,
bindingHost: '',
database: {
db: 'cnpmjs',
username: 'root',
password: '123456',
dialect: 'mysql',
host: '127.0.0.1',
port: 3306,
pool: {
maxConnections: 10,
minConnections: 0,
maxIdleTime: 30000
nfs: require('fs-cnpm')({
dir: path.join(dataDir, 'nfs')
}),
registryHost: '',
admins: {
admin: '[email protected]',
},
enablePrivate: false,
scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test' ],
privatePackages: [],
officialNpmRegistry: 'https://registry.npmjs.com',
officialNpmReplicate: 'https://replicate.npmjs.com',
sourceNpmRegistry: 'https://registry.npm.taobao.org',
sourceNpmRegistryIsCNpm: true,
syncByInstall: true,
syncModel: 'none',
syncInterval: '10m',
syncDevDependencies: false,
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,
enableCluster: false,
numCPUs: os.cpus().length,
registryPort: 7001,
webPort: 7002,
bindingHost: '127.0.0.1',
protocol: '',
debug: process.env.NODE_ENV === 'development',
pagemock: process.env.NODE_ENV === 'development',
sessionSecret: 'cnpmjs.org test session secret',
jsonLimit: '10mb',
logdir: path.join(dataDir, 'logs'),
uploadDir: path.join(dataDir, 'downloads'),
viewCache: false,
registryCacheControlHeader: '',
registryVaryHeader: '',
disableSearch: false,
viewDir: path.join(root, 'view', 'web'),
customRegistryMiddlewares: [],
customWebMiddlewares: [],
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,
admins: {
fengmk2: '[email protected]',
admin: '[email protected]',
dead_horse: '[email protected]',
},
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',
adBanner: '',
customReadmeFile: '',
customFooter: '',
npmClientName: 'cnpm',
packagePageContributorSearch: true,
maxDependencies: 200,
backupFilePrefix: '/cnpm/backup/',
database: {
db: 'cnpmjs_test',
username: 'root',
password: '',
dialect: 'sqlite',
host: '127.0.0.1',
port: 3306,
pool: {
maxConnections: 10,
minConnections: 0,
maxIdleTime: 30000
},
dialectOptions: {
trace: true,
},
storage: path.join(dataDir, 'data.sqlite'),
logging: !!process.env.SQL_DEBUG,
},
enableNpmAuditsProxy: true,
nfs: require('fs-cnpm')({
dir: path.join(dataDir, 'nfs')
}),
downloadRedirectToNFS: false,
downloadTgzDontCheckModule: false,
unpublishRemoveTarball: true,
registryHost: 'r.cnpmjs.org',
enablePrivate: false,
scopes: [ '@cnpm', '@cnpmtest', '@cnpm-test' ],
privatePackages: [],
officialNpmRegistry: 'https://registry.npmjs.com',
officialNpmReplicate: 'https://replicate.npmjs.com',
cnpmRegistry: 'https://r.cnpmjs.com',
sourceNpmRegistry: 'https://registry.npm.taobao.org',
sourceNpmWeb: 'https://npm.taobao.org',
sourceNpmRegistryIsCNpm: true,
syncByInstall: true,
syncModel: 'none',
syncConcurrency: 1,
syncInterval: '10m',
syncPopular: false,
syncPopularInterval: '1h',
topPopular: 100,
syncDevDependencies: false,
syncDeletedVersions: true,
syncChangesStream: false,
syncDownloadOptions: {
},
handleSyncRegistry: 'http://127.0.0.1:7001',
badgeSubject: 'cnpm',
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,
userService: null,
alwaysAuth: false,
httpProxy: null,
snykUrl: 'https://snyk.io',
enableAbbreviatedMetadata: false,
globalHook: null,
opensearch: {
host: '',
},
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 {
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);
};