最近在公司做了一个公共组件库脚手架,踩了一些坑,所以写文章记录一下。
该组件库基于组件库iview做的二次封装业务组件,实现的功能有如下:
- 热更新开发
- 打包编译、发布
- 组件文档
- eslint、prettier、styelint、husky
基于vue2 , vue-cli,vuepress,eslint,prettier,stylelint, husky等技术
1 .首先看一下目录结构。
lua
business-component
|- build ----------------------------------------------------------------------webpack配置
|- webpack.config.js
|- docs --------------------------------------------------------------------- -vuepress文档
|- .vuepress
|- config.ts
|- enhanceApp.js
|- guide
|- button.md --------------------------------------------------------------button文档
|- README.md
|- examples -------------------------------------------------------------------本地开发页面
|- App.vue
|- main.ts
|- lib ------------------------------------------------------------------------打包后的文件
|- web-design.css
|- web-design.umd.js
|- packages --------------------------------------------------------------------组件源文件 |- components
| - button
| - style
| - index.less
| - index.ts
|- public ----------------------------------------------------------------------静态资源
|- vue.config.js
|- package.json
2.打包配置
-
dev配置
iniconst path = require('path'); module.exports = { entry: { index: path.resolve(__dirname, '../examples/main.ts'), }, }; -
prod配置
javamodule.exports = { entry: { index: '../packages/components/button/index.js', }, output: { // 文件名称 filename: '[name].js', // 构建依赖类型 libraryTarget: 'umd', // 库中被导出的项 libraryExport: 'default', // 引用时的依赖名 library: 'WebDesign', }, }; -
example
javaconst path = require('path'); module.exports = { entry: { index: path.resolve(__dirname, '../examples/components/index.ts'), }, output: { // 文件名称 filename: '[name].js', // 构建依赖类型 libraryTarget: 'umd', // 库中被导出的项 libraryExport: 'default', // 引用时的依赖名 library: 'WebDesign', }, }; -
vue.config.js
arduinoconst { defineConfig } = require('@vue/cli-service'); const path = require('path'); const devWebpackConfig = require('./build/webpack.config.dev.js'); const proWebpackConfig = require('./build/webpack.config.prod.js'); const exampleWebpackConfig = require('./build/webpack.config.example.js'); function getWebpackConfig() { if (process.env.NODE_ENV === 'example') { return exampleWebpackConfig; } else if (process.env.NODE_ENV === 'development') { return devWebpackConfig; } else { return proWebpackConfig; } } module.exports = defineConfig({ transpileDependencies: true, configureWebpack: getWebpackConfig(), css: { extract: { filename: 'css/[name].css', //在lib文件夹中建立 theme 文件夹中,生成对应的css文件。 }, }, productionSourceMap: false, // 扩展 webpack 配置 /** * 删除splitChunks,因为每个组件是独立打包,不需要抽离每个组件的公共js出来。 * 删除copy,不要复制public文件夹内容到lib文件夹中。 * 删除html,只打包组件,不生成html页面。 * 删除preload以及prefetch,因为不生成html页面,所以这两个也没用。 * 删除hmr,删除热更新。 * 删除自动加上的入口App。 */ chainWebpack: config => { // @ 默认指向 src 目录,这里要改成 examples // 另外也可以新增一个 ~ 指向 packages config.resolve.alias.set('@', path.resolve('examples')).set('~', path.resolve('packages')); // 把 packages 和 examples 加入编译,因为新增的文件默认是不被 webpack 处理的 config.module .rule('js') .include.add(/packages/) .end() .include.add(/examples/) .end() .use('babel') .loader('babel-loader') .tap(options => { // 修改它的选项... return options; }); if (process.env.NODE_ENV === 'development') { config.optimization.delete('splitChunks'); config.plugins.delete('copy'); config.entryPoints.delete('app'); } else { config.optimization.delete('splitChunks'); config.plugins.delete('copy'); config.plugins.delete('html'); config.plugins.delete('preload'); config.plugins.delete('prefetch'); config.plugins.delete('hmr'); config.entryPoints.delete('app'); } }, });
- 组件示例
xml
<script lang="tsx">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'WebButton', // 注意这个name是必须的
props: {
disabled: {
type: Boolean,
default: false,
},
},
render() {
const { disabled } = this.$props;
return (
<button class={['ts-button', { 'is-disabled': disabled }].join(' ')} disabled={disabled}>
<span>
<slot>测试按钮</slot>
</span>
</button>
);
},
});
</script>
<style lang="less" src="../../../css/button.less"></style>
入口文件
javascript
import Button from './button';
const components = [Button];
// 全局引入: 引入的组件是个对象时,必须要有install函数
const install = Vue => {
components.forEach(component => {
Vue.component(component.name, component);
});
};
/* istanbul ignore if */
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
install,
Button,
};
运行npm run build,就能打包出组件库代码,vue-cli支持打包出umd模块。
- example示例,main.ts实现
javascript
import Vue from 'vue';
import App from './App.vue';
// 批量注册组件
import WebDesignComponent from '../packages/components';
import '../packages/css/index.less';
Vue.use(WebDesignComponent);
console.log(WebDesignComponent);
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
}).$mount('#app');
App.vue的实现
xml
<template>
<div id="app">
<div class="mb10">
<WebButton>按钮组件测试</WebButton>
<WebButton disabled type="primary">按钮组件测试</WebButton>
<WebButton type="success">按钮组件测试</WebButton>
</div>
</div>
</template>
<script>
export default {
name: 'App',
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin-top: 60px;
}
.mb10 {
margin-bottom: 10px;
}
</style>
运行npm run dev就能运行example中的代码,调试组件。运行npm run build:example就能将示例中的组件打包,这在后面的vuepress中会用到的。
5.vuepress的实现
config.ts的代码
php
import { defineConfig } from 'vuepress/config';
export default defineConfig({
// ...
themeConfig: {
// logo: '/assets/img/logo.png',
nav: [{ text: 'Home', link: '/' }],
repo: 'vuejs/vuepress',
editLinks: true,
docsDir: 'packages/docs/docs',
sidebar: [
{
title: '按钮', // 必要的
path: '/guide/button', // 可选的, 标题的跳转链接,应为绝对路径且必须存在
collapsable: false, // 可选的, 默认值是 true,
sidebarDepth: 1, // 可选的, 默认值是 1
},
{
title: '虚拟表格', // 必要的
path: '/guide/virtual-table', // 可选的, 标题的跳转链接,应为绝对路径且必须存在
collapsable: false, // 可选的, 默认值是 true,
sidebarDepth: 1, // 可选的, 默认值是 1
},
],
search: true,
},
plugins: [
// require('./my-plugin.js')
],
});
enhanceApp.js
dart
// 引入打包后的样式和文件。
import '../../lib/web-design.css';
export default async ({
Vue,
isServer,
}) => {
// Vue.component('WebButton', WebButton);
if(!isServer) {
await import('../../lib/web-design.umd.js').then(vueComp => {
Vue.use(vueComp);
})
}
}
运行npm run docs:dev就能启动vuepress文档了
参考文献:
- csdn - 2023 blog.csdn.net/jin11050211...