1

前言

年前做了一个类似于用户画像的项目,功能比较独立,而且可能被很多项目作为一个功能模块嵌入,所以很自然的就想到把这个项目做成一个组件输出。vue-cli提供库打包模式,所以我每次开发完只需要将打包后的文件拷贝到其他项目就可以快乐地使用了。但是随着要引用这个模块的项目增多,和这个项目自身的开发迭代,这种手动拷贝的方式就太蠢了。显然我需要一套成熟的包管理方案,但是由于种种原因我又不能将代码发布到公共的npm上,只能在公司的测试服务器上搭建私有npm仓库。

下面我将一步一步地记录如果开发一个自己的前端包,如何搭建一个私有npm仓库,并上传自己的前端包,最后下载并引用自己的前端包。

一、使用lerna管理包

lerna是什么我就不介绍了,如果你还不知道就去看一下官网文档

  1. 全局安装lerna

    npm install lerna -g

  2. 初始化项目

    创建一个文件夹,并进入该文件夹执行以下命令:

    lerna init

    完成后,手动添加.gitignore文件,项目目录如下:

    ├── .gitignore
    ├── lerna.json
    ├── package.json
    └── packages
  3. 创建包

    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私有仓库

如果你有自己的服务器可以在你的服务器上试试看。

进入服务器之后,安装verdacciopm2,安装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的包管理应该也有了进一步的认识,如果你们团队内有这个需求,不妨一试,毕竟工程化就是为了减少人工操作所带来的失误风险和提升开发、构建效率的。


不死小强
2.2k 声望587 粉丝

前端开发