Is it possible to make a distributable Vue widget with Single File Components? - vue.js

This might be a bit of an odd question, but I'll try to explain.
I'm looking to build a vue based video player widget for a client's Drupal website. The idea is to create something he can just drop in, like a JQuery plugin. However, I'd really like to leverage Vue's Single File Components (with Webpack) so I can keep everything all bundled together.
My first thought would be to use the Vue CLI, npm build and then reach into the dist/ folder and pull out the following to drop in:
<link href=/static/css/app.cf6f127cf50f4c0b2424d30fdc56c3a4.css rel=stylesheet>
<div id="my-widget"></div>
<script type=text/javascript src=/static/js/manifest.e12c1c4a9566f686d69f.js></script>
<script type=text/javascript src=/static/js/vendor.47037dd92c40b3f38949.js></script>
<script type=text/javascript src=/static/js/app.3f1bab5cc5b1be1127b2.js></script>
Although this feels off, is there a better way to achieve this? Keep in mind his website is NOT a Vue app, but I want this widget to be built LIKE a Vue app.

I don't know if I understand 100 percent, as far as I know, it is possible. It doesn't matter how you bundle your app. It is a matter of architecture. You can use vue.js partly, like widget.
First when you set Vue instance, just set element with your target element.
new Vue({
el: '#my-widget'
});
If you want your client to set element himself, make some functions to create vue widget. (considering multiple vue instance or state sharing blah blah...)
// you can provide simple function like this (I'm sure it needs to be more.)
const Widget = {
createWidget(el) {
new Vue({
el: el
});
}
};
// on client side
Widget.createWidget('#his-widget');
On bundling, if you want your widget to be bundled together with client's Drupal website. Let him import your widget like other libraries. You can build your widget with npm run build in vue-cli and then give it to him so that he can include it.

Thanks to #yuriy636 for answering my question. The CLI 3.0 allows to build as a library or a web component. docs
Also I found the following article which goes into more depth
https://vuejsdevelopers.com/2018/05/21/vue-js-web-component/

Related

How to Export Vue component and reuse it in any html page passing parameters?

I'm new to Vue 3 and I just created my first real life Vue project.
I would like to use and distribute this component (and it's subcomponents) to be used in any html page.
It's easy, right?
<div id="app"></div>
<script src="/js/chunk-vendors.99a5942c.js"></script>
<script src="/js/app.042d60b5.js"></script>
But how can I pass parameters to the main component when reusing it in some ordinary html page?
Parameters can be passed and read as globals:
<div id="app"></div>
<script>
window.myNamespace = { foo: 1 };
</script>
...
Or be passed as attributes and read from app element:
<div id="app" data-foo="1"></div>
...
This is suitable when Vue application is used as a sub-application (widget). For framework-agnostic reusable components, web components have to be used.
So I'm not sure what you're specific use case is, but if you're interested in making a multi-page app (MPA), then I suggest taking a look at the answer posted here.
What you would be doing here is actually mounting an instance of the Vue App itself onto an element every html page, and then pass props to that and it's children. Vue itself doesn't really support passing props to the root instance using element attributes, and it isn't the recommended way of using the framework, but if you are still interested in going down this route, I suggest taking a look at this answer here.
What I would suggest doing instead is taking a look at creating components, and passing those around. You can make separate files for each, and render them all in the main page, no need to create other pages. If that's something you're interested in, I suggest taking a look at routes or the making your project a multi-page app (MPA) instead of a single-page app (SPA) although the same concept would still apply, passing components to your main instance and building your app that way.
For passing parameters to components in Vue 3 I would suggest taking a look at the props page on the documentation here for more details.
I hope this is helpful! I tried my best to be thorough, I do suggest reading through the full documentation however!

NuxtJS possible to generate JUST plain HTML?

I'm really curious if I use NuxtJS right.. I just want to generate HTML pages, so basically I dont need ANY JavaScript!
But Everytime I do generate any page with Nuxt There is a lot of JS in there.
Now I managed to remove ClientSide Scripts with:
render: {
injectScripts: false
},
in the nuxt.config.js .. but now anyway there is a inlineJS script with:
window.__NUXT__={staticAssetsBase:"/_nuxt/static/1614565042",serverRendered:!0,routePath:'"/"'}
or even
<script>window.__NUXT__={staticAssetsBase:"/_nuxt/static/1614566041"}</script>
<script src="/_nuxt/3dacfb6.js" defer></script>
<script src="/_nuxt/47380cc.js" defer></script>
<script src="/_nuxt/fbdf180.js" defer></script>
<script src="/_nuxt/77b577f.js" defer></script>
<script src="/_nuxt/04f2e32.js" defer></script>
in the generated HTML.. I dont understand why there is not a simple mode to just generate very simple HTML pages without ANY overhead.
Its just about re-using components for me and using some very simple variables..
No JS have to be used at all and CSS I'm generating & combining with YARN, so no need for anything else..
Also i dont like the data-* tags .. I really dont need them. I want to create simple HTML pages with no function on clientside, but still having the function of "components" which is injected (serverside) and re-use in multiple pages.
I run Nuxt with this config:
target: 'static',
render: {
injectScripts: false
},
hooks: {
'vue-renderer:ssr:context'(context) {
const routePath = '';
context.nuxt = '';
},
},
to remove as much JS and standard stuff as possible... but seems it still not possible to remove Everything and just generate a plain HTML without anything extra.
So the question is:
How can I generate static pages with NuxtJS and not having to include ANY JS file.. specially not the standard NUXT-JavaScript code?
If you think I better should not use NuxtJS for simple clean HTMl pages tell me :)
Nuxt is not meant to be used as SSR only, it does have the whole hydration part that will bring interactivity to your app even when going full static. You could probably use another SSG like 11ty or hugo to not have any JS loaded.
But you can also use vue-lazy-hydration and prevent the hydration at the top level of your app. It's still kinda in beta but it should do the trick.
“If you think I better should not use NuxtJS for simple clean HTMl pages tell me :)”
You would be better off not using Nuxt. It’s a JavaScript framework built on top of Vue, which makes it super simple to develop SSR SPA applications.
You mention you don’t want to use JavaScript, but you would like access to components and simple variables. To me it sounds like you’d be much better off using PHP, and might enjoy the Laravel framework (though I’d recommend plain old PHP if you don’t want the overhead of an entire framework).
Laravel

Vue template render without all the extra

I have a very, very simple set of Vue components that all work. These are a simple addition on top of an existing C# app.
At the moment, these are .html files (brought into the app inside <script> tags) and .js files loaded by reference.
These all work, are very light weight, and I love it.
Now I want to compile the HTML for each component into a Vue render function, and the .js into one minified .js file.
The .js to .min.js is pretty standard, but I cannot figure out how to get the HTML to compile into the Vue render function. Everything I've found involves a LOT of overhead and running a web server which seems a massive overkill for an html->script transform, and I don't need a full web application spun up. I only need my existing, simple templates transformed to something more friendly for production than my long-form html templates getting dumped to the page.
I'm not entirely opposed to turning the .html+.js into .vue files, but just doing that doesn't seem to overcome my issue.
I cannot figure out how to get the HTML to compile into the Vue render function
To generate a render function from a Vue template string (e.g., read from an HTML file), you could use vue-template-compiler like this:
const compiler = require('vue-template-compiler')
const output = compiler.compile('<div>{{msg}}</div>')
console.log(output) // => { render: "with(this){return _c('div',[_v(_s(msg))])}" }
Everything I've found involves a LOT of overhead and running a web server which seems a massive overkill for an html->script transform
The "web server" you mention is provided by Webpack CLI, and is intended to faciliate development. You don't need to use the dev server. The article indeed describes several steps in manually setting up a project to build Vue single-file-components, but a simpler method is to use Vue CLI to automatically scaffold such a project.

Vue: Stripe is not defined - does stripe need to be included everywhere?

When I tried to include the stripe dependency only for the template where I need it (in laravel blade):
#push ('head_scripts')
<script src="https://js.stripe.com/v3/"></script>
#endpush
..I got the error 'ReferenceError: Stripe is not defined'. So I included it in my main "head" partial, so it was included everywhere. Then I ran into the same error when going into the admin section, because it's not included in that template.
But does it really need to be included everywhere?
It is only used in one vue component like this:
<script>
let stripe = Stripe(`pk_test_zzzzzzzzzzzzzzz`);
let elements = stripe.elements();
let card = undefined;
This component seems to be evaluated even when it isn't rendered. Can I get around this issue in some way?
I was having this problem in a Vue app not using Laravel.
But to fix it i put the script <script src="https://js.stripe.com/v3/"></script> in my index.html
Then when referencing Stripe in a component i used window.Stripe That pointed to the script and fixed the ReferenceError: Stripe is not defined error.
Putting script in my index.html worked, but gave me performance issues when I published because it loads the script on every single page, instead of just where it's needed.
So instead I used import {loadStripe} from '#stripe/stripe-js/pure';. It delays loading Stripe until loadStripe is called.
This article helped me use the import:
Importing Stripe.js as an ES Module into Vue

multiple pages app and vuejs

I am trying to use vuejs in a multiple pages app, say I have two pages:
/home and /account, I created two js files, home.js and account.js, home.js is included in home.html and account.js is included in account.html, this works quite well until I started to use webpack 4, webpack combines files into a single main.js, how to work with a single main.js in my use case? thanks
You should be able to have more than 1 Vue instance, for example, for home.js:
new Vue({
el: '#home'
...
and for account.js:
new Vue({
el: '#account'
...
and then just wrap the content of home.html with an id="home" and wrap the content of account.html with id="account"
You can take a look at this template as an example or starting point. The idea is the same no matter the backend technology.
https://github.com/danijelh/aspnetcore-vue-typescript-template
You can create modules for pages which you want to enhance with Vue and import its bundle. There's also a medium article for more details :)