Tag Archives: Vue.js

Practical Fullstack approach to Vue3

I am a fullstack developer. I do user support, requirement analysis, nginx configuration, backup handling, integrations and css. Much of my work is centered around Node.js and Vue.

I do not love Vue and I am not fascinated with it, nor interested in its internal working. It is a tool to write reactive (2-way-binding) web applications and to modularize web code (write small reusable components).

I started using AngularJS (v1) years ago. That changed the way I thought of web development and I became more productive making better web applications. However AngularJS is kind of abandoned now, and it is a much heavier framework than need. So I started transitioning to Vue2 some years ago thinking of it as AngularJS-light. In most ways Vue2 is nicer than AngularJS, except sometimes it (the reactivity system) does not work (predictably). Well, Vue2 probably works exactly as it is written to work, but for me as a developer I think I do what works, and then it fails for some delicate detail that I can figure out if I have time, maybe. That is waste of time and it adds uncertainty to my job.

I have this feeling with Vue2 that I need a plan (a design pattern) and I still have not found one that works well. Now I started migrating Vue2 to Vue3 and things change a bit (and things break a bit). So now I really want to find simple design principles for my Vue3 applications, that I can follow so everything works without me thinking about it.

State

The real challenge when writing an (single page web) application is managing the state:

  • Information about session
  • I/O and error handling
  • Incoming data, updating state and UI, avoiding conflicts
  • Application settings, like filters and user choices
  • Data validation and invalid-data-feedback to user
  • Data modelling

This is harder than writing a good user interface. So the client-side-design needs to be state-first, not UI-first. Also

  1. I am migrating things from Vue2 to Vue3 that were originally AngularJS. If the state, business logic, I/O, were dependent on AngularJS-stuff I would be stuck in AngularJS.
  2. I can write this state in generic JS (not specific for web/UI) and thus make it possible to also run it on a server, exposing it as APIs and do automated testing

So I am not interested in Veux. Perhaps it can run backend, I do not care. This is how I think of my architecture:

  1. GUI (as thin layer as possible)
  2. Web component business logic (plain JS, no Vue, can run in Node.js)
  3. State (plain JS, no Vue, can run in Node.js)
  4. Server Side (Node.js)

Most code can (ideally) run in 2-4, and can thus be tested in Node.js. Vue is only about (1).

State – Vue – Interface

Some applications are large and state consists of many modules. Some are small. For a simple example I think of state as (this is, admittedly based on Vue2-experience, where you need to consume state data in a way that makes it reactive in Vue).

STATE = {
  ro : { ... things that are readonly to Vue (like server data) ... }
  rw : { ... things that Vue can change (like filter choices or user input) ... }
  api: { ... functions that can do stuff with state ...}
}

Typically I would get this from a plain JS factory function where I can supply dependencies that are possibly implemented (for I/O) differently on Browser and Node.js:

function MyStateFactory(libIO, lib1, lib2) {
const state = { ro:{} , rw:{} , api:{} };
... set up state ...
return state;
}

How do I make this state available (and reactive) in my Vue application and Vue components? I can admit that in the past I have been lazy and done things like (pseudo code):

Vue.Component({
  data : function() {
    return { state : STATE };
  },
  ... more stuff
});

That kind of works in many cases! But I have also ran into problems. In a real application you have 3 types of components:

  1. Those that depend only on supplied props
  2. Those that depend only on state
  3. Those that depend on a mix of props and state

In theory, all components should be (1) and all other design is rotten (you may think). In practice 2 and 3 are useful too.

So the real questions are:

  1. How do you expose state, as data and functions, so changes can be picked up by the right components?
  2. How do you design components so they update when they should?

AngularJS – Vue2 – Vue3

AngularJS has a function that recalculates everything, over and over again until it gets the same result twice. Then it updates the DOM accordingly. AngularJS does not detect changes to data automatically, however when you use its api to manipulate data, you are also telling AngularJS that you are changing data, and the function mentioned before can run. If you change data from outside angular you may need to use $scope.$apply() to tell Angular to refresh.

