wuruoyun/vue-component-lib-starter

Consume a Component Library File from a CDN in Another Vue Application?

mkuehn opened this issue · 2 comments

Hello,

I am successfully building a component library that renders some UI using vue-component-lib-starter, and it is working great. We are hosting this library on a CDN, like https://example.com/library.umd.js and we pull it into other non-Vue websites where it is the only Vue-powered item on the site using the "vanilla" example from https://github.com/wuruoyun/vue-component-lib-starter#use-your-component-library. This is working just as we had hoped, and lets us work on one component and share it with others.

However, we are now working on a new Vue-based application that needs this library as well. I can get the library working following the "vanilla" example as mentioned above in the project's index.html file, but then that requires we use <script src="https://unpkg.com/vue"></script> (which seems to me like a second copy of Vue that shouldn't be needed) to load Vue and a script block to render the included library using Vue on the page (in index.html for the project) outside of the normal build process. This is all in addition to the output that is created when we run npm run build to generate the Vue application to deploy:

<!DOCTYPE html>
<html lang="en">
	<head>
		<!-- CSS for the external library -->
		<link rel="stylesheet" href="https://example.com/external-library.css">
	</head>
	<body>
		<!-- This is where the external library renders its content. -->
		<div id="external-shared-content">
			<external-library />
		</div>

		<!-- This is the section I want to replace somehow.-->
		<script src="https://unpkg.com/vue" type="text/javascript"></script>
		<script src="https://example.com/external-library.umd.js"></script>

		<script>
			var app = new Vue({
				el: '#external-shared-content'
			})
		</script>
		<!-- END section to replace somehow -->

		<!-- This is where the actual content of the new app I'm working on will go. -->
		<div id="app"></div>
		<!-- built files will be auto injected -->
	</body>
</html>

How would I go about possibly including external-library.umd.js from the CDN URL in the build process, and pass it to the new Vue application so that I don't have to include a reference to another copy of Vue in index.html? I think it would also be OK to keep loading the component library with the script tag, as long as I could somehow pass it through to the Vue instance of the new application. Overall, I'm looking for a "cleaner" implementation of what seems like should be a simple process.

I've tried looking into Vue loader, and Webpack's val-loader, and these seem like what I need, but I can't seem to get a working configuration that loads this file from the CDN and injects it into the build of the new application. I've also tried accessing window['external-library'] in the JavaScript itself, which has what sounds like a helpful install() method on it, but I haven't had any luck there, either.

If possible, please provide an example of consuming a library generated with this package in another Vue application, or let me know of any existing examples I haven't been able to find yet. :)

Thanks,
Matthew

Hey @mkuehn

I am working on a hosted library on a CDN as above, however what I am doing is rendering different views / components on different clients using the same library. I have found a way to bring in an externally hosted umd.js file and extract the component and use it somewhat normally.

To do this I have made a utility called external-component.js i am then importing that in App.vue let's say for ease like this;

import externalComponent from "../external-component";
const AppWrapper = () => externalComponent("http://localhost:8081/dist/pwa.umd.js");

Then I can use that component as normal;

export default {
  created(){
    console.log(AppWrapper)
  },
  components: {
    AppWrapper,
  },
};

My external-component.js looks like this;

export default async function externalComponent(url) {
    const name = url.split(`/`).reverse()[0].match(/^(.*?)\.umd/)[1];

    if (window[name]) return window[name];

    window[name] = new Promise((resolve, reject) => {
        const script = document.createElement(`script`);
        script.async = true;
        script.addEventListener(`load`, () => {
            resolve(window[name]);
        });
        script.addEventListener(`error`, () => {
            reject(new Error(`Error loading ${url}`));
        });
        script.src = url;
        document.head.appendChild(script);
    });

    return window[name];
}

Using the above method, you do not need to use another instance of Vue!! You also don't need the pollyfill as it is being brought in as a component, not imported in the HTML!

The issue I am now facing is adding programmatic routes to Vue Router from within this component. If you have anything you could think of that would work that would be awesome. I have not come across any related posts anywhere that are anywhere near what I am attempting to achieve, so any help would be much appreciated.

I was thinking of going down the route of making it a plugin instead of a library, but cannot seem to get that to work.

Thanks
Jay

@mkuehn , my apologies for the super late reply to the query. The example HTML (in earlier version of this starter) is not suitable for your "new Vue-based application". Publishing your library to NPM is the way to reuse, rather than CDN.