畅行石化app连云港石化基地
116.69MB · 2025-11-10
最近在公司做了一个公共组件库脚手架,踩了一些坑,所以写文章记录一下。
该组件库基于组件库iview做的二次封装业务组件,实现的功能有如下:
基于vue2 , vue-cli,vuepress,eslint,prettier,stylelint, husky等技术
1 .首先看一下目录结构。
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配置
const path = require('path');
module.exports = {
entry: {
index: path.resolve(__dirname, '../examples/main.ts'),
},
};
prod配置
module.exports = {
entry: {
index: '../packages/components/button/index.js',
},
output: {
// 文件名称
filename: '[name].js',
// 构建依赖类型
libraryTarget: 'umd',
// 库中被导出的项
libraryExport: 'default',
// 引用时的依赖名
library: 'WebDesign',
},
};
example
const 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
const { 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');
}
},
});
3. 组件示例
<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>
入口文件
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模块。
4. example示例,main.ts实现
import Vue from 'vue';
import App from './App.vue';
// 批量注册组件
import WebDesignComponent from '../packages/components';
import '../packages/css/index.less';
Vue.use(WebDesignComponent);
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
}).$mount('#app');
App.vue的实现
<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的代码
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
// 引入打包后的样式和文件。
import '../../lib/web-design.css';
export default async ({
Vue,
isServer,
}) => {
if(!isServer) {
await import('../../lib/web-design.umd.js').then(vueComp => {
Vue.use(vueComp);
})
}
}
运行npm run docs:dev就能启动vuepress文档了
参考文献: