低代码平台加载远端组件解决方案(1)——defineAsyncComponent

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 低代码平台加载远端组件解决方案(1)——defineAsyncComponent

背景

最近在做低代码平台项目中遇到一个很容易遇到的问题,具体描述如下:

  • 问题描述:低代码平台依赖的组件库,如果将一个组件库进行融合打包到平台项目中的就会导致平台在渲染页面的时候需要加载完整的组件库,从而导致页面加载了一些大部分页面不需要的组件文件
  • 希望方案:页面使用到哪些组件就去动态加载组件
  • 解决方案:
  • Vue的异步加载组件,SuspensedefineAsyncComponent
  • React的异步加载组件, Suspenseimport()

由于低代码项目本身使用的 Vue3 框架,而且 Vue和 React的异步加载组件方案其实差异不多,所以下面以 Vue为主进行介绍。

基础知识

异步组件

在使用异步组件之前,我们需要先声明一个 Vue的异步组件,主要有以下几种方式:

第一种,采用<script setup>语法的,需要在 setup中 使用 await语法即可,例子如下:

<script setup>
const res = await fetch(...)
const posts = await res.json()
</script>

第二种,声明setup函数增加async,会被识别成异步组件,具体如下:

export default {
  async setup() {
    const res = await fetch(...)
    const posts = await res.json()
    return {
      posts
    }
  }
}

第三种,就是通过defineAsyncComponent函数定义异步获取的组件实例,具体如下:

import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() => {
  return new Promise((resolve, reject) => {
    // ...从服务器获取组件
    resolve(/* 获取到的组件 */)
  })
})
// ... 像使用其他一般组件一样使用 `AsyncComp`

注意:同时Vue组件有个配置属性suspensible,可以用来设置false忽略为异步组件。

Suspense

<Suspense> 是一个内置组件,用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。 —— Vue官方 Suspense定义

<Suspense>解决了我们什么问题:

  • 当我们有个全局 loading,就不再需要每个组件的针对自己的加载状态去写逻辑处理
  • 能够更好统一处理异步组件,减少逻辑代码
  • 结合路由切换 和 <Transition>,可以完美实现页面切换效果

目前只有异步组件才会触发<Suspense>状态变更。

使用Suspense

<script lang="ts" setup>
import Aysnc from "@/components/AsyncComponent.vue";
/**
 * Suspense 组件的 pending 进入挂起状态时触发
 */
 */
const pending = ()=>{
    console.log('pending')
}
/**
 * Suspense 组件的 resolve在 default 插槽完成获取新内容时触
 */
const resolve = ()=>{
    console.log('resolve')
}
/**
 * Suspense 组件的  fallback 插槽的内容显示时触发
 */
 */
const fallback = ()=>{
    console.log('fallback')
}
</script>
<template>
    <h3>测试 Supsense</h3>
    <Suspense @pending="pending" @resolve="resolve" @fallback="fallback">
        <!-- 具有深层异步依赖的组件 -->
        <aysnc />
        <!-- 在 #fallback 插槽中显示 “正在加载中” -->
        <template #fallback>
            <h1>正在加载中...</h1>
        </template>
    </Suspense>
</template>

其中,Suspense组件有三个事件分别是:

  • pending 进入挂起状态时触发
  • fallback 插槽的内容显示时触发
  • resolve default 插槽完成获取新内容时触

defineAsyncComponent

定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。 —— Vue异步组件

通过官方定义,从中可以得到两层意思,分别是:

  • 第一是这个函数是专门用来的定义异步组件的,其参数是一个async函数,结合ES Moduleimport()动态导入,可以快速实现懒加载组件
  • 第二是这个函数是可以从远端加载组件描述代码,而这个恰恰就是本文的重点

第一种用法就很简单了,通过 import()引入的组件会在打包的时候单独分割成一个文件,当使用的时候才会去加载。代码如下:

import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
  import('@/component/AsyncComponent.vue')
);

vite或者 Webpack 会把AsyncComponent.vue文件单独拆分打包成一个 js文件。

第二种用法是从远端服务器加载一个组件回来,然后加载成组件进行页面渲染,如下描述。

加载服务器上的组件

如果利用第二种方式去加载组件,我们最期待的代码效果如下:

