Home  >  Q&A  >  body text

How can I create a library that exposes a single Vue component that can be used by distributed .mjs files?

<p>I want to create a Vue component bundled into a single .mjs file. Another Vue project can get this .mjs file over HTTP and use the component. Installing a pluggable component via npm is not possible because other applications will try to get it based on the configuration at runtime.</p> <p>Things to consider with pluggable components</p> <ul> <li>May be using a subcomponent from another UI framework/library</li> <li>May use custom CSS</li> <li>May depend on other files, such as images</li> </ul> <hr /> <p><strong>Copy library</strong></p> <p>I created a new Vuetify project via <code>npm create vuetify</code></p> <p>I deleted everything in the src folder except vite-env.d.ts and created a component 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>and an index.ts file</p> <pre class="brush:php;toolbar:false;">import Renderer from "./Renderer.vue"; export { Renderer };</pre> <p>I added library mode in 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>and extended the package.json file</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>Since I use custom CSS, Vite generates a styles.css file, but I have to inject the styles into the .mjs file. Based on this question, I'm using the plugin vite-plugin-css-injected-by-js.</p> <p>When building, I get the required .mjs file containing the custom CSS</p> <hr /> <p><strong>Using components</strong></p> <p>I created a new Vue project via <code>npm create vue</code></p> <p>For testing purposes, I copied the generated .mjs file directly into the new project's src directory and changed the App.vue file to </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>Unfortunately, I get the following warning and error</p> <blockquote> <p>[Vue warn]: Vue received a component that has become a reactive object. This can cause unnecessary performance overhead and should be avoided by marking components with <code>markRaw</code> or using <code>shallowRef</code> instead of <code>ref</code>. </p> </blockquote> <blockquote> <p>[Vue warn]: Injection 'Symbol(vuetify:defaults)' not found. </p> </blockquote> <blockquote> <p>[Vue warn]: An unhandled error occurred during execution of the setup function</p> </blockquote> <blockquote> <p>[Vue warn]: An unhandled error occurred during execution of a scheduler refresh. </p> </blockquote> <blockquote> <p>Uncaught (in promise) Error: [Vuetify] Default instance not found</p> </blockquote> <p>Does anyone know what I'm missing or how to fix it? </p>
P粉797004644P粉797004644419 days ago485

reply all(1)I'll reply

  • P粉668146636

    P粉6681466362023-08-27 10:19:56

    Vuetify does not provide isolation components and needs to initialize the plugin. You need to do this in the main application:

    app.use(Vuetify)

    Make sure vuetify is not duplicated in the project deps so that the library and main application use the same copy.

    lib should use vuetify as a development dependency and specify it in Rollup external to prevent project global things from being bundled with the lib:

    external: ["vue", "vuetify"]

    reply
    0
  • Cancelreply