柏乡企业做网站,wordpress新打开空白页,软件开发教程培训,wordpress小程序制作本文作者系360奇舞团前端开发工程师 淘宝 NPM 镜像站切换新域名时#xff0c;放了一张知乎博主天猪的图片#xff0c;如下#xff1a; _图片来源#xff1a;https://zhuanlan.zhihu.com/p/432578145 看着逐年增长的访问量#xff0c;不禁让人感慨#xff0c;npm 的出现放了一张知乎博主·天猪·的图片如下 _图片来源https://zhuanlan.zhihu.com/p/432578145 看着逐年增长的访问量不禁让人感慨npm 的出现对 JavaScript 生态产生了深远影响。npm 包下载量的变迁也是 JavaScript 生态体系发展的一个缩影同时也是国内公司前端领域发展的一个缩影。 npm 的出现让我们可以轻松使用第三方模块也让我们可以轻松发布自己的模块。 随着企业的发展公司内部对私有的 npm 源的需求越来越多下面就来介绍一下企业级 npm 私有仓库部署方案。 一、 为什么需要 npm 私有仓库 我们从基本要求和扩展需求两个方面来分析。 基本要求 安装速度快内网访问对接公司内部登录权限系统支持私有包避免公网 npm 服务不稳定 扩展需求 安全审计追踪依赖及时发现安全问题使用 AI 相关技术自动产出项目老旧依赖升级建议支持内部 npm cli 工具扩展更多功能前端工程数字化建设定制化数据统计分析功能 基本要求是搭建企业级 npm 私有仓库的核心诉求扩展需求则是企业数字安全和团队工程化的诉求。当然不同的团队有不同的需求本质上就是为了安全和稳定能依托 npm 服务做定制化服务。 二、开源项目方案 既然要搭建企业级 npm 私有仓库那么首先就要考虑开源项目。 有 nexus-public、verdaccio(sinopia已停止更新)、cnpmcore(cnpmjs已废弃)等其中 nexus-public 是 java 项目其他都是 nodejs 项目。另外有收费的有 JFrog Artifactory是通用通用存储库管理器支持许多流行仓库包括 npm。 基本上能做到私有化部署npm服务 对接公司内部权限系统就能满足基本要求。 nexus-public 是 java 项目能满足基本要求如果公司有同步管理 maven、docker等需求可以考虑。verdaccio 界面简洁功能齐全社区活跃拥有 15k 的 star数是一个不错的选择。verdaccio 非常轻量安装和配置都非常简单可以通过插件定制化包括身份验证、存储和通知等功能。cnpmcore 是淘宝 NPM 镜像站服务 npmmirror.com 背后的核心是基于 eggjs 开发的。 三、选择 cnpmcore 企业服务要求数据和服务分离既要保证数据的安全和可靠性又要保证服务的持续升级迭代。 既然是内网私有化部署不用面对公网的流量更多的关注点在于除了满足内网 npm 基本服务要求更多的是企业定制化需求。 综合考虑各方需求后我认为 cnpmcore 对于企业级 npm 私有仓库部署方案来说是一个不错的解决方案。 图片来源: https://juejin.cn/post/7132723239813382151 相比于前身 cnpmjscnpmcore 进行了重大的重构cnpmcore 对我来说看中的就是它的二次研发能力。 cnpmcore 部署比较简单文档介绍的已经很详细了主要步骤简单描述 依赖服务准备MySQL 数据服务、Redis 缓存服务包存储默认是本地文件系统推荐使用对象存储服务源码下载安装依赖修改配置文件启动服务 比起直接源码部署我更推荐创建 tegg 项目集成 cnpmcore 使用, cnpmcore 官方有提供详细的 tegg 集成示例。当前有个前提你对于 eggjs 和 tegg 有一定的了解。 了解 cnpmcore 项目架构 首先放一下 cnpmcore 文档里的架构分层依赖图 简单总结一下文档内容 项目结构项目按照功能进行了分层包括 common通用工具和服务调用、core核心业务逻辑、repository数据存储和查询、portHTTP 控制器、infra基于 PaaS 的基础设置实现等。Controller主要处理 HTTP 请求继承自 AbstractController 和 MiddlewareController。AbstractController 封装了一些基础的数据 Entity 访问方法MiddlewareController 主要负责编排中间件的加载顺序。请求合法性校验请求合法性校验包括请求参数校验、用户认证和资源操作权限校验。请求参数校验使用 egg-typebox-validate用户认证和资源操作权限校验通过 UserRoleManager 进行。Service依赖 Repository然后被 Controller 依赖。PackageManagerService 管理所有包以及版本信息。Repository依赖 Model然后被 Service 和 Controller 依赖。Repository 类方法命名规则包括 findSomething查询一个模型数据、saveSomething保存一个模型数据、removeSomething移除一个模型数据和 listSomethings查询一批模型数据。 由于 tegg 的存在后续在定制化开发中我们可以按需导出所需要的模块然后进行二次开发。 四、定制化开发 如何在 tegg 中集成 cnpmcore 是官方提供的集成示例完整代码可以参考 这里。 准备工作 依赖的外部服务这里不多做赘述既然是企业级可以自行对接公司内部的 MySQL、Redis 服务。另外准备对象存储服务 s3, 用于存储包文件。 注意: cnpmcore 是渐进式开发mysql 数据结构会随着版本发生变动升级 cnpmcore 时一定要注意这里 https://github.com/cnpm/cnpmcore/tree/master/sql, 提前做好数据库表结构变更准备。 项目初始化 $ mkdir tegg-cnpm
$ cd tegg-cnpm
$ npm init egg --typets 初始化后的项目是一个 tegg 项目集成了 eggjs 和 tegg这里先更新一下依赖。 然后我们需要安装 cnpmcore 依赖以及需要的一些依赖如 eggjs/tegg-orm-plugin、egg-typebox-validate、s3-cnpmcore 等。 配置文件 修改 config/config.default.ts 配置文件添加 cnpmcore 配置。 config.cnpmcore {name: mynpm,sourceRegistry: https://registry.npmmirror.com,...// sync mode// - none: dont sync npm package, just redirect it to sourceRegistry// - all: sync all npm packages// - exist: only sync exist packages, effected when enableCheckRecentlyUpdated or enableChangesStream is enabledsyncMode: SyncMode.admin,syncDeleteMode: SyncDeleteMode.delete,...registry: process.env.CNPMCORE_CONFIG_REGISTRY || http://localhost:7001, // 填写自己的域名// white scope listallowScopes: [myscope, // 这里添加自己的 scope],...// 默认的系统管理员admins: { // name: emailxxx: xxxmy.cn,},...}; 添加 nfs 配置用于存储包文件 import S3Client from s3-cnpmcore;
...
// 默认是本地文件系统
config.nfs {client: null,dir: join(config.dataDir, nfs),
};// 这里使用 s3 对象存储, s3-cnpmcore 是 cnpmcore 官方提供的 s3 对象存储实现, 当然可以不用这个自己实现也可以
config.nfs.client new S3Client({region: xx,endpoint: http://xxx.com,credentials: {accessKeyId: ,secretAccessKey: ,},bucket: cnpmcore,forcePathStyle: false,disableURL: false,}); 修改 config/plugin.ts 配置文件开启我们需要的插件如下 teggOrm: {enable: true,package: eggjs/tegg-orm-plugin,},typeboxValidate: {enable: true,package: egg-typebox-validate,}, 添加 module.json [{path: ../app/service},{path: ../app/infra},{package: cnpmcore/common},{package: cnpmcore/core},{package: cnpmcore/port},{package: cnpmcore/repository}
] 其中 package 可以导出 cnpmcore 的模块也可以用 path 导出自己的本地模块具体参考 tegg 文档。 写业务代码 文件结构 如图所示在 infra 中我们可以实现自己的 adapter如 nfs 为例这里实现了自己的 nfs adapter用于存储包文件。如果在默认配置里没有配置 nfs.client那么就会使用默认的本地文件系统存储包文件。 以 AuthAdapter 为例这里实现了自己的 AuthAdapter用于对接公司内部的登录权限系统。 import { AccessLevel, EggContext, SingletonProto } from eggjs/tegg;
import { AuthAdapter } from cnpmcore/infra/AuthAdapter;
import { randomUUID } from crypto;
import { AuthUrlResult, userResult } from node_modules/cnpmcore/dist/app/common/typing;const ONE_DAY 3600 * 24;SingletonProto({name: authAdapter,accessLevel: AccessLevel.PUBLIC,
})
export class MyAuthAdapter extends AuthAdapter {async getAuthUrl(ctx: EggContext): PromiseAuthUrlResult {const sessionId randomUUID();await this.redis.setex(sessionId, ONE_DAY, );const registry ctx.app.config.cnpmcore.registry;const ssoLoginUrl ctx.app.config.ssoLoginUrl;const ref encodeURIComponent(${registry}/cli/login/sso/${sessionId});return {loginUrl: ${ssoLoginUrl}?ref${ref},doneUrl: ${registry}/-/v1/login/done/session/${sessionId},};}async ensureCurrentUser(): PromiseuserResult | null {if (this.user) {return this.user;}return null;}
} 添加登录验证Controller import {HTTPController,HTTPMethod,HTTPMethodEnum,Context,EggContext,HTTPParam,HTTPQuery,HTTPBody,Middleware,Inject,
} from eggjs/tegg;
import { EggLogger, EggAppConfig } from egg;
import { traceMethod } from ../middleware/trace_method;
import { LoginService } from ../service/LoginService;
import { CacheAdapter } from cnpmcore/common/adapter/CacheAdapter;
import { UserService } from cnpmcore/core/service/UserService;HTTPController()
Middleware(traceMethod)
export class LoginController {Inject()private readonly loginService: LoginService;Inject()protected userService: UserService;Inject()private cacheAdapter: CacheAdapter;Inject()protected config: EggAppConfig;Inject()private readonly logger: EggLogger;HTTPMethod({method: HTTPMethodEnum.GET,path: /cli/login/sso/:sessionId,})async cliLogin(Context() ctx: EggContext, HTTPParam() sessionId: string, HTTPQuery() sid: string) {if (!sessionId) {return { success: false, data: { message: need sessionId } };}// 验证 sessionId 是否有效const sessionData await this.cacheAdapter.get(sessionId);if (sessionData ! ) {return { success: false, data: { message: invalid sessionId } };}// 通过自己实现的 loginService 获取用户信息const user await this.loginService.getUser(ctx, sid);if (!user?.name || !user?.email) {return { success: false, data: { message: invalid user info } };}// 通过 cnpmcore UserService 保存 tokenconst { token } await this.userService.ensureTokenByUser({ name: user.name, email: user.email, ip: ctx.ip });await this.cacheAdapter.set(sessionId, token!.token!);// return { success: true, data: { message: login success } };// 跳转到登录成功页ctx.redirect(${this.config.cnpmcore.registry}/-/v1/login/request/success);return;}
} 前端部分 上面讲了服务端定制化开发对于前端部分cnpm 提供了 https://github.com/cnpm/cnpmweb可以直接下载源码使用也可以根据自己的需求进行二次开发这里就不多做赘述了。 五、总结 cnpmcore 对于企业级 npm 私有仓库部署方案来说是一个不错的选择。通过在 tegg 中集成 cnpmcore我们可以很方便的进行 npm 服务的二次开发扩展自己的业务代码满足企业定制化需求。 参考资料 https://juejin.cn/post/7132723239813382151https://github.com/cnpm/cnpmcorehttps://github.com/cnpm/cnpmcore/blob/master/INTEGRATE.mdhttps://github.com/verdaccio/verdaccio - END - 关于奇舞团 奇舞团是 360 集团最大的大前端团队代表集团参与 W3C 和 ECMA 会员TC39工作。奇舞团非常重视人才培养有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。