<script setup>
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent(() =>
    // 从服务器获取组件
    const async = await fetch('https://example.com/AsyncComponent.js')
    resolve(async)
    return async
);
// 后续可以直接在 template中使用 AsyncComponent
</script>
<template>
 <AsyncComponent />
</template>

那么AsyncComponent.js这种组件的代码应该如何生成呢?

但是,当数据还没返回来的时候,页面是不知道会渲染什么组件的。所以我们遇到第一个问题:

问题: 如何从远端加载 Vue组件,Vue通过defineAsyncComponent函数帮忙解决了加载问题,那么我们还需要知道这个函数支持加载什么格式的组件。

为了解决这个问题,我们先需要复习一下 Vue的组件基础知识

  1. 如何去定义一个组件,在 Vue 官方文档中是这么定义一个非单文件(.Vue)的组件, 如下所示:
// 选项式的组件
export default {
  data() {
    return {
      count: 0
    }
  },
  template: `
    <button @click="count++">
      You clicked me {{ count }} times.
    </button>`
}
  1. Vue组件注册知识,分为全局注册和局部注册,如下所示:

全局注册代码如下:

import { createApp } from 'vue'
import MyComponent from './App.vue'
const app = createApp({})
app.component('MyComponent', MyComponent)

局部注册如下:

<script>
import ComponentA from './ComponentA.vue'
export default {
  components: {
    ComponentA
  }
}
</script>
<template>
  <ComponentA />
</template>

复习完组件定义和注册,那么我们大概就知道如何解决【如何从远端加载Vue组件并进行注册使用?】,步骤如下:

  • 编写远端组件文件,需要符合组件的基本配置规范
  • 利用defineAsyncComponent函数异步加载组件机制去拉取远端组件
  • 解析远端组件文件内容,生成按照组件定义规范返回组件的对象resolve返回
  • 通过全局或局部注册,将defineAsyncComponent函数返回对象进行注册

示例代码如下:

  1. 制造符合组件规范的文件Async.js
// Async.js
export default {
  "template": `<h1>我是异步组件</h1><div></div><button @click="count++">\
        点击了 {{ count }} 次
      </button>`,
  "script": {
    "data": {
      "count": 0
    }
  }
}
  1. 解析组件和注册组件
<script lang="ts" setup>
...
</script>
<template>
    <h3>测试 Supsense</h3>
    <Suspense>
        <!-- 具有深层异步依赖的组件 -->
        <AsyncDD />
        <!-- 在 #fallback 插槽中显示 “正在加载中” -->
        <template #fallback>
            <h1>正在加载中...</h1>
        </template>
    </Suspense>
</template>
<script lang="ts">
import { defineAsyncComponent } from 'vue/dist/vue.esm-bundler.js';
/**
 * 加载远端+解析组件
 * @param url 
 */
const loadRemoteComponent = async (url: string) => {
    const response = await fetch(url);
    const scriptText = await response.text()
    let Component: any = '';
    try {
        const scriptStr = scriptText.replace('export default', '')
        Component = new Function('return ' + scriptStr)()
        console.log(Component)
    } catch (e) {
        console.error(e)
    }
    return Component
}
const AsyncDD = defineAsyncComponent(() => {
    return new Promise((resolve) => {
        setTimeout(() => {
            loadRemoteComponent('/async/demo.js').then((Component) => {
                resolve(Component)
            });
        }, 2000);
    });
})
export default {
    components: {
        AsyncDD
    }
}
</script>

项目实战

上述这种解决方案很明显存在问题,但是基础解决思路是没有问题,主要问题在于

  • 无法使用vue单文件
  • 无法通过import引用外部资源

如何解决呢,由于项目实战还在研究中,打算放到下一篇项目实战去解决掉,尽情期待。

参考资料

