Zephraph

https://slides.com/zephraph/deck-7/live

Supercharging

Single file components

Justin Bennett

Front End Architect

Scripps Networks Interactive

Text

Let there be peace on CSS - Cristiano Rastelli, Badoo

Single File Component

<template>
  <div class="greeting">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style scoped>
.greeting {
  color: red;
}
</style>

Hello.vue

?

Loaders are transformations that are applied on the source code of a module.

Webpack

vue-loader

docs @ webpack.js.org

Helpful Hint #1

Use vue-cli or poi to save your sanity

<template>
  <div class="greeting">{{ msg }}</div>
</template>

<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>

<style scoped>
.greeting {
  color: red;
}
</style>

Hello.vue

But what is it really?

<template>
  <div class="greeting">{{ msg }}</div>
</template>


<script>
export default {
  data () {
    return {
      msg: 'Hello world!'
    }
  }
}
</script>


<style scoped>
.greeting {
  color: red;
}
</style>
// Template tag
module.exports = {
    render: function() {
        var _vm = this;
        var _h = _vm.$createElement;
        var _c = _vm._self._c || _h;
        return _c('div', {
            staticClass: "greeting"
        }, [_vm._v(_vm._s(_vm.msg))])
    }
}

// Script tag
__exports__["default"] = ({
    data: function data() {
        return {
            msg: 'Hello world!'
        };
    }
});

// Styles tag
exports = __webpack_require__(9)();
exports
    .push([
        module.i,
        ".greeting[data-v-b5235a7e]" 
        + "{ color: red; }"
    ]);

Helpful Hint #2

Use the ExtractTextPlugin to separate out css

What more can we do?

<template>
  <button>Click Me</button>
</template>

<style scoped>
  button {
    background-color: red;
  }
</style>

<style scoped>
  button {
    background-color: blue;
  }
</style>

Helpful Hint #3

Single file components can have multiple style blocks

Multi-brand Theming

<template>
  <button>Click Me</button>
</template>

<style scoped>
  button {
    width: 90px;
    height: 30px;
    font-size: 12px;
    border-radius: 6px;
  }
</style>

<style theme="hgtv" scoped>
  button {
    background-color: #0E9AB0;
    color: white;
  }
</style>

<style theme="diy" scoped>
  button {
    background-color: #9C1C4C;
    color: white;
  }
</style>

vue-loader doesn't care

How do I build this?

What does vue-loader do?

vue-template-compiler

(You probably shouldn't use this)

Run through parseComponent()

<template>
  <button>Click Me</button>
</template>

<style scoped>
  button {
    width: 90px;
    height: 30px;
    font-size: 12px;
    border-radius: 6px;
  }
</style>

<style theme="hgtv" scoped>
  button {
    background-color: #0E9AB0;
    color: white;
  }
</style>
let output = compiler
    .parseComponent(src);

console.log(output);
{
    template: {
        type: 'template',
        content: '\n<button>Click Me</button>\n',
        attrs: {},
        ...
    },
    script: null,
    styles: [{
            type: 'style',
            content: '\nbutton {\n  width: 90px;\n  height: ...',
            attrs: [Object],
            scoped: true,
            ...
        },
        {
            type: 'style',
            content: '\nbutton {\n  background-color: #0E9AB0...',
            attrs: [{ theme: 'hgtv' }],
            scoped: true,
            ...
        },
        {
            type: 'style',
            content: '\nbutton {\n  background-color: #9C1C4C...',
            attrs: [{ theme: 'diy' }],
            scoped: true,
            ...
        }
    ],
    customBlocks: []
}

Multi-brand Theming

<style scoped>
  button {
    width: 90px;
    height: 30px;
    font-size: 12px;
    border-radius: 6px;
  }
</style>

<style theme="hgtv" scoped>
  button {
    background-color: #0E9AB0;
    color: white;
  }
</style>

<style theme="diy" scoped>
  button {
    background-color: #9C1C4C;
    color: white;
  }
</style>

Building for HGTV

Webpack

vue-loader

theme-loader

The anatomy of a loader

modules.export = function loader(source) {
    return doSomethingWithSource(source);
}

webpack passes in module code

Return transformed source

vue-theme-loader

Graphql support

<template>
  <div class="example">{{ Greetings.hello }}</div>
</template>

<graphql>
    query Greetings {
        hello
    }
</graphql>

Webpack

vue-loader

graphql-loader

Text

Lack of editor support

Read the docs

Resources

Supercharging SFCs

By Justin Bennett

Supercharging SFCs

  • 3,021