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.compile
和 decorateCompiler.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