目录
相关文章
|
4月前
|
数据可视化 数据挖掘 数据库
低代码开发全解析核心功能及其优势
低代码开发平台采用图形界面与预构建组件加速软件开发,降低技术门槛与成本,并支持敏捷迭代与快速部署。其核心功能包括可视化建模、预构建组件库、业务流程自动化、集成与连接性、多平台应用开发、数据分析报告、版本控制与协作、测试调试工具、安全性与合规性及快速部署更新。优点体现在提升开发速度与效率、降低成本、加强团队合作及提高灵活性与可扩展性。选择平台时需明确需求、评估功能与灵活性、考虑易用性、集成能力、安全性与合规性及成本与定价模型。例如,Zoho Creator作为成熟平台,拥有丰富的经验和广泛的应用案例。低代码开发已成为企业数字化转型的关键工具。
98 13
|
5月前
|
小程序 前端开发 定位技术
简单快速搭建出适配于多平台的小程序
随着移动互联网的深入发展,小程序以其轻量、便捷、即用即走的特点,逐渐成为企业与用户沟通的重要桥梁。在当今数字化时代,随着各大平台纷纷推出小程序,小程序已成为企业与用户交互的重要工具,跨平台开发更是成为开发者们关注的焦点。作为开发者来说,为了满足不同用户的需求,我们需要能够快速搭建出适配于多平台的小程序,那么本文就来聊一聊小程序的优势、如何实现一站式开发多平台的小程序,以及对于小程序功能模块集成能力的期望。
151 1
简单快速搭建出适配于多平台的小程序
|
5月前
|
安全 定位技术 API
探讨如何在Flutter中集成支付、地图等第三方服务,以及集成过程中需要注意的问题和最佳实践
【6月更文挑战第11天】本文介绍了在Flutter中集成第三方服务,如支付和地图,以增强应用功能和用户体验。开发者可通过官方或社区插件集成服务,注意服务选择、API调用、错误处理和用户体验。支付集成涉及选择服务、获取API密钥、引入插件、调用API及处理结果。地图集成则包括选择地图服务、获取API密钥、初始化地图组件和添加交互功能。集成时要选择稳定插件、仔细阅读文档,处理错误,优化性能并遵循安全规范。随着Flutter生态发展,更多优质服务将可供选择。
110 2
|
5月前
|
小程序 存储 UED
如何实现一次搭建 多平台适配的小程序
【6月更文挑战第3天】如何实现一次搭建 多平台适配的小程序
|
存储 运维 数据可视化
低代码平台中的“模型驱动”与“表单驱动”有何区别?
低代码是近几年比较火的一种应用程序快速开发方式,它能帮助用户在开发软件的过程中大幅减少手工编码量,并通过可视化组件加速应用程序的高效交付。(低代码的定义来自Forrester报告,被认为是低代码一词的起源)。
低代码平台中的“模型驱动”与“表单驱动”有何区别?
|
监控 安全 前端开发
低代码PaaS平台源码:采用对象式和勾选式实现企业应用程序开发,内置10大功能引擎
管理后台低代码PaaS平台是一款基于 Salesforce Platform 的开源替代方案,旨在为企业提供高效、灵活、易于使用的低代码开发平台。低代码PaaS平台的10大核心引擎功能:1.建模引擎 2.移动引擎 3.流程引擎 4.页面引擎 5.报表引擎 6.安全引擎 7.API引擎 8.应用集成引擎 9.代码引擎 10.公式引擎。 采用与直接模块拖拽编程不一致的是,低代码PAAS采用的对象方式实现字段、API的字段类型,引入RPA实现表自动化建模;再使用选择方式对地段功能进行选择定义甚至可以插入代码进行自定义。采用前后端同一技术,可实现功能应用边使用边修改的功能。
212 1
低代码PaaS平台源码:采用对象式和勾选式实现企业应用程序开发,内置10大功能引擎
|
数据可视化 物联网 数据挖掘
应用开发组件功能介绍(一)
应用开发组件功能介绍(一)
276 0
|
数据可视化 前端开发 安全
应用开发组件功能介绍(三)
应用开发组件功能介绍(三)
290 0
|
数据可视化 物联网 机器人
应用开发组件功能介绍(二)
应用开发组件功能介绍(二)
323 0
|
监控 数据可视化 搜索推荐
只需简单编写配置文件即可构建企业级应用程序的低代码平台
一套可视化建模,描述式编程的企业应用程序开发平台。只需简单的点击鼠标,几乎任何人都可以创建功能强大的企业应用程序,实现业务流程自动化。企业创建的应用程序可以部署在移动,平板电脑和Web上,创建的应用程序可以很简单,也可以非常复杂,并且可以连接到几乎任何数据源。
只需简单编写配置文件即可构建企业级应用程序的低代码平台