首页 > IT职业 > > 浅谈低代码平台远程组件加载方案
浅谈低代码平台远程组件加载方案
https://www.zoo.team/article/low-code

低代码开发平台(LCDP)是无需编码(0 代码)或通过少量代码就可以快速生成应用程序的开发平台。通过可视化进行应用程序开发的方法,使具有不同经验水平的开发人员可以通过图形化的用户界面,使用拖拽组件和模型驱动的逻辑来创建网页和移动应用程序。这两年越来越多的公司和开发人员开始自研低代码平台来达到降本提效的目的。今天和大家分享一下低代码平台开发过程中遇到一个问题和对应的解决思路。
低代码平台之所以不需要写代码是因为平台提供了很多可配置的组件,让平台的用户可以通过配置的方式生成自己想要的产物。那么如果想要能配置出更多的效果,就需要保证物料库足够丰富。
如果物料组件很多,就需要按需加载组件。现有的开发工具如 Webpack 也支持代码分割。但是在低代码平台的开发场景中,平台应用是和组件分离的,需要用户在选择某个组件的时候,要加载远程组件代码。
我们以 vue 框架为例,假如当前有一个组件 A,代码如下,如何远程加载这个组件呢?
https:<template>
<div class="wp">{{text}}</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
import _ from 'lodash';
export default defineComponent({
setup(props) {
console.log(_.get(props, 'a'));
return {
onAdd,
option,
size,
text: 'hello world',
};
},
});
</script>
<style>
.wp {
color: pink;
}
</style>
打包:组件代码打包为 umd 格式,打包时配置 Webpack externals, 使打包产物不包含公共的依赖;
上传:打包的组件 js 上传到 cdn;
加载:在需要使用组件时,插入一个 script ,在这个 script 中将组件放在一个全局对象上;
注册:在 script 插入完成后,从全局对象上获取组件,并进行注册;
首先需要增加一个入口文件
https:https:import Component https:from https:'./index.vue';
https:if(!https:window.share) {
https:window.share = {};
}
https:window.share[Component.name] = Component;
以上面的入口文件为入口,用 Webpack 打包为 umd 格式
https:https:// 组件打包 Webpack 配置
https:const path = https:require(https:'path');
https:const { VueLoaderPlugin } = https:require(https:'vue-loader')
https:module.exports = {
https:mode: https:'production',
https:entry: path.resolve(__dirname, https:'./comps/index.js'),
https:output: {
https:filename: https:'index.js',
https:path: path.resolve(__dirname, https:'dist'),
https:library: { https:type: https:'umd' }
},
https:module: {
https:rules: [
{
https:test: https:/\.vue$/,
https:use: https:'vue-loader',
https:exclude: https:/node_modules/,
},
{
https:test: https:/\.js$/,
https:loader: https:'babel-loader'
},
{
https:test: https:/\.css$/,
https:use: [
https:'vue-style-loader',
https:'css-loader'
]
}
]
},
https:plugins: [
https:new VueLoaderPlugin()
],
https:externals: {
https:vue: https:'vue',
https:lodash: https:'lodash',
}
};
组件公共依赖都需要先加入到模板 html 中
https:https:<!DOCTYPE https:html>
https:<https:html https:lang=https:"en">
https:<https:head>
https:<https:meta https:charset=https:"UTF-8">
https:<https:meta https:http-equiv=https:"X-UA-Compatible" https:content=https:"IE=edge">
https:<https:meta https:name=https:"viewport" https:content=https:"width=device-width, initial-scale=1.0">
https:<https:title>Documenthttps:</https:title>
https:<https:script https:src=https:"https://cdn/vue.global.js">https:</https:script>
https:<https:script https:src=https:"https://cdn/lodash@4.17.21.min.js">https:</https:script>
https:</https:head>
https:<https:body>
https:<https:div https:id=https:"root">https:</https:div>
https:</https:body>
https:</https:html>
https:https:const loadComponent = https:(https:name) => https:new https:Promise(https:(https:resolve) => {
https:const script = https:document.createElement(https:'script');
script.src=https:`http://xxx/https:${name}.js`;
script.onload = script.onreadystatechange = https:https:function(https:){
resolve();
};
https:document.querySelector(https:'head').appendChild(script);
})
https:const addComp = https:async (name) => {
https:await loadComponent(name);
https:// 注册组件,其中 app 为 Vue 应用实例对象
app.component(name, https:window.share[name]);
}
https:// 动态注册组件
addComp(https:'A');
amd 格式也是一种模块化方案,这里我们选择知名度比较高的 require.js 作为 amd 模块加载器。
用 amd 格式来做远程加载时不需要像方案一一样,增加额外的入口文件,可以直接将 .vue 文件作为入口。以下是 Webpack 打包配置示例
https:https:// 组件打包 Webpack 配置
https:const path = https:require(https:'path');
https:const { VueLoaderPlugin } = https:require(https:'vue-loader')
https:module.exports = {
https:mode: https:'production',
https:entry: path.resolve(__dirname, https:'./comps/index.vue'),
https:output: {
https:filename: https:'index.js',
https:path: path.resolve(__dirname, https:'dist'),
https:library: { https:type: https:'umd' } https:// 输出 amd 或者 umd
},
https:module: {
https:rules: [
{
https:test: https:/\.vue$/,
https:use: https:'vue-loader',
https:exclude: https:/node_modules/,
},
{
https:test: https:/\.js$/,
https:loader: https:'babel-loader'
},
{
https:test: https:/\.css$/,
https:use: [
https:'vue-style-loader',
https:'css-loader'
]
}
]
},
https:plugins: [
https:new VueLoaderPlugin()
],
https:externals: {
https:vue: https:'vue',
https:lodash: https:'lodash',
}
};
https:https:<!DOCTYPE https:html>
https:<https:html https:lang=https:"en">
https:<https:head>
https:<https:meta https:charset=https:"UTF-8">
https:<https:meta https:http-equiv=https:"X-UA-Compatible" https:content=https:"IE=edge">
https:<https:meta https:name=https:"viewport" https:content=https:"width=device-width, initial-scale=1.0">
https:<https:title>Documenthttps:</https:title>
https:<https:script https:src=https:"./require.js">https:</https:script>
https:</https:head>
https:<https:body>
https:<https:div https:id=https:"app">https:</https:div>
https:</https:body>
https:</https:html>
https:https:// main.js
requirejs.config({
https:baseUrl: https:'https://cdn.xxx.com',
https:map: {
https:'*': {
https:css: https:'require-css',
},
},
https:paths: {
https:echarts: https:'echarts@5.1.1',
https:vueDemo: https:'vue-demo',
https:vue: https:'vue@3.2.37',
https:moment: https:'https://cdn/moment@2.29.1.min',
},
https:shim: {
https:'ant-design-vue': [https:'css!https://cdn/ant-design-vue@2.1.6.min.css'],
},
});
requirejs([https:'vue', https:'vue-demo', https:'vue-app'], https:https:function (https:vue, vueDemoModule, VueAppModule) {
https:const app = Vue.createApp(VueAppModule.default);
app.component(https:'vue-demo', vueDemoModule.default);
https:const vm = app.mount(https:'#app');
});
vue-app)也需要编译为 amd 格式,然后上传到 cdn 上,开发流程改变,需要定制化的开发平台项目的发布机制。这里需要注意的是,externals 配置项中直接把公共依赖配置为 cdn 地址;
https:https:import path https:from https:'path';
https:import VueLoader https:from https:'vue-loader';
https:const VueLoaderPlugin = VueLoader.VueLoaderPlugin;
https:const __dirname = path.resolve();
https:export https:default {
https:mode: https:'development',
https:entry: path.resolve(__dirname, https:'./src/vue-demo.vue'),
https:output: {
https:filename: https:'vue-demo.esm.js',
https:path: path.resolve(__dirname, https:'components'),
https:library: { https:type: https:'module' }
},
https:experiments: { https:outputModule: https:true },
https:module: {
https:rules: [
{
https:test: https:/\.vue$/,
https:use: https:'vue-loader',
https:exclude: https:/node_modules/,
},
{
https:test: https:/\.js$/,
https:loader: https:'babel-loader'
},
{
https:test: https:/\.css$/,
https:use: [
https:'vue-style-loader',
https:'css-loader'
]
}
]
},
https:plugins: [
https:new VueLoaderPlugin()
],
https:externals: {
https:vue: https:'https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.esm-browser.js',
https:'lodash': https:'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.js'
}
};
使用上述配置打包后产物,中会把 'vue' 替换为 externals 中的 cdn 地址
https:https:// 输入
https:import Vue https:from https:'vue';
https:// 输出结果
https:import Vue https:from https:'https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.esm-browser.js';
https:https:const list = ref([]);
https:const addComp = https:async () => {
https:const VueDemo = https:await https:import(https:/* @vite-ignore */https:`http://cdn/components/vue-demo.esm.js`)
https:window.app.component(https:'vue-demo', VueDemo.default);
list.value.push({ https:key: https:new https:Date().valueOf(), https:name: https:'vue-demo' });
}
需要注意的是要保证本地开发时引入的 vue 也是远程的,所以需要在 vite 的配置文件中增加 alias 配置。
https:https:// vite.config.js
https:import { defineConfig } https:from https:'vite';
https:import vue https:from https:'@vitejs/plugin-vue';
https:// https://vitejs.dev/config/
https:export https:default defineConfig({
https:plugins: [vue()],
https:resolve: {
https:alias: {
https:'vue': https:'https://cdn.jsdelivr.net/npm/vue@3.2.37/dist/vue.esm-browser.js'
}
}
})
exports.default、exports.__esModule 等利用语法来兼容 ESModule 和 CommonJS 的废案往往也都被 babel 实现,而且被许多开发者使用并且发布到了 npm 上,这就导致了现在 npm 上的许多包中有大量的废弃兼容性代码,而这些代码往往会对开发工具的转化造成阻碍。基于笔者对模块联邦的了解,笔者认为 Webpack 的模块联邦,目前更加适合微前端的场景,但是不太适用于低代码平台的场景。但是笔者对 webpack 模块联邦了解不够深入,判断不一定准确,欢迎有不同意见的小伙伴在评论区讨论。
对比上面三个方案,方案一实现起来最简单,但是没有真正实现按需加载,随着项目规模和需要满足的业务场景的扩大,组件的公共依赖会越来越多。方案二 、方案三 都能实现真正的按需加载,其中 require.js 虽然听上去已经是上个世纪的东西了,但是兼容性和坑相对比较少。说到 ESModule, 虽然有兼容性和上面提到的一些格式转化的问题,但随着近些年 Vite 、Snowpack 的发展,在未来 ESModule 一定是大势所趋,目前笔者也正在将负责的我司内部大屏低代码平台改造为 ESModule 方式加载。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/1741/viewspace-3143270/ ,如需转载,请注明出处,否则将追究法律责任。