Vue 加载远程组件的解决方案

背景

最近的项目有一个加载远程组件的需求。基于此我对 Vue 加载远程组件的方案进行了研究,并且整理了两个可行的解决方案。

HTML 文件 + umd 组件

这个方案是最简单、最容易实现的。组件以 umd 的格式进行打包,然后在 HTML 文件中直接使用。

<div id="app">
    <test-input></test-input>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
    // 将组件 URL 挂载到 script 标签上,然后通过 window 获取这个组件
    await lodaScript('http://localhost/component/input/0.1.0/bundle.js')
    app.component('TestInput'window.TestInput)
</script>

但是这个方案不适合在大型项目中使用,效率比较低。

Vue 工程项目 + esm /umd 组件

Vue 工程项目 + esm /umd 组件是我目前在使用的方案,但是在研究的过程中遇到了两个问题,逐一解决后,才把这个方案趟通了。

第一个问题 Relative references must start with either "/", "./", or "../"

由于我们的项目不需要兼容 IE,所以打包组件采用的是 esm 格式。打包后的组件源码如下:

import { reactive } from 'vue'
// other code...

然后在主项目中进行引用:

const { default: TestInput } = await import('http://localhost/component/input/0.1.0/bundle.mjs')

在动态导入远程组件到项目时,提示报错 Relative references must start with either "/", "./", or "../"。这是因为在浏览器中不支持以 import { reactive } from 'vue' 的方式进行导入,得把 'vue' 改成 https://..../vue.js 或者 './vue.js' 的形式才可以。平时我们这样用没问题是因为有 vite、webpack 等构建工具帮忙解决了这个问题。

第二个问题 Vue 上下文环境不同

产生上面的问题是因为要引入依赖,如果打包组件时把相关依赖都打在一起,那不就没有 import 语句了。结果试了一下还是不行,因为当前的 Vue 主项目和打包好的 Vue 组件存在两个不同的 Vue 上下文。导致在加载组件时报错,比如提示 xxx 变量找不到 这种问题。虽然主项目和远程组件使用的 Vue 方法都是一样的,但由于各自的 Vue 上下文不一样,导致主项目无法正常使用远程组件。以上两个问题困扰了我一天的时间,但是睡醒一觉后,终于想到了如何解决这两个问题。首先在浏览器上不能直接使用 import { reactive } from 'vue' 这种语句,那把它改成 const { reactive } = Vue 就能解决这个问题了。至于第二个问题,打包时不把依赖打在一起,而是在 main.js 文件中直接把整个 Vue 引进来:

import * as Vue from 'vue'
window.Vue = Vue

这样就能确保主项目和远程组件使用的是同一个 Vue 上下文。为了解决代码转换问题,我写了一个 rollup-plugin-import-to-const 插件(支持 rollup、vite),打包 esm 组件时,它会自动的把 import { reactive } from 'vue' 转换成 const { reactive } = Vue 。至此,就可以在主项目中加载远程 esm 组件了:

const { default: TestInput } = await import('http://localhost/component/input/0.1.0/bundle.mjs')

其实只要能解决上面的两个问题,不管是 esm 还是 umd、cjs 等格式,都能够实现加载远程组件的方案。比如换成 umd 的格式来打包组件,就不需要引入 rollup 插件去转换代码了,并且还能支持 webpack。唯一要做的只是在 main.js 上把 Vue 全引进来挂到 window 下。

import * as Vue from 'vue'
window.Vue = Vue

总结

远程组件的方案其实不止上面两种,比如还有直接加载 .vue 文件的方案,有个现成的 vue3-sfc-loader 插件能用。一般来说,加载远程组件的应用场景比较少,所以网上能搜到的讨论也比较少。目前比较常见的应用场景应该就是在低代码平台中加载远程组件了。

References

[1] rollup-plugin-import-to-const: https://github.com/woai3c/rollup-plugin-import-to-const
[2] vue3-sfc-loader: https://github.com/FranckFreiburger/vue3-sfc-loader

推荐阅读  点击标题可跳转

1、vue3优雅的使用useDialog

2、Vue3 除了 keep-alive,还有哪些页面缓存的实现方案

3、Vue3实现加入购物车抛物线效果组件

相关推荐

  • 七种分布式全局 ID 生成策略,你更爱哪种?
  • 大家都叫好的非典型编程书《码农翻身》更新啦
  • JDK 22 发布正式版了
  • 如何运用大模型进行文档图表Chart理解:兼看20240321年大模型进展早报
  • 爬虫新利器:揭秘Github火爆的开源IP代理池秘密!
  • 最新爆料!GPT-5已有客户上手体验:性能惊人,或将在夏天发布
  • 做实验没 GPU 机器,还记得导师爆出最脏的一句话是什么?
  • 破解大模型安全难题,360推出大模型安全能力框架
  • 联合国通过首个全球AI决议;曝微软6.5亿美元买下Inflection AI员工;联想首款AI PC下月发布丨AIGC大事日报
  • 微软深夜首推AI PC!新AI功能戳中打工人,月减10小时工作量
  • 突发:拜登对苹果下狠手,令市值暴跌6700亿,苹果强硬回应“不妥协”!
  • 换掉ES!Redis官方搜索引擎来了,效率大幅提升
  • 沉寂 600 多天后,React 憋了个大招
  • Vue 团队正式开源 Rolldown
  • 为什么阿里不推荐使用 keySet() 遍历HashMap?
  • 新零售SaaS架构:线上商城系统架构设计
  • 别做老实人了!这才是 HR 喜欢听的离职原因!
  • Vite为什么快呢?快在哪?说一下我自己的理解吧
  • Vue 的 style 加了 scoped 也会样式冲突?可怕!
  • 我真服了!媳妇刚发3.8万年终奖,就要拿出四十万还房贷,说她不愿给银行付利息。可我觉得不应该提前还房贷。