In Vue2, when you make an object part of “data” in a component, it becomes “reactive”. This is very implicit and it has some limitations (with Arrays, for example). What if a prop changes? What if you have a method that uses external data (as a state outside Vue), does that trigger refresh of the component? If a parent refreshes does that refresh the children? What if a child element deep down in data/prop changes? What if properties in data are replaced/added rather than modified? All I say is that to someone so stupid and ignorant as me it is not obvous how to make Vue2 just work.

Vue3 is more explicit (I interpret that as Vue2 was unpredictable not only for me, and that the Vue2 abstraction was leaky). While AngularJS and Vue2 hide the mechanism that drives reactivity Vue3 has the very explicit functions:

  • ref
  • reactive
  • readonly
  • shallowRef
  • shallowReactive
  • shallowReadonly

These functions are what connects the Vue controllers to the outside-of-Vue-world, and makes it possible for Vue to detect changes.

Vue3 – a first simple practical design

So, now we can think that we have something like this:

var state = { a:1 };
state = Vue.reactive(state);

Vue.component({
  props : { /* parameters to component here */ },
  data : { /* component local data here */ },
  methods : { /* access state via functions here */ }
});

Lets explore what happens and what works!

Vue.reactive()

We need to understand – exactly – the difference between the argument and the result of Vue.reactive():

var state_reactive = Vue.Reactive(state_original)

I have experimented (test0) and found that:

  • They share the same data, that is, the data lives in state_original
  • If you add/delete/modify data in one of them, it is immediately available in the other
  • state_orginal, and none of its children, will ever be reactive
  • state_reactive, and all of its children, will always (more on this later) be reactive
  • state_orginal and state_reactive (and all of its corresponding children) are never the same object (everything in state_reactive is Proxy to state_orginal)

The consequence of this is that your state-library must modify data in state_reactive, if you want Vue to be notified of the change (when Vue anyway refreshes for any reason, it will get the changes).

So the problem becomes:

var state = StateFactory();

// will not work because the internal state of StateFactory is not affected
state = Vue.reactive(state)

// this has severe implications:
//  1) Vue is modifying something inside the state library
//     (that was explicitely supposed to be read-only)
//  2) How does the state library protect itself?
//     possibly keeping an internal ro, and replacing the state.ro regularly
state.ro = Vue.Reactive(state.ro)

So I would say that you will need to design your state library with this in mind.

  1. Be clear that state.ro, state.ro can be made reactive this way, or
  2. Expose something else that can be made reactive (state.updated), or
  3. If the “Vue” object is present, the library could use it and take care of making the right things reactive itself, or
  4. The library has some way to notify of updates (an update callback function), and in the Vue-world, you let that callback be a function that updates something that IS reactive already.

Regardless of this little problem it is a much better situation than the Vue2-way of adding external objects in data and hoping for the best.

What Vue3 Components are updated?

Now that we know what data outside of the component that is reactive, the questions are:

  • what changes trigger the component to be updated?
  • when do child components update?
  • can any number of components, independently, be triggered by the same reactive variable?
  • if a reactive variable is used in a method, does that trigger an update
    • even if the method is not always called
    • even if the variable is not always used in the method (only some branches)
    • even if the result of the method does not change
    • even if the result of the method is not rendered
    • when the method called on any other occation (like polling)
  • is there any risk that some components are updated multiple times (in one cycle)?
  • in what order are the components updated, and can it matter?
  • what is enough to trick/force a component to update?
  • can a component update only partly?

I do not really want to know. I just want a way of designing my components so they work predictably. What I have found in the past is that when I write one big Vue-component (or application) I have no problems. But when I start modularizing it, with components that are sometimes but not always nested, that is when problems start. I have asked myself questions (with Vue2) like:

  • can one component override/replace what triggers another component, making the earlier “trigger-subscriber” dead?
  • can I end up with deadlocks, infinite recursion or mutual dependencies?
    (it has happened)

We kind of can not keep all these details in mind when building an application. We need to have a simple design that just works every time.

Single Application

I have written a simple test (test1) application with no child components. I want to explore how little reactivity works.

// Start with a STATE:
  STATE = { lines: [] };

  setInterval(() => {
    updateLines(STATE);  // implemented elsewhere somehow
  }, 2000);

// Make reactive
  STATE.lines = Vue.reactive(STATE.lines);

// Make a simple app (not showing everything)
  Vue.createApp({
    data: {
      function() {
        return { lines : STATE.lines }
      }
    }
  });

// In HTML Template, do something like
  <tr v-for="l in lines">...</tr>

This works (as expected) IF updateLines does not replace the lines array. So I have experimented and found:

Vue.reactive(STATE.lines)updateLines keeps linesworks
Vue.reactive(STATE.lines)updateLines replaces linesweird behaviour
Vue.reactive(STATE)updateLines keeps linesworks
Vue.reactive(STATE)updateLines replaces linesweird behaviour
Vue.shallowReactive(STATE)updateLines keeps linesnot at all
Vue.shallowReactive(STATE)updateLines replaces linesnot at all

The problem here is that when STATE.lines becomes a new array, the data:function in createApp does not re-run, so we keep track of and old array that STATE no longer cares about (the weird behaviour is that updateLines kept part of the old lines-structure and that “garbage” is still reactive).

It is clearly a sub-optimal situation that the implementation of state, and not just what STATE looks like, matters. 4 alternatives do not work, 2 work but are bad design. What about:

  STATE = Vue.shallowReactive(STATE);

// Make a simple app (not showing everything)
  Vue.createApp({
    data: {
      function() {
        return { state : STATE }
      }
    }
  });

// In HTML Template, do something like
  <tr v-for="l in state.lines">...</tr>

This works also sometimes:

Vue.shallowReactive(state)updateLines keeps linesnot at all
Vue.shallowReactive(state)updateLines replaces linesworks
Vue.reactive(state)updateLines keeps linesworks
Vue.reactive(state)updateLines replaces linesworks

The only thing that works regardless how updateLines is implemented, is to make all of STATE recursively reactive and make all of it data in every component. Exactly what I admitted above that I had been doing with Vue2.

shallowReactive is appealing, but it depends on the inner implementation of state, and that kind of design will quite possibly give you nasty bugs later when something changes.

So, making your data embrace STATE, or part of states works only if you know how state updates itself, unless you make exactly all of STATE recursively reactive. I think more people than I find that sledgehammer approach unsatisfying.

How about state signalling that something is updated, by updating a primitive variable (value, to avoid using ref and then ending upp with value anyway)? Note that updated.value is truthy from the beginning, and it will alwasy be truthy (++ only operation on it ever), but Vue does not know that so it needs to read and check.

  STATE = { updated: {value:1} , lines: [] };

// Make just updated reactive
  STATE.updated = Vue.reactive(STATE.updated);

  setInterval(() => {
    updateLines(STATE);
    STATE.updated.value++;
  }, 2000);

// And in Vue.createApp
  data : function() {
           return {
             lines : STATE.lines,
             updated : STATE.updated
           }
         }

Now, we can not rely on

  • lines, because it is not reactive at all
  • updated in data because it is not used in the template

However, there are some things that work. First it seems nice to replace lines in data with a method:

  methods : {
    getLines : () => { return STATE.lines; }
  }

  <tr v-for="l in getLines()">...<tr>

However, that is not enough because lines is still not reactive. But here are 3 simple little hacks that do work (and of course there are or more):

  <-- output updated in the template - not typically wanted -->
  Updated: {{ updated.value }}

  <-- display table (parent of lines) "conditionally" (always truthy)-->
  <table v-if="updated.value">

  // use updated.value in getLines()-function
  getLines() => { return STATE.updated.value ? STATE.lines : []; }
  getLines() => { console.log(STATE.updated.value); return STATE.lines; }
  // assuming devnull exists and does nothing
  getLines() => { devnull(STATE.updated.value); return STATE.lines; }

You can use this.updated.value if you use function() instead of ()=>{}. I find it quite a positive surprise that the above works even if neither lines nor updated is in data:

  STATE.updated = Vue.reactive(STATE.updated);

  data: {}
  methods: {
    getLines : () => { return STATE.lines; }
  }

  <table v-if="updated()">
    <tr v-for="l in getLines()">...</tr>
  </table>

This is beginning to look like something that appeals to my sense of simplicity. The conclusion for simple application, external state, and no components is that you have two (simple to explain) options:

  1. Make all of STATE (the exposed data, not functions) recursively reactive. Use it directly from everywhere.
  2. Make only one variable, STATE.updated, reactive. Make sure to poke (++ is probably ok) that variable whenever you want anything else to update.

