Create quick prototype with Vue and Less (2020)

We’re been bombarded with building tools such as Webpack, Gulp and Grunt and what not, but you still want to create something quick, without having an advanced editor by hand and you just want to start on the fly.

Ghost blog has a place where you can inject code for Site Header and Site Footer for something quick and dirty. I want to make PageIndex app where headers are listed.

Ghost Settings: /ghost/#/settings/code-injection

This is actually a good year where ES6 is working on Chrome and you can load modules if you want, but let’s keep it simple! Write code..., press save..., and check website! That's the reoccurring workflow I was about to do.

To start of we need two libraries LESS and Vue.

Quickstart

<!-- Site Header -->
<style rel="stylesheet/less" type="text/less"></style>
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js"></script>
<!-- Site Footer -->
<div id="quickstart-vue-app">Vue Component Load Here</div>
<script src="https://unpkg.com/vue@2"></script>
<script></script>
Quickstart Example
Less v2.7.1 & Vue v2.6.11
Note the vue@2 for the latest version omit @2
Vue Component Load Here

Make Vue work

;(() => {
    const App = new Vue({
        template: `<div class="quickstart-app">You! 
					<span class="quickstart-app__hello">Hello</span> <span class="quickstart-app__world">World</span>
    			   </div>`
    })
    App.$mount('#quickstart-vue-app')
})()
Code within the <script></script> tags
Vue Component Load Here

Make LESS work

.quickstart-app {
  background-color: #0fb8ad;
  color: green;
    
  &__hello {
    background-color: ##1fc8db;
    color: yellow;
  }
  
  &__world {
    background-color: hotpink;
    color: black;
  }
}
Style within the <style rel="stylesheet/less" type="text/less"></style> tags

Vue Component Load Here

Make template modular in script tag

<script type="text/html" id="quickstart-app--app-tpl">
<div class="quickstart-app">You! 
	<span class="quickstart-app__hello">Hello</span> <span class="quickstart-app__world">World</span>
</div>
</script>
<script>
;(() => {
    const App = new Vue({
        template: '#quickstart-app--app-tpl'
    })
    App.$mount('#quickstart-vue-app')
})()
</script>
template is replaced with script element id: #quickstart-app--app-tpl
Vue Component Load Here

That’s it!

You can start building & styling. Happy prototyping!

<!-- Site Header -->
<style rel="stylesheet/less" type="text/less">
.quickstart-app {
  background-color: #0fb8ad;
  color: green;
    
  &__hello {
    background-color: ##1fc8db;
    color: yellow;
  }
  
  &__world {
    background-color: hotpink;
    color: black;
  }
}
</style>
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js"></script>
<!-- Site Footer -->
<div id="quickstart-vue-app">Vue Component Load Here</div>
<script src="https://unpkg.com/vue"></script>
<script type="text/html" id="quickstart-app--app-tpl">
<div class="quickstart-app">You! 
	<span class="quickstart-app__hello">Hello</span> <span class="quickstart-app__world">World</span>
</div>
</script>
<script>
;(() => {
    const App = new Vue({
        template: '#quickstart-app--app-tpl'
    })
    App.$mount('#quickstart-vue-app')
})()
</script>

One script loads them all

Another option is make things little bit more modular if you have access to a project folder, but still you don’t want to use zero building tools. Have your project folder look like this, for example:

/content/images/files/js/quickstart/
  index.js
  quickstart.less
  quickstart--app-tpl.html
  quickstart--helloworld-tpl.html
File structure
Ghost Blog can only access files from /content/images/ folder on the browser and to make it easier to maintain, I created some sub folders files/js/quickstart.

Have your HTML page load like this:

<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.1/less.min.js"></script>
<script src="https://unpkg.com/vue"></script>
<script src="/content/images/files/js/quickstart/index.js"></script>
Quickstart with one file that loads them all.

Then have a main file that does the fetching and attach the currentScript element.

;(() => {
	const d = document,
		loadTemplate = url =>
			fetch(url)
				.then(response => response.text())
				.catch(console.error.bind(console, 'FAIL: loadTemplate')),
		loadTemplates = templates => {
			const promises = templates => {
				const list = []
				templates.forEach(i => list.push(loadTemplate(i)))
				return list
			}

			return Promise.all(promises(templates)).catch(
				console.error.bind(console, 'FAIL: Promise.all')
			)
		},
		projectFolder = '/content/images/files/js/quickstart/',
		templates = [
			`${projectFolder}quickstart.less`,
			`${projectFolder}quickstart--app-tpl.html`,
			`${projectFolder}quickstart--helloworld-tpl.html`
		],
		prependStyle = (el, css) => {
			const style = d.createElement('style')
			style.innerHTML = css
			el.prepend(style)
		}

	loadTemplates(templates)
		.then(values => {
			const [appStyle, ...rest] = values
			return less.render(appStyle).then(({ css }) => [css, ...rest])
		})
		.then(values => {
			const [appStyle, appTpl, helloworldTpl] = values

			// Component: Helloworld
			const Helloworld = {
				name: 'Helloworld',
				template: helloworldTpl,
				data: () => ({
				}),
				methods: {},
				created() {}
			}

			// Main Component: App
			const App = Vue.extend({
				name: 'QuickstartApp',
				template: appTpl,
				components: {
					Helloworld
				},
				data: () => ({
				}),
				methods: {},
				mounted() {
					prependStyle(this.$el, appStyle)
				}
			})

			const QuickstartApp = new App()
			QuickstartApp.$mount(d.currentScript)
		})
})()
File: /content/images/files/js/quickstart/index.js
.quickstart-app {
  background-color: #0fb8ad;
  color: green;
    
  &__hello {
    background-color: ##1fc8db;
    color: yellow;
  }
  
  &__world {
    background-color: hotpink;
    color: black;
  }
}
File: /content/images/files/js/quickstart/quickstart.less
<div class="quickstart-app">You! 
	<Helloworld />
</div>
File: /content/images/files/js/quickstart/quickstart--app-tpl.html
<span class="quickstart-app__helloworld">
    <span class="quickstart-app__hello">Hello</span> <span class="quickstart-app__world">World</span>
</span>
File: /content/images/files/js/quickstart/quickstart--helloworld-tpl.html