bekwam courses

Vue.js Component Notes

January 27, 2019

One of the difficulties in learning a new programming language is understanding the same keyword or concept expressed in different ways. Sometimes, the differences are just shorthand or style. Other times, the differences strengthen an application's design. This article contains some notes I've taken about Vue.js Components. These are some tradeoffs of the packaging and registration methods described in the Guide.

HTML

The code presented in this article uses core Vue. The following is the index.html file. vue.js is imported along with a Javascript file main.js. The document contains a single div "app" which will be referenced later in the Vue app instance.

    
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BKCourse - Components</title>
</head>
<body>
<div id="app">
</div>
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
	<script type="module" src="main.js"></script>
</body>
</html>

    

main.js is added using type=module. This is required for the ES2015 Modules demo, but not required for the Global Component or Local Component demos. In each section, I'll be swapping different contents in and out of main.js. main.js will be downloadable at the end.

Global Components

main.js


Vue.component('global-component', { template: '<p>Global Component</p>' })

const app = new Vue({
    el: '#app',
    template: `
        <div>
            <global-component />
        </div>
    `
})

Viewing the page adds the global-component template -- a paragraph tag -- into the containing Vue app instance div.

Browser Screenshot
Global Component Template Added to App

global-component is available for immediate use in the Vue app instance. While completely functional, using Global Components can lead to a problem called "namespace pollution". As the application grows larger and involves more developers, the likelihood of two developers naming components the same thing increases. Picture two developers working independently naming their components "report-component" or "form-handler". Through reviews and a consistent naming convention, you can mitigate the problem. However, it's better to have Vue enforce the component name uniqueness before any conflicts arise.

The global definition must appear prior to its use in the Vue app instance.

Local Components

To create a Local Component, create an object using the var or const keyword. "const" is preferred to prevent a programmer for accidentally changing a variable. This object is referenced in the components field of the Vue app instance.

As mentioned in the guide, it's a best practice to use the kebab casing (ex, naming-like-this) instead of the camel casing (NamingLikeThis). This is because HTML is case insensitive and naming-like-this is easier to read than NAMINGLIKETHIS or naminglikethis. However, camel casing is used in the Javascript declaration because dashes are not allowed in variable names.

main.js

    
const LocalComponent = { template: '<p>Local Component</p>'}

const app = new Vue({
    el: '#app',
    template: `
		<div>
		    <local-component />
		</div>
    `,
    components: { 'local-component' : LocalComponent }
})    
    

As with the Global Components demo, the LocalComponent paragraph is inserted in the Vue app instance div.

Browser Screenshot
Local Component Template Added to App

ES2015 Modules

ES2015 Modules are neither specific to nor required by Vue. However, most of the examples outside of the Guide seem to be using them. This includes the Vue.js codebase itself. Modules strengthen application design through a principle called "information hiding". The Vue Javascript is segmented into a collection of files outfitted as ES2015 Modules. By Vue convention, a file will export a single component (this is not an ES2015 requirement). Each individual file shares only one component with outside callers. The component itself might contain many functions, variables, or other components. These details are "hidden" from the caller and won't lead to conflicts with other components.

The import and the export keywords were when type=module was specified in the index.html. This code creates a component and exports it for use in other modules. "export default ES2015Component" indicates that this is the sole component exported from the .js file. The JS file is stored in a subdirectory "components" in accordance with a Vue convention.

components/ES2015Component.js


const ES2015Component = { template: '<p>ES2015 component</p>'}

export default ES2015Component

On the main.js side, the component is imported. This variant of the import statement associates what is exported -- ES2015Component -- with a name "es2015". Notice that es2015 does not appear in the ES2015Component.js file. As with the Local Component demo, the components field of the Vue app instance is set to this variable and associated with a kebab-case name. The kebab-case name is inserted into the template for the Vue app instance.

main.js


import es2015 from './components/ES2015Component.js'

const app = new Vue({
    el: '#app',
    template: `
		<div>
		    <es2015-component />
		</div>
    `,
    components: { 'es2015-component' : es2015 }
})

This screenshot shows the demo. As with the other examples, the component's paragraph is inserted into the Vue app instance div.

Browser Screenshot
Module Component Template Added to App

Subcomponents

This next demo shows a component being imported into another component with a surprise twist! As with the previous demo, the template of a component "ParentComponent" is inserted into the Vue app instance div tag. Additionally, the ParentComponent makes use of a component of its own "ChildComponent". Three Javascript files are involved in this demo.

components/ChildComponent.js

This file contains a single exported component with a paragraph tag in the template.

    
// Note: I'm hidden unless you import me
const ChildComponent = { template: '<p>child component</p>'}

export default ChildComponent    
    

ChildComponent.js is imported into a second file, ParentComponent.js. ChildComponent is imported under the name "cc" which is used in ParentComponent's components field. It's aliased as "child-component" and applied to the ParentComponent template.

components/ParentComponent.js


import cc from './ChildComponent.js'

const ParentComponent = { 
    template: `
		<div>
			<p>parent component</p>
			<child-component />
			`,
    components: {
		'child-component': cc
    }
}

export default ParentComponent

Finally, the main.js file itself imports ParentComponent and applies it to the Vue app instance template.

main.js


    import pc from './components/parentComponent.js'

const app = new Vue({
    el: '#app',
    template: `
		<div>
		    <parent-component />
		</div>
    `,
    components: { 
		'parent-component' : pc
    }
})

Viewing the example shows the templates chained together. Notice the nested structure that has developed in the Vue window. ChildComponent is not a child of Root, but rather ParentComponent.

Browser Screenshot
Subcomponent Template

The Twist!

As mentioned earlier, the benefit of ES2015 Modules is information hiding. Without an explicit import to ChildComponent, the Vue app instance has no knowledge of ChildComponent. Vue is able to define its own ChildComponent. See the following revised main.js from the previous demo.

main.js


import pc from './components/parentComponent.js'

const ChildComponent = {
	template: '<p><em>Wait...What?</em></p>'
}

const app = new Vue({
    el: '#app',
    template: `
		<div>
		    <parent-component />
		    <child-component />  <!-- not your parent's child -->
		</div>
    `,
    components: { 
		'parent-component' : pc,
		'child-component' : ChildComponent
    }
})

The corresponding browser view shows two different renderings by two different components sharing the name "ChildComponent". The Vue tab gives some insight as to what is going on. There is a ChildComponent associated with Root and one with ParentComponent.

Browser Screenshot
Two ChildComponent Definitions

You wouldn't set out to duplicate names like this. However, if you are integrating a component, you don't need to be aware of all the names used thoughout. This example, defined a ChildComponent at the app instance level and also buried a definition in a hidden ChildComponent.js file.

The Guide sections on Components are clear. This article added demo code and emphasized the principle of information hiding. The final demo in the article showed how to identically-named components could coexist in an application. While not something you'd plan for, this is a condition that often arises in larger apps where your assmembling pieces and can't constantly go back over the assembly to fix names.

Resources

The files referenced in the article can be downloaded from this zip file. The main.js file was manipulated throughout the article. Various sections are commented with the final demo Vue app instance in effect.


Headshot of Carl Walker

By Carl Walker

President and Principal Consultant of Bekwam, Inc