Beware of doing things like value = STATE.some.child.value for anything that is expected to work beyond the next “tick”. Please note that I have not build a big single-application-zero-components application this way. So for now, this is just a qualified hypothesys.

You can check out the final result as test1.

Application with components

I split my application into three components. The application itself has no data or methods.

  • Application (test2)
    • Market
    • Portfolio
    • Copyrigh notice (nothing reactive, should fail to update)

This worked fine with no changes to reactivity compared to test1. So I got confident and made components for the lines:

  • Application (test3)
    • Market
      • Market-quote
    • Portfolio
      • Portfolio-stock

This did not immediately work. The template in Market had this content:

  <test-market-quote v-for="q in getQuotes()" :q="q">

getQuotes is still depending on update.value and is called every time, but it “happens” to return the same, modified, quote-lines every time. So the test-market-quote does not realise anything changed:

  APP.component('test-market-quote',{
    props : {
      q : Object
    },
    data : function() { return {}; },
    template: '#test-market-quote',
    ...

So I needed to replace (in a method in the test-market-quote component):

  return API.valueOf(stock) < STATE.trader.cash;
//with
  return STATE.updated.value && API.valueOf(stock) < STATE.trader.cash;

in order to make sure some method in the child component also is dependent on updated.value. This was not needed when there were no child components, becuase the parent component had another dependency on updated.value and that cause the update of the entire component (but obviously not forcing its children to update). That worked in one component, but the other component had no methods to add a dependency to, so I successfully replaced

  <td>{{ s.name }}</td>
<!-- with -->
  <td>{{ upd(s.name) }}</td>

//and added
  methods : {
    upd : (v) => { return STATE.updated.value ? v : 0; }
  }

Reality check!

This is beginning to be ridiculous. How many obscure hacks are we going to use to not have to rely on the reactivity system that is at the heart of Vue? These kind of hacks are also a source of (subtle) bugs and can make refactoring harder. The problem I have experienced with Vue is that I need to understand how things work under the hood. But with these different updated.value hacks the cure is getting as bad as the disease (that said, these hacks are probably anyway things you need to do, if components do not update when you want them to).

So I was thinking about a universal fix for updated.value (test4):

// first a reusable function
  API.yes = () => { return !!updated.value; }

// second every (child) component makes it part of its methods
  methods: {
    yes : API.yes
  }

// third, every component template has a root element, add a v-if
  <div v-if="yes()">
    .. component template body ..
  </div>

This works! It is rather simple.

Two working practial design choices

So, we have arrived at two rather simple (conceptually) ways to build predictable Vue3 applications that rely on external (Vue-independent) state code:

  1. Make all state recursively reactive, from the root
  2. Only make an update-variable reactive, and make all components depend on it

Obviously there does not have to be exactly ONE state. There can be some log-state, some io-state, some user-setting-state, some data-state and they could possibly work differently.

Regardless, it is important to understand that if there is an exposed state, the code responsible for the state may update objects, replace object, reuse objects and move objects around in the state (tree), unless the state is very clear and strict about this.

How is the recursive reactivity-tree updated?

We have a plain object:

  x1.a.b.c.d = 5;

// make it recursively reactive

  x2 = Vue.reactive(x1); 

// we add something in x1

  x1.a.b.c2: {d : 3.14} };

// NOW c2 and c2.d can not possibly be reactive, because if
// Vue could know that we did that to a child of x1, we would
// not need to make a reactive copy (proxy) of x1 in the first
// place. The above operation does not trigger anything in Vue.

// How does it happen that c2 and c2.d *eventually* end up
// begin reactive?, that is
//   isReactive(x2.a.b.c2.d) => true

// Well I think when you do that (isReactive) you are accessing
// x2, x2.a, x2.a.b and eventually x2.a.b.c2. That means, you
// are asking the Proxy b to give you its child c2 - which it was
// not aware of. But now it is!
// So it can find c2, make it recursively reactive before giving it
// to you so you can resolve x2.a.b.c2.d and pass it to isReactive().

That is how I think it works.

Vue2 vs Vue3

I really have not code very much in Vue3 yet. But I have done enough research to write this post. I think Vue3 seems to be MUCH better.

In Vue2 I ended up doing:

STATE = { ro:{}, rw:{}, api:{} };

Component({
  data : function() {
    state_ro : STATE.ro
  },
  methods : {
    stuff : function(
      state_ro.foo ...     // is there any difference?
      ... STATE.ro.bar     // does it matter if I use
    )                      // state_ro or STATE.ro?
  }

This mess is GONE with Vue3. Making things reactive is 100% explicit. data can be used exclusively for local variables to that component instance. methods can be used to get external state data, and if it is reactive that methods will trigger and the component will update.

I can imagine that this can essentially be done with Vue2 as well. But with the implicit reactivity system based on putting external state in data I never managed to figure it out.

When my code is migrated to Vue3 I will never look back at Vue2. I think.

Performance

I get a bad feeling when I think of thousands of lines, where each line is a complex object (like an invoice), and everything is made reactive, recursively. And that there are thousands of components on my web page, that each depend on several objects/properties in every invoice. And that these thousands of lines may just be discarded when something new arrives over the network, garbage collector trying to make sense of it, and new complex lines comes in to be made reactive. Perhaps it takes 0.05s and it is no problem. Perhaps it always works.

To just render everything again is usually no problem, very predictable, and rather easy to optimize if needed.

But I think like I did with AngularJS. Use the reactivity-system inside the components. But do not let the components, or the Vue Application for that matter, be made aware of everything. Give to it what it needs to do, to render everything and to allow for user input/edit where required.

A second thought…

I wrote a minesweeper game (test5) with the intention of abusing the reactivity system and see if performance got bad. It turned out I wrote a too good implementation, and the reactivity system worked perfectly. So I failed to prove my idea, but I learnt something on the way: that the reactivity system is better than I first thought – not the implementation in Vue but the idea, fundamentally.

My fear was that I essentially have two trees of objects

  • Data, nested data, deeply nested data, complicated data and separated data
  • UI, nested components, deeply nested components and separate components

My fear was that data consists of tens of thousands of reactive nodes, and each of them will trigger an update to hundreds or thousands of UI-components. However…

…in reality the data-tree will much resemble the ui-component-tree. Often there will be 1-to-1 relationships. This means that nothing will be updated in vain, and everything (and only that) which should be updated will be updated, typically each triggered by one or a few reactive “events”.

What would be wasteful?

  • If a single small component depends on a lot of spread out data – but that is already wasteful design because everything needs to be calculated every time – which is probably a bigger problem than the reactivity system
  • If the data tree is much larger than needed (for the current presentation). Lets assume we have a game with a few AI players. Each AI player is just presented as name, score and a few more fields. But the AI implementation may be several megabytes of complex data in memory. There is NO reason to make that data reactive out of laziness.

My basic design in AngularJS was:

  STATE ==> Presentation Data ==> Apply Filters ==> Apply Paging ==> Give to Angular

This means that the Presentation data is already structured quite much as the UI and its components, and it does not contain more data than necessary (or it does not have to, if it gives problems).

Disclaimer

I will be doing work based on this “reasearch” in the near future. I will update this post if I discover something relevant.

Web Components 2020

Web Components is standard technology (as opposed to libraries, frameworks and tools that come and go) for web development.

It allows you to simply write custom html elements in JavaScript. Such components become framework-independent and can be shared and reused. They are simple to use. In your html-file, simply:

<html>
  ...
  <script src="wc-blink.js"></script>
  ...
  <wc-blink>This should blink</wc-blink>
  ...
</html>

The code of wc-blink is quite simple (view), I stole it (here) and modified it slightly.

Another advantage of Web Components is the Shadow DOM allowing private CSS: the styles wont escape, override or be overridden.

This technology has been around for a while… but the bad news… it still does not work with Microsoft browsers (IE11, Edge).

I wrote a simple demo page (link).

With Polyfill you can use it with Edge. IE11 seems to be out of luck because the keyword class from ES6 must work (see code for wc-blink above) and this is not simply a matter of polyfill. There is technology to compile/transpile stuff to ES5 but in that case I can rather keep building my components in Vue.js.

Conclusion

It is actually sad that work that goes into web browser standards (to make it possible to build applications and components for the web in a good way) gets delayed by MS simply not supporting it.

I dont think web development should be more complicated than including scripts and writing html. Web Components allow just that.

If you need to support IE11, simply ignore Web Components until you don’t need to support IE11 anymore.

If you are fine supporting just Edge, there are ways not to need to include the 117kb polyfill for everyone.

I can not afford to break IE11 at this point, and neither am I willing to transpile stuff. I stick to Vue.js components.

Force Vue Update ($forceUpdate)

Occationally you want to force some part of your Vue application to update. One situation is that I have a “big” web application not written in Vue, and somewhere I add a Vue component. Something in the world around it changes but it is not aware of it, so I want to force it to update.

It seems, the vm.$forceUpdate method is just updating the component itself, and children with slots. I didn’t use slots, and $forceUpdate was useless.

So, if you do myVue.$forceUpdate() without success, try:

    myVue.$children.forEach(c => c.$forceUpdate());

It might do what you want. It did for me.

Vue components in Angular

I have an application written in AngularJS (v1) that I keep adding things to. Nowadays I prefer to write new code for Vue.js rather than AngularJS but rewriting the entire AngularJS application is out of the question.

However, when the need shows up for a new Page (controller in AngularJS) it is quite simple to write a Vue-component instead.

The AngularJS-html looks like this:

<div ng-if="page.showVue" id="{{ page.getVueId() }}"></div>

You may not have exactly “page” but if you have an AngularJS-application you know how to do this.

Your parent Angular controller needs to initiate Vue.

page.showVue = true;
var vue      = null;
var vueid    = null;

page.getVueId = function() {
    if ( !vueid ) {
        vueid = 'my_vue_component_id';
        var vueload = {
            el: '#' + vueid,
            template : '<my_vue_component />',
            data : {}
        };
        $timeout(function() {
            vue = new Vue(vueload);
        });
    }
    return vueid;
};

At some point you may navigate away from this vue page and then you can run the code:

vue.$destroy();
page.showVue = false;
vue          = null;
vueid        = null;

The way everything works is that when Angular wants to “show Vue” it sets page.showVue=true. This in turn activates the div, which needs an ID. The call to page.getVueId() will generate a Vue component (once), but initiate it only after Angular has shown the parent div with the correct id (thanks to $timeout).

You may use a router or have several different Vue-pages in your Angular-application and you obviously need to adjust my code above for your purposes (so every id is unique, and every component is initatied once).

I suppose (but I have not tried) that it is perfectly fine to have several different Vue-components mounted on different places in your Angular application. But I think you are looking for trouble if you want Vue to use (be a parent for) Angular controllers or directives (as children).

Vue.js is small enough that this will come at a quite acceptable cost for your current Angular application and it allows you to write new pages or parts in Vue in an existing AngularJS application.

Vue.js: loading template html files

Update 2018-05-27: A few months have passed since I wrote this post. I have used my solution/library for several real applications and it has worked very well. So everything looks exactly as it did when I posted v0.1 and that is a good thing. There are obviously improvement opportunites and probaby limitations/bugs. But for my purposes I have not encountered any problems to fix. And nobody has notified me of needed fixes.

You may want to code your Vue.js application in such way that your html templates are in separate html files, but you still do not want a build/compile step. Well, the people writing Vue dont want you do do this, but it can easily be done.

All you need is to download this single js file and include it in your Vue.js web page. All instructions and documentation required are found in the js file.

VueWithHtmlLoader-library
I wrote a little library that simply does what is required in a rather simple way. I will not hold you back and I will show you by example immediately:

  • A Rock-paper-scissors Vue-app, all in 1 file: link
  • A Rock-paper-scissors Vue-app, modularised with separate html/js files: link
  • Source of VueWithHtmlLoader library: link

These are the code changes needed to use VueWithHtmlLoader:

 * 1) After including "vue.js", and
 *    before including your component javascript files,
 *    include "vuewithhtmlloader.js"
 *
 * 2) In your component javascript files
 *    replace: Vue.component(
 *       with: VueWithHtmlLoader.component(
 *
 *    replace: template: '...'
 *       with: templateurl: 'component-template.html' (replace with your url)
 *
 * 3) The call to "new Vue()" needs to be delayed, like:
 *    replace: var myVue = new Vue(...);
 *       with: var myVue;          
 *             function initVue() {
 *               myVue = new Vue(...);
 *             }
 *             VueWithHtmlLoader.done(initVue);

My intention is that the very simple Rock-paper-scissors-app shall work as an example.

Disclaimer: the library is just written and tested only with this application. The application is written primarily to demonstrate the library. The focus has been clarity and simplicity. Please feel free to suggest improvements to the library or the application, but keep in mind that it was never my intention to follow all best practices. The purpose of the library is to break a Vue best practice.

What the library does:

  1. It creates a global object: VueWithHtmlLoader
  2. It provides a function: VueWithHtmlLoader.component() that you shall use instead of Vue.component() (there may be unsupported/untested cases)
  3. When using VueWithHtmlLoader.component(), you can provide templateurl:’mytemplate.html’ instead of template:’whatever Vue normally supports’
  4. The Vue()-constructor must be called after all templateurls have been downloaded. To facilitate this, place the code that calls new Vue() inside a function, and pass that function to VueWithHtmlLoader.done()
  5. The library will now load all templateurls. When an html template is successfully downloaded over the network Vue.component() is called normally.
  6. When all components are initiated, new Vue() is called via the provided function

Apart from this, you can and should use the global Vue object normally for all other purposes. There may be more things that you want to happen after new Vue() has been called.

The library has no dependencies (it uses XMLHttpRequest directly).

Background
Obviously there are people (like me) with an AngularJS (that is v1) background who are used to ng-include and like it. We see Vue as a better, smaller AngularJS for the future, but we want to keep our templates in separate files without a build step.

I also expect many developers with various backgrounds to try out Vue.js. They may also benefit from a simple way to keep templates in separate files without worrying about a build tool.

As I see it, there are different sizes of applications (and sizes of team and support around them).

  1. Small single-file applications: I think it is great that Vue supports simple single-file applications (with x-template if you want), implemented like my game above. This has a niche!
  2. Applications that clearly require modularization, but optimizing loading times is not an issue, and you want to use the the simplest tools available (keep html/js separate to allow standard editor support and not require a build step). AngularJS (v1) did this nicely. I intend Vue to do it nicely too with this library.
  3. Applications built by people or organizations that already use Webpack and such tools, or applications that are so demanding that such tools are required.

I fully respect and understand the Vue project does not want to support case 2 out of the box and that they prefer to keep the Vue framework small (and as fast as possible).

But i sense some kind of arrogance with articles like 7 Ways To Define A Component Template in Vue.js. I mean 1,2 are only useful for very small components. 3 is only useful for minimal applications that dont require modularization. 4 has very narrow use cases. 5 is insane for normal development (however, I can see cases where you want to output/generate it). And 6,7 requires a build step.

8. Put the damn HTML in an HTML-file and include it? Nowhere to be seen.

The official objection to 8 is obviously performance. I understand that pre-compiling your html instead of serving html that the client will compile is faster. But compared to everything else this overhead may be negligable. And that is what performance is all about, focusing on what is critical and keeping everything else simple. My experience is that loading data to my applications take much more time than loading the application itself.

The Illusion of Simplicity
AngularJS (v1) gave the illusion of simplicity. You just wrote JavaScript-files and (almost) HTML-files, the browser loaded everything and it just worked. I know this is just an illusion and a lot happens behind the scenes. But my experience is that this illusion works well, and it does not leak too much. Vue.js is so much simpler than AngularJS in so many ways. I think my library can keep my illusion alive.

Other options
There is thread on Stackoverflow about this and there are obviously other solutions. If you want to write .vue-files and load them there is already a library for that. For my solution I was inspired by the simple jquery example, but: 1) it is nice to not have a jquery dependency, 2) it is nice to keep the async stuff in one place, 3) the delayed call of new Vue() seems forgotten.

Feedback, limitations, bugs…
If you have suggestions for improvements or fixes of my library, please let me know! I am happy to make it better and I intend to use it for real applications.

I think this library suits some but not all (or even most) Vue.js applications. Lets not expect it to serve very complex requirements or applications that would actually benefit more of a Webpack treatment.

TODO and DONE

  • A minified version – I have not really decided on ambition/obfuscation level
  • Perhaps change loglevel if minified Vue is used? or not.
  • I had some problems with comments in html-files, but I failed to reproduce them. I think <!– comments –> should definitely be supported.