21年9月 写一个vue ui库

259 阅读3分钟

参考elment-ui写一个ui库

工作中写了一个vue的ui库,所以在这里记录一下写ui库的步骤

一、开始开发

  1. 新建文件夹(代表已经在开发了)
  2. 打开编辑器,导入项目(我用的webstorm)
  3. 新建package.json
  4. 新建.editorconfig文件,我用的是webstorm中标准的模式即所有文件4个空格等规则
  5. 建立四个文件夹:
    1. packages 即组件目录
    2. src 一些组件公用代码的目录
    3. build 主要用来写webpack配置文件
    4. examples 用于测试我们的组件,在工作中我也将此目录的内容最终打包后作为文档来使用
  6. 新建.gitignore文件

二、写个组件

  1. 在packages中新建button文件夹
  2. 在button中新建index.js文件与src文件夹,在src中新建button.vue
  3. 在button.vue中写一个组件的代码,示例如下:
<template>
    <button class="act-button" @click="handleClick($event)" :type="type">
        <slot></slot>
    </button>
</template>

<script>
export default {
    name: "act-button",
    props: {
        type: {
            type: String,
            default: 'primary',
        },
    },
    methods: {
        handleClick(evt) {
            this.$emit('click', evt);
        }
    }
}
</script>
  1. 在button/index.js中写入以下内容:
import Button from './src/button';

Button.install = function (Vue){
    Vue.components(Button.name, Button);
}

export default Button;
  1. 在packages中新建theme-chalk文件夹,在theme-chalk中新建button.less与index.less文件(用什么预处理器不重要)
  2. 在button.less中写button组件的样式(代码较长,就不示例了),并在index.less中引入button.less

三、打包组件

  1. 在项目根目录下新建components.json文件夹,用于配置组件名与组件入口文件,示例如下:
{
    "button": "./packages/button/index.js"
}
  1. 安装依赖
"devDependencies": {
    "vue": "^2.6.14",
    "vue-loader": "^15.9.8",
    "vue-loader-plugin": "^1.3.0",
    "vue-template-compiler": "^2.6.14",
    "webpack": "^5.54.0",
    "webpack-cli": "^4.8.0",
    "webpack-merge": "^5.8.0"
}
  1. 在build文件夹中新建webpack.common.js文件并写入以下内容
const VueLoaderPlugin = require('vue-loader-plugin');

module.exports = {
    resolve: {
        extensions: ['.vue', '.js', '.jsx'],
    },
    module: {
        rules: [
            {
                test: /.vue$/,
                exclude: /node_modules/,
                use: 'vue-loader',
            },
            {
                test: /.less/,
                exclude: /node_modules/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader',
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
    ]
}
  1. 在build文件夹中新建webpack.lib.js文件并写入以下内容
const {merge} = require('webpack-merge');
const common = require('./webpack.common');
const components = require('../components.json');
const path = require('path');

module.exports = merge(common, {
    mode: 'development',
    entry: components,
    output: {
        path: path.resolve('./lib'),
        filename: '[name].js',
        libraryTarget: 'commonjs2',
        clean: true,
    }
})
  1. 配置npm脚本
"scripts": {
    "build:lib": "webpack --config build/webpack.lib.js"
},

四、打包样式文件

采用gulp对样式内容单独进行打包

  1. 安装以下依赖
"gulp": "^4.0.2",
"gulp-autoprefixer": "^8.0.0",
"gulp-cssmin": "^0.2.0",
"gulp-less": "^5.0.0",
  1. 项目根目录下新建gulpfile.js并写入以下内容
const {src, dest} = require('gulp');
const less = require('gulp-less');
const cssmin = require('gulp-cssmin');
const autoprefixer = require('gulp-autoprefixer');

function css() {
    return src('packages/theme-chalk/*.less')
        .pipe(less())
        .pipe(autoprefixer({
            cascade: false,
        }))
        .pipe(cssmin())
        .pipe(dest('lib/theme-chalk'))
}

exports.default = css;
  1. 修改npm的构建指令build:lib
"build:lib": "webpack --config build/webpack.lib.js && gulp"

五、调试组件库

开发了组件,我们也需要在浏览器中调试一下看看效果才行

1.新建src/index.js文件并写入以下内容

import Button from '../packages/button';

export default {
    install(Vue) {
        Vue.use(Button);
    },
    Button,
}

2.在examples文件夹中建立一个vue项目,并引入src/index.js与packages/theme-chalk/index.less文件,然后就像一个正常vue项目来开发

六、问题记录

更新时间:2022年4月8日

移除vue

问题描述:我在开发tooltip组件时,使用了Vue的extend方法,由此而引入了vue库,但未在webpack中的externals选项中设置vue以避免将vue文件打包到这个组件中,所以导致这个组件打包后的体积过大

解决方法

目前未能彻底解决问题,在实际项目中,我直接引用了这个组件库的源代码而非打包后的内容

彻底解决思路

一是要在webpack中设置vue的externals,二是要使用webpack-node-externals库,但在我的尝试中仍未能彻底解决,原因请看以下内容

未能彻底解决问题的原因猜想

在尝试了许多次配置后,我觉得可能是webpack版本的问题,组件库打包使用的是5版本,而vue-cli自动创建的项目都是用的4版本的webpack。两个版本的webpack打包时的一些逻辑可能不相同可能导致了这个问题。