如何创建一个库,公开可供分布式 .mjs 文件使用的单个 Vue 组件?
P粉797004644
2023-08-26 23:23:36
<p>我想创建一个捆绑到单个 .mjs 文件中的 Vue 组件。另一个 Vue 项目可以通过 HTTP 获取此 .mjs 文件并使用该组件。通过 npm 安装可插入组件是不可能的,因为其他应用程序会尝试在运行时根据配置来获取它。</p>
<p>可插拔组件需要考虑的事项</p>
<ul>
<li>可能正在使用另一个 UI 框架/库中的子组件</li>
<li>可能使用自定义 CSS</li>
<li>可能依赖其他文件,例如图片</li>
</ul>
<hr />
<p><strong>复制库</strong></p>
<p>我通过 <code>npm create vuetify</code> 创建了一个新的 Vuetify 项目</p>
<p>我删除了 src 文件夹中除 vite-env.d.ts 之外的所有内容,创建了一个组件 Renderer.vue</p>
<pre class="brush:php;toolbar:false;"><script setup lang="ts">
import { VContainer } from "vuetify/components"
defineProps<{ value: unknown }>()
</script>
<template>
<v-container>
<span class="red-text">Value is: {{ JSON.stringify(value, null, 2) }}</span>
</v-container>
</template>
<style>
.red-text { color: red; }
</style></pre>
<p>和一个index.ts文件</p>
<pre class="brush:php;toolbar:false;">import Renderer from "./Renderer.vue";
export { Renderer };</pre>
<p>我在vite.config.ts中添加了库模式</p>
<pre class="brush:php;toolbar:false;">build: {
lib: {
entry: resolve(__dirname, "./src/index.ts"),
name: "Renderer",
fileName: "renderer",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},</pre>
<p>并扩展了 package.json 文件</p>
<pre class="brush:php;toolbar:false;">"files": ["dist"],
"main": "./dist/renderer.umd.cjs",
"module": "./dist/renderer.js",
"exports": {
".": {
"import": "./dist/renderer.js",
"require": "./dist/renderer.umd.cjs"
}
},</pre>
<p>由于我使用自定义 CSS,Vite 会生成 styles.css 文件,但我必须将样式注入到 .mjs 文件中。基于这个问题,我正在使用插件 vite-plugin-css-injected-by-js。</p>
<p>构建时,我获得了包含自定义 CSS 的所需 .mjs 文件</p>
<hr />
<p><strong>使用组件</strong></p>
<p>我通过<code>npm create vue</code>创建了一个新的Vue项目</p>
<p>出于测试目的,我将生成的 .mjs 文件直接复制到新项目的 src 目录中,并将 App.vue 文件更改为</p>
<pre class="brush:php;toolbar:false;"><script setup lang="ts">
import { onMounted, type Ref, ref } from "vue";
const ComponentToConsume: Ref = ref(null);
onMounted(async () => {
try {
const { Renderer } = await import("./renderer.mjs"); // fetch the component during runtime
ComponentToConsume.value = Renderer;
} catch (e) {
console.log(e);
} finally {
console.log("done...");
}
});
</script>
<template>
<div>Imported component below:</div>
<div v-if="ComponentToConsume === null">"still loading..."</div>
<component-to-consume v-else :value="123" />
</template></pre>
<p>不幸的是,我收到以下警告和错误</p>
<blockquote>
<p>[Vue warn]:Vue 接收到一个已成为响应式对象的组件。这可能会导致不必要的性能开销,应该通过使用 <code>markRaw</code> 标记组件或使用 <code>shallowRef</code> 而不是 <code>ref</code> 来避免。</p>
</blockquote>
<blockquote>
<p>[Vue warn]:找不到注入“Symbol(vuetify:defaults)”。</p>
</blockquote>
<blockquote>
<p>[Vue warn]:执行设置函数期间出现未处理的错误</p>
</blockquote>
<blockquote>
<p>[Vue warn]:执行调度程序刷新期间出现未处理的错误。</p>
</blockquote>
<blockquote>
<p>未捕获(承诺中)错误:[Vuetify] 找不到默认实例</p>
</blockquote>
<p>有人知道我缺少什么或如何解决它吗?</p>
Vuetify 不提供隔离组件,需要初始化插件,您需要在主应用中执行此操作:
确保
vuetify
在项目 deps 中不重复,以便库和主应用程序使用相同的副本。lib应该使用
vuetify
作为开发依赖,并在Rollupexternal
中指定它,以防止项目全局的东西与lib捆绑在一起: