博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
组件库构建过程
阅读量:6448 次
发布时间:2019-06-23

本文共 5748 字,大约阅读时间需要 19 分钟。

最近在项目内部创建了一个vue组件库,希望通过组件库的形式,统一项目中组件的逻辑和样式,让代码的复用性更强。

这篇文章主要是梳理组件库的整个结构和构建过程。

结构

图片描述

首先在这里介绍一下组件库的代码结构,上面是整体代码目录结构,每个目录的作用如下:

  1. packages:组件源码位置,每个组件作为一个子目录;同时提供packages/index.js作为全局组件的入口(具体内容后面会介绍)
  2. lib:存放编译后的代码
  3. build:构建工具相关(后面构建过程中会重点介绍)
  4. config:环境配置相关
  5. examples:doc文档相关
  6. test:单元测试代码
  7. 其他:eslint、babel、git相关的配置文件

这里再详细说一下packages,先看一下packges的目录结构:

图片描述

packages中子目录的名字就是组件的名称,每个组件会有index.vue和index.sass作为组件入口和样式入口。

同时,在packages根目录,index.js作为全局注册组件入口,会引入所有组件,然后调用Vue.component注册为全局组件。

ok,目录结构梳理清楚,但这也只是开发过程的一部分,至于最终的输出内容,还需要基于具体使用场景来编译,下面是目前组件库支持的使用方式和具体的编译方法。

浏览器引入

浏览器引入必然包括script和link,所以对应的,我们需要打包出包含所有组件需要的js和css文件。

对于script这种使用场景,需要把所有代码都打包到一个文件中,那么通过webpack的模式,就能达到我们的要求。
再配合,即可获取所有的css内容。
webpack入口文件就是packages/index.js,最终编译的文件,就是整个文件pirate.js和样式文件pirate.css。

webpack配置如下:

"use strict";const path = require("path");const webpack = require("webpack");const ExtractTextPlugin = require("extract-text-webpack-plugin");function resolve(dir) {  return path.join(__dirname, "..", dir);}module.exports = {  entry: resolve("packages/index.js"),  externals: {    vue: {      root: "Vue",      commonjs: "vue",      commonjs2: "vue",      amd: "vue"    }  },  output: {    path: resolve("lib"),    filename: "pirate.js",    library: "pirate",    libraryTarget: "window",  },  resolve: {    extensions: [".js", ".vue"]  },  module: {    rules: [{        test: /\.vue$/,        loader: "vue-loader",        options: {          js: {            loader: "babel-loader",            options: {}          },          scss: {            loader: ["css-loader", "scss-loader"]          },          extractCSS: true        }      },      {        test: /\.js$/,        loader: "babel-loader",        include: [resolve("package")]      },      {        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,        loader: "url-loader",        options: {          limit: 10000        }      }    ]  },  plugins: [    new ExtractTextPlugin("pirate.css"),    new webpack.optimize.UglifyJsPlugin({      compress: {        warnings: false      }    })  ]};

按需加载

至于按需加载,默认的方式,当然可以直接通过import Xxx from "pirate/lib/xxx/index.js"的方式去加载js,同时还需要通过@import ~pirate/lib/index.css手动加载样式。

但是这里建议配合这个插件来使用,代码会更加简洁舒适。

那么根据babel-plugin-import的要求,index.css会生成在lib/xxx/style目录下,这样的话,按需加载就需要一行代码:import { Xxx } from 'pirate'

回到编译阶段,自然的会想到用webpack来编译,每个组件就是一个入口,然后使用webpack多入口的模式来编译。

首先,前置一个自动化收集组件目录的工作,生成components.json用来作为webpack入口,实现的build/component.js代码如下:

const fs = require('fs-extra');const path = require('path');function isDir(dir) {  return fs.lstatSync(dir).isDirectory();}const json = {};const dir = path.join(__dirname, '../packages');const files = fs.readdirSync(dir);files.forEach(file => {    const absolutePath = path.join(dir, file);    if (isDir(absolutePath)) {        json[file] = `./packages/${file}`;    }});console.log(JSON.stringify(json));

然后通过node build/components.js > components.json生成components.json,通过webpack编译即可,webpack代码如下:

'use strict'const path = require('path');const ExtractTextPlugin = require('extract-text-webpack-plugin');const components = require('../components.json');function resolve(dir) {  return path.join(__dirname, '..', dir)}module.exports = {  entry: components,  externals: {    vue: {      root: 'Vue',      commonjs: 'vue',      commonjs2: 'vue',      amd: 'vue'    },  },  output: {    path: resolve('lib'),    filename: '[name]/index.js',    library: 'pirate',    libraryTarget: 'umd',    umdNamedDefine: true,  },  resolve: {    extensions: ['.js', '.vue'],  },  module: {    rules: [{        test: /\.vue$/,        loader: 'vue-loader',        options: {          js: {            loader: 'babel-loader',            options: {},          },          scss: {            loader: ['css-loader', 'scss-loader'],          },          extractCSS: true,        }      },      {        test: /\.js$/,        loader: 'babel-loader',        include: [resolve('package')],      },      {        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,        loader: 'url-loader',        options: {          limit: 10000,        }      },    ]  },  plugins: [    new ExtractTextPlugin('[name]/style/index.css'),  ],}

但是这里有一个问题,或者说是一个优化点,就是通过webpack生成的入口代码,都会包了一层webpack的启动器(想了解可以看我之前的文章、、),而通常作为按需加载来说,用户会有自己的webpack,那么组件库需要做的就是把vue文件编译成js,仅此而已(甚至vue文件也是可以的,但是考虑到更通用的场景,js还是更合适)。

所以,这里可以使用vue官方提供的,他的工作是把vue模板编译成独立的vue对象。这里我会使用同事开发的来做编译,vue-sfc-compiler底层封装了vue-template-compiler,上层提供了babel的支持,使用起来会更加方便,不过目的是一样的。

那么,基于上面webpack编译的文件,我会用vue-sfc-compiler编译出的更小的文件做覆盖,具体代码如下:

const fs = require('fs-extra');const compiler = require('vue-sfc-compiler');const path = require('path');function isDir(dir) {    return fs.lstatSync(dir).isDirectory();}function compile(dir) {    const files = fs.readdirSync(dir);    files.forEach(file => {        const absolutePath = path.join(dir, file);        if (isDir(absolutePath)) {            return compile(absolutePath);        }        if (/\.vue|.js$/.test(file)) {            const source = fs.readFileSync(absolutePath, 'utf-8');            const content = compiler(source).js;            const outputPath = absolutePath.replace('packages', 'lib').replace('.vue', '.js');            fs.outputFileSync(outputPath, content);        }    });}const dir = path.join(__dirname, '../packages');compile(dir);

全局组件注册

对于全局组件注册的方式,我会把这个入口作为整个module的入口,也就是默认的使用方式。

在上一步,按需加载阶段,其实已经把每个组件编译好了,那么入口文件,其实只要用babel做个转换就可以了,这里用到gulp来操作,代码如下:

const gulp = require('gulp');const babel = require('gulp-babel');const path = require('path');gulp.task('default', () =>  gulp.src(path.join(__dirname, '../packages/index.js'))  .pipe(babel({    presets: ['env']  }))  .pipe(gulp.dest(path.join(__dirname, '../lib'))));

总结

最后还有一个遗憾,目前文档化还没完成,那么这里先描述一下目前的设想,等实现后再写一篇分享。

现在计划是每个组件目录增加一个demo.vue和doc.md,demo.vue用来演示当前组件功能,doc.md作为文档内容。

然后通过一个自动化工具,把所有组件demo和doc合并到一起,生成一个html。

转载地址:http://uelwo.baihongyu.com/

你可能感兴趣的文章
GitHub页面使用方法
查看>>
Python爬虫综述(笔记)
查看>>
Scala之柯里化和隐式转换
查看>>
wmic命令
查看>>
Merge and BottomUpSort
查看>>
reids 安装记录
查看>>
获取androdmanifest里面的meta-data
查看>>
Centos 6.3编译安装nagios
查看>>
如何实现7*24小时灵活发布?阿里技术团队这么做
查看>>
iSCSI
查看>>
java1234_Activiti_第6讲_一般程序员使用的函数
查看>>
mysql拷贝表的几种方式
查看>>
NetApp FAS2240-4存储删除文件数据恢复
查看>>
技术人在学习爱的路上
查看>>
LVS -NAT模式配置实例
查看>>
北航 2012 秋季 现代软件工程 团队项目要求
查看>>
获取通讯组属性Get-DistributionGroup
查看>>
"知识管理夏季论坛",免费,欢迎你来!
查看>>
常用DOS命令
查看>>
能上QQ上不了网的解决办法
查看>>