前言
年前做了一个类似于用户画像的项目,功能比较独立,而且可能被很多项目作为一个功能模块嵌入,所以很自然的就想到把这个项目做成一个组件输出。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
二、使用vite+vue3开发包
我在实际项目中用的是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<string, FileType> = 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
:
<template>
<hello-world msg="Hello Vue 3 + TypeScript + Vite" />
</template>
<style>
#app {
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
执行npm run dev
启动服务,页面完美呈现~
总结
这一套下来你对npm
的包管理应该也有了进一步的认识,如果你们团队内有这个需求,不妨一试,毕竟工程化就是为了减少人工操作所带来的失误风险和提升开发、构建效率的。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。