Post

Create quick prototype with Vue and Less (2020)

Harianto van Insulinde

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

html
<!-- 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

js
;(() => {
    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

;(() => { const App = new Vue({ template: `

You! Hello World

Make LESS work

less
.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

.quickstart-app-2 { background-color: #0fb8ad; color: hotpink; &__hello { background-color: #1fc8db; color: yellow; } &__world { background-color: hotpink; color: black; } }

Vue Component Load Here

;(() => { const App = new Vue({ template: `

You! Hello World

Make template modular in script tag

html
<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

.quickstart-app-3 { background-color: #0fb8ad; color: hotpink; &__hello { background-color: #1fc8db; color: yellow; } &__world { background-color: hotpink; color: black; } }

Vue Component Load Here

You! Hello World

That’s it!

You can start building & styling. Happy prototyping!

html
<!-- 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:

text
/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:

html
<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.

js
;(() => {
    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

less
.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

html
<div class="quickstart-app">You! 
    <Helloworld />
</div>

File: /content/images/files/js/quickstart/quickstart--app-tpl.html

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