阅读 256

element UI 和 ivivew UI 合并方案 (vue2.0)

element UI 和 ivivew UI 合并方案 (vue2.0)

故事背景: 公司想搭建物料库、组件库、低代码平台等相关的基础工具,但是公司内有两套 UI 框架分别是 elementUI 和 iviewUI , 导致开发前端基础设施就非常困难。所以我们想将 elementUI 合并到 iviewUI 上.


vue前端编译工具


在vue代码里其实是分为两种类型

  • 第一种.vue 文件类型

<template>   <div id="app">     <el-button round>2323</el-button>   </div> </template> <script> export default {   data(){     return {       data: [{         label: '一级 1'       }]     }   } } </script>> 复制代码

  • 第二种.js类型

 export default {   data(){     return {       data: [{         label: '一级 1'       }]     }   },   render(h) {     return <div id="app">     <el-button round>2323</el-button>   </div>   }, } 复制代码

不管哪种类型,我希望同一套转换代码能兼容两种 vue 的语法糖,经过调研不管是jsx类型还是 .vue 文件类型。其实最后都是 render 函数渲染

  • 第一种.vue 转化render函数

<template>   _c('div', [     _c('el-button',{         attrs: {           round: ''         }       },      '2323')   ]) </template> <script> export default {   data(){     return {       data: [{         label: '一级 1'       }]     }   } } </script>> 复制代码

  • 第二种.js类型的 render 函数

 export default {   data(){     return {       data: [{         label: '一级 1'       }]     }   },   render(h) {     return h('div',[       h('el-button', {         attrs: {           round: ''         }       }, '2323')     ])   }, } 复制代码

其实第一种类型中的 _c 其实就是第二种里面的 h 函数


其实拿到这个 render 其实就成功了一半,我们只需要把这个render 交给babel,拦截 render 函数,然后将组件的 tag 或者 attrs 替换成 iviewUi 组件即可


比如:h('el-button'})  =>  h('Button'})


拦截 vue 的 render 函数


vue-loader 原理可以看这里

ps: 本来想通过 webpack 钩子获取拦截 render 函数,但是不可以甚至问了下webpack的作者, 可以直接连接跳转过去看下

  • 第一种 .vue 方式类型

通过 vue-loader 我们可以拦截 template 生产的render函数

拦截方式

const customer = require('your vue-template-compiler') chainWebpack: config => {     config.module       .rule('vue')       .use('vue-loader')       .tap(options => {         options.compiler = v         return options       })   } // ========= your vue-template-compiler import * as compiler from 'vue-template-compiler' const decorateCompiler: Record<string, any> = {} function decorateCompilerPreproty() {   for (let key in compiler) {     decorateCompiler[key] = compiler[key as CompilerPreproty]   } } decorateCompilerPreproty() // main methods  decorateCompiler.ssrCompile = decorateCompiler.compile = function overCompiler(template: string, options: CompilerOptionsWithSourceRange) {   const { ast, render, staticRenderFns, tips, errors } = compiler.compile(template, options)   // ... add your code like "() => render"   return { ast, render, staticRenderFns, tips, errors } } 复制代码

如上代码所示,我们可以通过替换 vue-loader 中用到的 vue-template-compiler。vue-template-compiler 中我们主要重写下 compiler.compiledecorateCompiler.ssrCompile

  • 第二种 render 函数类型

第二种其实是js文件,vue2.0 其实基于webpack封装的脚手架工具,这里我们要了解下 webpack 的 loader 执行顺序

其实:loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。在下面的示例中,从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束。查看 loader 功能 章节,了解有关 loader 顺序的更多信息。

module.exports = {   module: {     rules: [       {         test: /\.css$/,         use: [           // 3           { loader: 'style-loader' },           // 2           {             loader: 'css-loader',             options: {               modules: true             }           },           // 1           { loader: 'sass-loader' }         ]       }     ]   } }; 复制代码

在 vuecli 中我们通过类似的方式拦截 render 函数

例如:

module.exports = {   module: {     rules: [       {         test: /\.js$/,         use: [           // this your loader           {loader: 'your loader'},           // 2           { loader: 'babel-loader' },           // 1         ]       }     ]   } }; 复制代码

loader 其实从下往上执行的,我们可以拦截 babel-loader 编译后的产物


babel修改render函数

我这里采用了配置化的方式将 elementUI 转换为 IviewUI 方式

以 button 按钮为例

 //  state 0 replace key, state 1 replace key and value, state 2 replace part export const buttonProprety = {   plain: {     state: 0,     ghost: null   },   circle: {     state: 1,     shape: 'circle'   },   round: {     state: 1,     shape: 'circle'   },   nativeType: {     state: 0,     htmlType: null   },   type: {     state: 2,     type: {       danger: 'error'     }   },   size: {     state: 2,     size: {       medium: 'default',       mini: 'small',       default: 'large'     }   } } 复制代码

如上代码,state 0 代表替换 key, state 1代表替换key 和value, state代表替换部分.

it('state 为 1的时候', () => {   `h('el-button', {round: ''}, 23)`.expect(`h('Button', {shape: 'circle'}, 23)`) }) it('state 为 0的时候', () => {   `h('el-button', {plain: ''}, 23)`.expect(`h('Button', {ghost: ''}, 23)`) }) it('state 为 2的时候', () => {   `h('el-button', {size: 'medium'}, 23)`.expect(`h('Button', {small: 'small'}, 23)`) }) 复制代码

我们罗列所有的 Button 的属性,通过 babel 获取到当前 Callexpssion 中的attrs 属性,然后通过数据转换

有兴趣的同学可以加入到我们的开发

最后使用方式

const compiler = require('YOUR COMPILER') module.exports = {   lintOnSave: false,   chainWebpack: config => {     config.module       .rule('vue')       .use('vue-loader')       .tap(options => {         options.compiler = compiler         return options       })   } }

 伪原创工具 SEO网站优化  https://www.237it.com/ 

作者:wulinsheng123
链接:https://juejin.cn/post/7036162432204554271

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