從0搭建自動版本管理的Vue組件庫

前言

本文將向你們分享一波搭建一個自動版本管理的Vue組件庫的過程,偏基礎向,若有不足之處懇請指出。javascript

爲了讓讀者更清晰的瞭解每一步的步驟,有興趣的盆友能夠將demo克隆到本地(demo地址)使用git reset [commitId] --hard切換到每個commit查看細節。css

commitId給出以下:html

# 描述 commitId
1 搭建項目 02a4880146675adc902592b74248a0e3526df053
2 配置項目 598f4592c043eeb44aea840237c1a7726de3acfd
3 編寫組件 ec9cc302317c1eded6eab9beda206c9ae51c88e5
4 打包組件 238a414231e926ec91feef5b9c501f339fedb0d6
5 發佈npm包 1738eac3e0b8876bf6261ffd2255758100c6481b

搭建項目

首先咱們基於@vue/cli建立一個vue項目,個人cli當前版本是4.1.2前端

npm i -g @vue/cli
vue create vue-component-lib-demo
複製代碼

咱們的構建目標是個組件庫,把Babel、TS、CSS預處理、Linter、單元測試勾上就成,安裝依賴大概須要幾分鐘時間。 vue

配置項目

項目建立好以後咱們須要進行一些配置:java

  1. 修改項目目錄,刪除src、public文件夾,新增example、packages、types文件夾。example用於存放咱們組件庫的開發調試文件,packages用於存放組件、公共樣式和方法,types文件夾用於存放ts的聲明文件。
  2. 在example文件夾中新增模版index.html、入口文件main.ts、根組件app.tsx。
<!--index.html-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>vue-component-lib-demo</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but vue-component-lib-demo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

複製代碼
// main.ts
import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

複製代碼
// App.tsx
/** * 這裏我使用了tsx來寫vue組件 * 主要緣由是vue的tamplate對ts的支持不夠 * 不習慣的同窗仍是能夠用.vue文件,沒有什麼區別 */
import { Component, Vue } from 'vue-property-decorator';

@Component({
    components: {
        TestA
    }
})

export default class App extends Vue {

    protected render() {
        return (
            <div> hello world </div>
        );
    }

}
複製代碼
  1. 將vue的兩個聲明文件(shims-tsx-d.ts和shims-vue.d.ts)移入types文件夾。
  2. 修改tsconfig.json中的path選項:(默認是指向src的)
"path": {
    "@/*": [
        "./*"
    ]
}
複製代碼
  1. 新增vue.config.js
// vue.config.js
const path = require('path')
module.exports = {
    // sourceMap
    productionSourceMap: false,
    devServer: { // 本地服務配置
        host: "localhost",
        port: 3000,
        hot: true,
        compress: true,
        hotOnly: true,
        open: false,
        https: false,
        overlay: {
            warning: false,
            error: true
        },
        public: "0.0.0.0:3000"
    },
    // 指向example中的模版和入口文件
    pages: {
        index: {
            entry: 'example/main.ts',
            template: 'example/index.html',
            filename: 'index.html'
        }
    },
    css: { 
        extract: false // 將css內聯,js和css但願分開打包的同窗這裏設置爲true
    },
    configureWebpack: {
        output: {
            libraryExport: 'default'
        },
    },
    // 插件選項
    pluginOptions: {
        'style-resources-loader': {
            preProcessor: 'less',
            patterns: [
                path.resolve(__dirname, './packages/common/style/common.less')
            ]
        }
    },
    // webpack配置項
    chainWebpack: config => {
        config.externals({
            'vue': 'Vue' // 咱們不但願把vue的源碼打包
        })
    }
}
複製代碼

最終咱們的項目目錄長這樣: node

編寫組件

編寫一個組件咱們須要建立:組件、組件的樣式、組件的入口文件、組件的文檔。 接下來以TestA爲例咱們建立一個簡單的組件,目錄結構以下:webpack

css使用了css module:git

// TestA.tsx
import style from './TestA.module.less'
複製代碼

直接在TestA.tsx中引入style會引發tslint報錯找不到模塊「./TestA.module.less」,這時候咱們須要在shims-vue.d.ts文件中對less文件添加一個描述:github

// shims-vue.d.ts
declare module "*.less" {
  const less: any;
  export default less;
}
複製代碼

接下來咱們來編寫TestA組件:

// TestA.tsx
import { Component, Vue } from 'vue-property-decorator';
import style from './TestA.module.less'

@Component({
    name: 'TestA',
})

export default class TestA extends Vue {

    protected render() {
        return (
            <span class={style.text}> TestA </span>
        );
    }
}
複製代碼

TestA.module.less

.text{
    color: purple;
}
複製代碼

實現了TestA組件後咱們須要爲他編寫一個入口文件index.ts,用於按需加載:

// index.ts
import TestA from './TestA'
import { VueConstructor } from 'vue'

// 爲TestA組件新增install方法,能夠將TestA註冊爲全局組件
TestA['install'] = (Vue: VueConstructor): void => {
    Vue.component(TestA.name, TestA)
}

export default TestA
複製代碼

接下來咱們在/example/App.tsx裏引入一下TestA組件看看效果:

import { Component, Vue } from 'vue-property-decorator';
import TestA from '../packages/components/TestA';

@Component({
    components: {
        TestA
    }
})

export default class App extends Vue {

    protected render() {
        return (
            <div> hello <TestA/> </div>
        );
    }

}
複製代碼

看起來還8錯:

打包組件

按照編寫組件的流程又新增了一個TestB組件,這時候咱們須要打包組件,須要提供一個總的入口文件,因而在/packages/下新增index.ts和config.ts,config.ts用於引入組件,可將組件重命名後導出到index.ts:

// packages/config.ts
import TestA from './components/TestA/TestA';
import TestB from './components/TestB/TestB';

export default {
    TestA,
    TestB
}
複製代碼
// packages/index.ts
import config from './config'
import { VueConstructor } from 'vue'

interface compList {
    [componentsName: string]: VueConstructor
}

const components: compList = config
const install = (Vue: VueConstructor): void => {
    Object.keys(components).forEach((name) => Vue.component(name, components[name]))
}

export default {
    install,
    ...components,
}

複製代碼

index.ts文件導出一個install方法,將組件遍歷註冊到全局

接下來咱們在package.json中新增一條npm script:

"lib": "vue-cli-service build --target lib --name base-lib --dest lib packages/index.ts"
複製代碼

這條命令的意思是vue-cli-service打包目標是組件庫,入口文件是packages/index.ts,目標目錄是lib,組件庫的名字是base-lib,執行npm run lib後咱們獲得了構建產物:

版本管理

若是咱們每次組件庫版本更新都須要手動更改package.json的version字段,很容易出錯,並且人工維護版本也很是累,咱們可使用npm version命令來爲咱們自動升級版本。

先安裝一些相關依賴:

npm i -D cross-var shelljs inquirer
複製代碼
  • cross-var:npm script跨平臺兼容
  • shelljs:在node中執行shell命令
  • inquirer:終端用戶交互

接下來修改package.json:

"config": {
    "target": "lib/$npm_package_version"
  },
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint",
    "lib": "cross-var vue-cli-service build --target lib --name base-lib --dest $npm_package_config_target packages/index.ts"
  },
複製代碼

新增了自定義變量config,其中target是咱們打包的目標目錄,$npm_package_version是當前package.json的版本號,修改lib命令,將config.target指定爲輸出文件。

接下來咱們在根目錄建立一個release.js,用於實現終端用戶交互,詢問用戶此次發佈要升級什麼版本,npm version 遵循semver版本號,咱們可使用npm version方便的管理版本而不用手動管理

  • npm version major 升級大版本
  • npm version minor 升級小版本
  • npm version patch 更新小補丁
// release.js
const { exec } = require('shelljs')
const inquirer = require('inquirer')

inquirer.prompt([
    {
        type: 'list',
        name: 'selected',
        message: '請選擇版本升級類型',
        choices: [
            'major',
            {
                name: '大版本更新',
                disabled: '較大版本更新時選擇此項'
            }, 
            'minor',
            {
                name: '小版本更新',
                disabled: '較小版本更新時選擇此項'
            }, 
            'patch',
            {
                name: '更新補丁',
                disabled: '修復bug選擇此項'
            },
            new inquirer.Separator(),
            'cover',
            {
                name: '覆蓋當前版本',
                disabled: '危險操做!請勿覆蓋線上運行版本!'
            },
            new inquirer.Separator(),
        ]
    }
]).then(answer => {
    if (answer.selected === 'cover') {
        exec(`npm run lib`)
    } else {
        exec(`npm version ${answer.selected} && npm run lib`)
    }
})
複製代碼

而後新增一條npm script命令release:

"release": "node release.js"
複製代碼

在咱們使用npm run release後咱們能夠看到:

選擇版本後會使用相應的npm version更新版本,打出來的包也在相應版本號文件夾裏了:

發佈npm包

修改package.json:

"private": false,
"main": "lib/baselib.umd.min.js",
"files": [
  "packages",
  "lib"
],
複製代碼

將包改成非私有,指定入口文件和上傳的文件。

接下來使用npm login登錄帳號,使用npm publish便可發佈到npm。

我是suhangdev,郵箱17816876697@163.com,歡迎與我交流前端相關話題,若是文章對你有幫助,請點贊支持噢👍~

相關文章
相關標籤/搜索