用vite+lerna配合verdaccio发布自己的前端包
前言
年前做了一个类似于用户画像的项目,功能比较独立,而且可能被很多项目作为一个功能模块嵌入,所以很自然的就想到把这个项目做成一个组件输出。vue-cli
提供库打包模式,所以我每次开发完只需要将打包后的文件拷贝到其他项目就可以快乐地使用了。但是随着要引用这个模块的项目增多,和这个项目自身的开发迭代,这种手动拷贝的方式就太蠢了。显然我需要一套成熟的包管理方案,但是由于种种原因我又不能将代码发布到公共的npm
上,只能在公司的测试服务器上搭建私有npm
仓库。
下面我将一步一步地记录如果开发一个自己的前端包,如何搭建一个私有npm仓库,并上传自己的前端包,最后下载并引用自己的前端包。
一、使用lerna管理包
lerna
是什么我就不介绍了,如果你还不知道就去看一下官网文档
- 全局安装
lerna
npm install lerna -g
- 初始化项目
创建一个文件夹,并进入该文件夹执行以下命令:
lerna init
完成后,手动添加.gitignore
文件,项目目录如下:
├── .gitignore ├── lerna.json ├── package.json └── packages
- 创建包
lerna create @dede/app
创建包这里,你可以通过多次create
命令创建过个包进行开发、管理。
完成后项目结构如下:
├── .gitignore ├── lerna.json ├── package.json └── packages └── app ├── README.md ├── __tests__ │└── app.test.js ├── lib │└── app.js └── package.json
我在实际项目中用的是
vue-cli
+vue2
,这里我用vite
+vue3
来做演示,毕竟vite
是真的快啊!进入到
/dede-cli/packages/app
目录,执行:npm create vite@latest code -- --template vue-ts
成功以后根据
vite
文档里库打包章节进行配置:// vite.config.ts
import { defineConfig } from 'vite'
const path = require('path')
import vue from '@vitejs/plugin-vue'export default defineConfig({
plugins: [vue()],
build: {
outDir: './../dist',
lib: {
entry: path.resolve(__dirname, 'packages/index.ts'),
name: 'app',
fileName: (format) => `app.${format}.js`
},
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['vue'],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
vue: 'Vue'
}
}
}
}
});
因为我使用的是
vue-ts
模板,所以还需要安装一下@types/node
:npm i --save-dev @types/node
在上面的配置中我的入口文件配置如下:
entry: path.resolve(__dirname, 'packages/index.ts')
,所以在
code
文件夹下需要新建一个packages文件,我们对外输出的组件都是在这个文件夹开发的,同时packages/index.ts
应该导出一个包含install
方法的对象,具体参考vue插件开发文档。完成后我们的packages目录内容如下:
packages/
├── components
│└── HelloWorld.vue
└── index.ts
其中
HelloWorld
就是我们要输出的组件。index.ts
代码如下:import { App, Component } from 'vue';
interface FileType {
[key: string]: Component;
}const componentFiles: Record = import.meta.globEager('./components/**.vue');
const componentList = Object.keys(componentFiles).map(item => {
return componentFiles[item]?.default;
});
export default {
name: 'dedeUI',
install(app: App) {
componentList.forEach(component => {
app.component(component?.name as string, component);
});
}
}
这还没完,我们还需要配置
@dede/app的package.json
文件,配置导出模块:{
"name": "@dede/app",
"version": "0.0.0",
"description": "dede app",
"keywords": [
"app"
],
"author": "",
"homepage": "",
"license": "ISC",
"directories": {
"lib": "lib"
},
"files": [
"dist"
],
"main": "./dist/app.umd.js",
"module": "./dist/app.es.js",
"exports": {
".": {
"import": "./dist/app.es.js",
"require": "./dist/app.umd.js"
},
"./dist/style.css": {
"import": "./dist/style.css",
"require": "./dist/style.css"
}
},
"publishConfig": {
"access": "public"
}
}
然后执行打包命令
npm run build
,会看到在/dede-cli/packages/app
目录下面生成了一个dist
文件夹,这个就是我们打包需要导出的文件。dist
├── app.es.js
├── app.umd.js
├── favicon.ico
└── style.css
这个时候已经万事具备了,下一步只要搭建好
npm
私有仓库就可以上传包了。三、使用verdaccio搭建npm私有仓库
如果你有自己的服务器可以在你的服务器上试试看。
进入服务器之后,安装
verdaccio
和pm2
,安装pm2
主要是为了管理node应用。npm install verdaccio -g
npm install pm2 -g
成功之后通过
pm2
启动verdaccio
:pm2 start verdaccio
,成功以后你就可以通过
localhost:4873
访问了,端口可以通过配置文件更改,这里不做细讲。通过提升添加账号后就可以去发包了。四、发布并安装自己的包
申请
git
代码仓库并添加远程仓库成功后,在dede-cli
目录添加.npmrc
文件,配置npm registry
为你的私有仓库地址:registry=http://xxx/
git add .
,git commit -m "project init"
,然后执行
lerna publish
遵循semver
版本语义化规范选择版本号,成功以后进入到verdaccio
页面就可以看到自己发布的包了。发布成功以后,进入到
/dede-cli/packages/app/code
目录下执行npm install @dede/app --registry=http://xxx/
安装自己发布的包,然后在main.ts
引入:import { createApp } from 'vue';
import '@dede/app/dist/style.css';
import dedeUI from '@dede/app';
import App from './App.vue';
const app = createApp(App);
app.use(dedeUI);
app.mount('#app');
在
App.vue
组件中使用全局组件HelloWorld
:#app {
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
执行
npm run dev
启动服务,页面完美呈现~总结
【用vite+lerna配合verdaccio发布自己的前端包】这一套下来你对
npm
的包管理应该也有了进一步的认识,如果你们团队内有这个需求,不妨一试,毕竟工程化就是为了减少人工操作所带来的失误风险和提升开发、构建效率的。推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。