前沿
目前, 我们能接触到的模块化组件库真可谓是数不胜数, 尤其是 vue 相关的那更是多如牛毛, 譬如 element,iview 等等, 虽然有很多, 但是轮子虽多, 合不合适自己还不好说, 就像买衣服, 有件衣服虽然好看, 但是貌似容纳不了自身肥胖的身躯那也只能望洋兴叹. 当然这时候, 量身定做就显得那么重要! 今天, 就一起从头开始定制一套符合自身的 vue 组件库.
起步
首先, 就已了解的组件库的写法也就那么回事, 但是编写组件库的同事要写一套完善的文档也是尤为重要, 经过各种方式了解到, 目前我所熟知的有三种:
storybook 相信做 react 开发的筒子很熟悉, 但自从 v3.2 版本之后开始支持 vue, 这消息可谓是喜大普奔.
vue-mark-down 用这个可以在 markdown 中演示代码案例, 以及代码展示.
docsify 这是一个快速生成 doc 文档的库, 也是最近才了解到的.
项目初始化
开始, 需要创建一个空的 vue 项目, 在此基础上我们才能开始接下来的组件库编写!
npm i -g vue-cli // yarn add global vue-cli
vue init webpack lyui //(lyui) 可以随意更换成你的名称
- cd lyui
- npm run dev
不出意外, 打开浏览器: http://localhost:8080 , 便能看到如下:
组件库结构
接下来的结构都会以一个最简单的按钮组件做讲述! 所有的组件都放在 src>components 里面, 每个组件都新建一个目录, 譬如 button 组件, 目录结构如下:
- src/components/index.js
- import Button from './button'
- const components = {
- Button
- }
- const install = function (Vue) {
- if (install.installed) return
- // components.map(component => Vue.component(component.name, component))
- Object.keys(components).forEach(key => {
- Vue.component(components[key].name, components[key])
- })
- }
- if (typeof window !== 'undefined' && window.Vue) {
- install(window.Vue)
- }
- const API = {
- install,
- ...components
- }
- export default API
- src/components/button/index.js
- import Button from './src/button.vue'
- Button.install = function (Vue) {
- Vue.component(Button.name, Button)
- }
- export default Button
- src/components/button/src/button.vue
- <template>
- <button>
- <slot></slot>
- </button>
- </template>
- <script>
- export default {
- name: 'ly-button'
- }
- </script>
当然, 我这里的 button 组件只是一个基本架构.
组件库的引用
上面写了一个按钮组件, 我们当然是要把他用到我们的项目中, 不知道大家是否还记得 element 的用法, 其实我们这里的用法类似.
src/app.js 添加如下代码:
- import lyui from './components/index'
- Vue.use(lyui)
现在我们的项目还没有发布到 npm, 就这样简单的项目内引用了, 后面我们发布到 npm 了之后就完全可以跟 element 一样的使用方法了. ui 库已经引用到项目中, 有点迫不及待要去测试一下效果了. src/docs/test.md
在 markdown 中添加如上代码!
好了, 到这里, 一个简简单单的按钮组件就成功了一半了! 但是一个没有样式的按钮, 总觉得很鸡肋!
脱胎换骨
房子已经买了, 总不能直接住毛坯, 接下来我们就一起简单的装修一番, 材料多种多样, 有 scss,css,postcss, 看个人喜好了, 这里为了方便起见, 我就直接用 scss 了, 其实更简单的是直接写在 style 里面, 但是不推荐那样做, 因为可定制性不强.
- src/components/button/button.scss
- .ly-button{
- border:none;
- padding:5px 15px;
- background:#41B883;
- color:#fff;
- }
- src/components/index.scss
- @import './button/src/button.scss'
- src/main.js
- import './components/index.scss'
上面我们简单的写了一下 button 的样式, 并且在 main.js 进行引用, 是不是就这样就可以了呢? 答案是否定的, 由于上面我们的样式是用的 sass, 然而我们的项目并没有任何关于 sass 的 loader, 这个简单, 我们添加个 sass 的 loader 不就是了
cnpm install --save-dev sass-loader node-sass
因为 sass-loader 依耐于 node-sass, 这里给个友情提示, 一般情况下, 我们 npm 又或者是 yarn 都不能很顺利的安装 node-sass, 唯一的一步到位的方式便是使用淘宝的 cnpm http://npm.taobao.org/ .
npm install -g cnpm --registry=https://registry.npm.taobao.org
安装完 sass-loader,node-sass 之后直接重启服务就能看到我们加的样式已经生效了!
打包发布
一个组件库写完了, 最后肯定是要打包发布的, 不然我们写出来就毫无意义了. 新建三个配置文件:
- config/package.config.js
- const path = require('path');
- const webpack = require('webpack');
- module.exports = {
- entry: {
- 'lyui" : './src/components/index.js'
- },
- output: {
- path: path.resolve(__dirname, '../package'),
- publicPath: '/package/',
- library: 'lyui',
- libraryTarget: 'umd',
- umdNamedDefine: true
- },
- externals: {
- vue: {
- root: 'Vue',
- commonjs: 'vue',
- commonjs2: 'vue',
- amd: 'vue'
- }
- },
- resolve: {
- extensions: ['.js', '.vue']
- },
- module: {
- loaders: [{
- test: /\.vue$/,
- loader: 'vue-loader',
- options: {
- loaders: {
- css: 'vue-style-loader!css-loader',
- sass: 'vue-style-loader!css-loader!sass-loader'
- },
- postLoaders: {
- html: 'babel-loader'
- }
- }
- }, {
- test: /\.js$/,
- loader: 'babel-loader',
- exclude: /node_modules/
- }, {
- test: /\.css$/,
- use: [
- 'style-loader',
- 'css-loader',
- 'autoprefixer-loader'
- ]
- }, {
- test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
- loader: 'url-loader?limit=8192'
- }]
- },
- plugins: [
- new webpack.optimize.ModuleConcatenationPlugin()
- ]
- }
- config/package.div.config.js
- const webpack = require('webpack')
- const merge = require('webpack-merge')
- const baseWebpackConfig = require('./package.config')
- const ExtractTextPlugin = require('extract-text-webpack-plugin')
- const extractScss = new ExtractTextPlugin('/lyui.min.css')
- module.exports = merge(baseWebpackConfig, {
- output: {
- filename: '[name].js'
- },
- module: {
- loaders: [{
- test: /\.scss$/i,
- loader: extractScss.extract(['css-loader', 'sass-loader'])
- }]
- },
- plugins: [
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: '"development"'
- }
- }),
- extractScss
- ]
- })
- config/package.prod.config.js
- const webpack = require('webpack')
- const merge = require('webpack-merge')
- const config = require('../config')
- const baseWebpackConfig = require('./package.config')
- const ExtractTextPlugin = require('extract-text-webpack-plugin')
- const extractScss = new ExtractTextPlugin('/lyui.min.css')
- const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
- const CopyWebpackPlugin = require('copy-webpack-plugin');
- module.exports = merge(baseWebpackConfig, {
- output: {
- filename: '[name].min.js'
- },
- module: {
- loaders: [{
- test: /\.scss$/i,
- loader: extractScss.extract(['css-loader', 'sass-loader'])
- }]
- },
- plugins: [
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: '"production"'
- }
- }),
- //new webpack.optimize.OccurrenceOrderPlugin(),
- new webpack.optimize.UglifyJsPlugin({
- uglifyOptions: {
- ie8: false,
- output: {
- comments: false,
- beautify: false,
- },
- mangle: {
- keep_fnames: true
- },
- compress: {
- warnings: false,
- drop_console: true
- }
- }
- }),
- extractScss,
- new OptimizeCSSPlugin({
- cssProcessorOptions: config.build.productionSourceMap ?
- {
- safe: true,
- map: {
- inline: false
- }
- } :
- {
- safe: true
- }
- }),
- new CopyWebpackPlugin([
- // {output}/file.txt
- {
- from: `./src/components`,
- to: `./components`
- }
- ]),
- ]
- })
接下来需要在 package.json 中添加三条 script
- "package:dev": "webpack --config build/package.dev.config.js",
- "package:prod": "webpack --config build/package.prod.config.js",
- "package": "npm run package:prod && npm publish && npm run build"
并且添加 mian
"main": "package/lyui.min.js",
最后需要在
src/components/index.js
中引用 index.scss
- import './index.scss'
- npm run package \ npm run package:prod
执行完上面的命令之后会生成 package 目录, 里面包含打包之后的所有文件.
文档编写
上面介绍了那么多, 最后写出来的东西也只有你自己看得懂, 用户可是看得一脸懵逼, 这时候一个好的文档就显得尤为重要, 接下来开始介绍今天的主角: https://docsify.js.org/#/?id=docsify
全局安装 dosify
npm i docsify-cli -g
初始化 docsify
docsify init ./docs
启动文档服务器
docsify serve ./docs
启动成功之后, 就可以直接打开: http://localhost:3000 接下来的很多配置的东西在这里就不累述了, https://docsify.js.org/ , 大家自行查看文档, 而且配置也很简单!
结尾
虽然写了好多这种技术性文章, 然而到目前为止还没有真正意义上的写一个属于自己的组件库, 实在惭愧, 希望大家能把这篇文章用到实处, 真正意义上学有所用!
来源: https://juejin.im/post/5afcd516f265da0b9e65414b