I really enjoy vue.js, and prefer it to React et al.
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
.js
files, but how to separate/include<template>
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:
-
<script>
doesn't work if your file does include non-JavaScript code -
<link>
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.
component-one.html
- Each file consists of
<template>
,<style>
,<script>
etc. tags; just plain HTML, essentially - To use components in a new app, I simply add this:
vue_components.loadComponents ( ['component-one','component-two','...'] , function(){ // Initialise router and mount app router = new VueRouter({routes}) ; app = new Vue ( { router } ) .$mount('#app') ; } ) ;
The vue_components
object is defined in a separate JS file (my version requires JQuery, for the load
method):
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($("<div id='"+id+"' style='display:none'>")); var url = me.components_base_url+component+'.html' ; $('#'+id).load(url,function(){ callback() }) ; } }
This adds each component in their own <div>
at the end of <body>
, 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!
Top comments (3)
Interesting idea! Thank you for sharing this.
Just a few JS advice. (You might lose a little bit of browser support, but since you are using object method shorthand, it shouldn't support IE and safari already according to MDN.)
var
anymore. Useconst
andlet
instead.me = this
, use arrow function to have the context inherited.Promise.all
)Or
Not both. Although they are essentially the same thing, it is important to have consistency.
Thanks! This is what it looks like in proper ES6 (some parts omitted):
You could probably replace jQuery with fetch but you lose IE (Edge works).
If IE is a requirement and since you don't need to do anything fancy you could try using a library like nanoajax so you can replace jQuery with that.