vue.js modules in the browser, the cheap way
Tags: vue, browser, javascript, jquery
Published: 2018-04-05 14:10:42

---
title: vue.js modules in the browser, the cheap way
published: true
description: Between server-side preprocessing and RequireJS, there is a simple, reliable way to (re-)use due components in the browser
tags: vue, browser, javascript, jquery
---

I really enjoy vue.js, and prefer it to React <i>et al.</i>
One advantage of vue is the ability to use it in the browser directly, without having to pre-process it on the server, with webpack or similar. But how to separate your vue components in a purely browser-based setup?
* You can put your JavaScript into <code>.js</code> files, but how to separate/include <code>&lt;template></code>s?
* How to keep JavaScript, templates, and (potentially) CSS together?

Ideally, I want to put JS, template code, CSS, and potential dependencies (e.g. non-vue JS libraries) for one component in a single file. However:
* <code>&lt;script></code> doesn't work if your file does include non-JavaScript code
* <code>&lt;link></code> didn't work for me
* RequireJS didn't work either (didn't dwell on it though)
* Up-and-coming ES6 include/require doesn't seem to be there/wide-spread enough yet

I found a low-tech solution that works for me, and may be of use to some of you, so here goes:
* I put all my vue components into a single directory, one file each, e.g. <code>component-one.html</code>
* Each file consists of <code>&lt;template></code>, <code>&lt;style></code>, <code>&lt;script></code> etc. tags; just plain HTML, essentially
* To use components in a new app, I simply add this:

<pre>
vue_components.loadComponents (
    ['component-one','component-two','...'] , 
    function(){
        // Initialise router and mount app
        router = new VueRouter({routes}) ;
        app = new Vue ( { router } ) .$mount('#app') ;
    } 
) ;
</pre>

The <code>vue_components</code> object is defined in a separate JS file (my version requires JQuery, for the <code>load</code> method):

<pre style='font-size:9pt'>
var vue_components = {
	template_container_base_id : 'vue_component_templates' ,
	components_base_url : 'https://my.favourite.server/resources/vue/' ,
	loadComponents : function ( components , callback ) {
		var me = this ;
		var cnt = 0 ;
		$.each ( components , function ( dummy , component ) {
			cnt++ ;
			me.loadComponent ( component , function(){
				if ( --cnt == 0 ) callback() ;
			} ) ;
		} ) ;
	} ,
	loadComponent ( component , callback ) {
		var me = this ;
		var id = me.template_container_base_id + '-' + component ;
		if ( $('#'+id).length > 0 ) return callback() ;
		$('body').append($("&lt;div id='"+id+"' style='display:none'>"));
		var url = me.components_base_url+component+'.html' ;
		$('#'+id).load(url,function(){ callback() }) ;
	}
}
</pre>
This adds each component in their own <code>&lt;div></code> at the end of <code>&lt;body></code>, templates, css, code, and all. Only when all components are loaded, the router and app are initialised. AFAICT, this works in every browser that works with JQuery. I just started using this system, and will undoubtedly improve on it, but I welcome any constructive feedback!