django cms boilerplate webpack documentation

51
django CMS Boilerplate Webpack Documentation Release 1.0.0 Divio AG April 11, 2018

Upload: others

Post on 05-Jan-2022

36 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate WebpackDocumentation

Release 1.0.0

Divio AG

April 11, 2018

Page 2: django CMS Boilerplate Webpack Documentation
Page 3: django CMS Boilerplate Webpack Documentation

Contents

1 Documentation 31.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71.3 Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181.4 Coding Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231.5 Tips and Tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451.6 Contribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

i

Page 4: django CMS Boilerplate Webpack Documentation

ii

Page 5: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

The django CMS Boilerplate Webpack is the most complete django CMS based Boilerplate for rapid development.It uses the full potential of ES2015+, Webpack and the Bootstrap framework for developing responsive, mobile-firstprojects on the web, and implements various best practices from within the front-end community.

This Boilerplate can be used with standalone django CMS websites as well as on the Divio Cloud platform.

The latest stable version is available on GitHub - https://github.com/divio/djangocms-boilerplate-webpack.

Contents 1

Page 6: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

2 Contents

Page 7: django CMS Boilerplate Webpack Documentation

CHAPTER 1

Documentation

General

Note: Welcome to the starting point of this documentation. Throughout each section we familiarise you with theGuidelines, Structure, /testing/index and other essential modules for our front-end code. The goal is to createa common coding ground for all developers.

What’s inside

Note: This Boilerplate includes and configures a number of components.

Webpack & Babel

For JavaScript bundling and preprocessing we use Webpack, Babel with ES2015 preset and some essential plugins forsmaller builds and easier testing.

We use Gulp as a wrapper around Webpack for consistency.

Sass

For CSS pre-processing, we use Sass. In particular, we use:

• LibSass for fast SASS compilation

• Gulp JS and the gulp-sass plugin to compile SASS files

• the official Sass port of Bootstrap

All styles should be created in /private/sass, and will be compiled to /static/css.

Note: We do not use Webpack capabilities for bundling CSS by default, but it is not forbidden.

Bootstrap

The full Bootstrap library is imported via the Sass component and the JavaScript component.

3

Page 8: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Note: django CMS Boilerplate Webpack uses the default 12 column based grid setting. You can change this settingin private/sass/settings/_bootstrap.scss.

The Glyhpicon icon set has been disabled in favour of the custom icon set that can be built with gulp icons.

JavaScript

We are implementing the latest 3.x.x versions of jQuery as they are released.

• http://jquery.com

In addition several commonly-used shims are available to you including:

• The HTML5 Shiv

• Outdated Browser

• console.log wrapper

Gulp

We use Gulp to manage our frontend workflow.

Template Language

As this is a django CMS based boilerplate, naturally we are using the Django template language.

In order to implements assets efficiently, django-sekizai and aldryn-snake are implemented within thebase_root.html template. This gives you the {% addtoblock "js" %}{% endaddtoblock %} and{% addtoblock "css" %}{% endaddtoblock %} template tags in addition to the django defaults.

Example

{% load sekizai_tags %}{% addtoblock "css" %}<link href="{% static 'css/theme.css' %}" rel="stylesheet">{% endaddtoblock %}{% addtoblock "js" %}<script src="{% static 'libs/jquery.min.js' %}"></script>{% endaddtoblock %}

• http://docs.django-cms.org

Configuration

There are several configuration files included such as:

• EditorConfig within .editorconfig

• ESLint within .eslintrc.json

• Stylelint within .stylelintrc.json

Please mind that they are ignored if your editor doesn’t support them.

4 Chapter 1. Documentation

Page 9: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Installation

Note: The following dependencies should be installed on your system in order to work with this Boilerplate.

• Node JS: http://nodejs.org/

• Gulp: http://gulpjs.com/

You can find most installation steps within osx-bootstrap but in short:

1. run brew install node when using Homebrew

2. run curl -L https://npmjs.org/install.sh | sh

3. run npm install -g gulp

At last make sure you correctly configured your paths.

Setup

Run the following command to install all requirements from within the root of the package:

• npm install to install the requirements from package.json

Gulp Commands

All front-end related tasks are handled via the Gulp task runner:

• gulp sass compiles sass and splits critical from non-critical css

• gulp lint starts all linting services using .eslintrc.js and .stylelintrc.js

• gulp webpack compiles javascript

• gulp icons generates an svg-sprite

• gulp optimise optimises images within /static/img and svgs within /private/svg

For generic usage use:

• gulp default runs the default gulp commands

• gulp watch runs the gulp watch defaults

• gulp build this is the command that is also run on Divio Cloud when deploying

Note: You can append --debug to almost all of the commands to enable debugging, sourcemaps, disable minifica-tion and more.

For a full set of commands checkout the tasks inside the Gulpfile.js.

We love code over configuration.

Configuration

Note: The Boilerplate ships pre-configured and runs out of the box if the Installation steps are followed properly.However most components can be freely configured.

1.1. General 5

Page 10: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

WYSIWYG

The CMS allows for custom style sets within the editor. This ables the user to choose certain pre-sets or colours. We already added the general Bootstrap utilities for you. The file can be found at:/static/js/addons/ckeditor.wysiwyg.js.

Custom Icons

We added support for custom svg-icon generation through Gulp. There are some configuration steps required if youwant to use them:

1. Add your SVG fonts to /private/svg. Gulp gets all SVG files from the /private/svg/**/*.svgpattern and generates the fonts for you.

2. Run gulp icons to generate the svg-sprite

3. Uncomment // @import icons; from /private/sass/components/_all.scss to include it inyour gulp build

The gulp icons command will automatically generate the /private/sass/components/_icon.scss filewhere you find the class reference and mixins for all icons.

The generated svg-icons will use the .icon css namespace for all custom icons. We recommend using the icon(*)mixin instead of @extend .icon-*.

Basic usage

Once installed in a Divio Cloud or django CMS project, django CMS Boilerplate Webpack is ready to use.

6 Chapter 1. Documentation

Page 11: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

In your project

See Templates for guidelines on how to set up your project templates so that they take advantage of what it has to offer.

Fundamentally, if your project’s templates inherit from the base.html template, they’ll be furnished with the classes,elements, hooks and other things they need.

In your applications

Your applications, if they are aware of django CMS Boilerplate Webpack, can also take advantage of it.

You could simply make your application assume that django CMS Boilerplate Webpack will be available. That’s notideal though, because it will be off-putting to people who don’t want to have to use it. A reusable application shouldhave requirements that are as generic as possible, not based on a particular frontend framework.

So, although it means a little more work for you, you should also provide more generic frontend (templates, CSS etc)support for the application, and if you like, for other Boilerplates too.

At the very least, the developers who use your application will find it easier to create templates and static file for it thatsupport their own frontend conventions if they can start with simple ones.

Divio Cloud Boilerplates

To make this easier, use the Aldryn Boilerplates application.

This provides support for multiple Boilerplates, allowing you to offer rich frontend machinery compatible with djangoCMS Boilerplate Webpack for those who want it, and generic frontend files for those who don’t, in a way that thecorrect set will automatically be chosen.

You can also add support for other Boilerplates, by adding the frontend files to namespaced directories in your appli-cation. This example of an application named djangocms_addon mentions only templates for sake of simplicity, butthe same principle applies to static files:

djangocms_addon- templates/ # the generic templates| - djangocms_addon/| - base.html- boilerplates/ # templates for particular Boilerplates| - bootstrap3/| - templates/| - djangocms_addon/| - base.html- some_other_boilerplate/

- templates/- djangocms_addon/- base.html

See Aldryn Boilerplates for more.

Guidelines

Note: This section describes guidelines for several front-end related technologies. We advise you to follow them.However it is sometimes necessary to break the rules in which case you have to watch this video and leave a commentdescribing why this was necessary.

1.2. Guidelines 7

Page 12: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

General

Note: There are global guidelines which affect every single language, file or folder.

Standards

Important:• Validate your code through the W3C validators.

• There is something called Accessibility.

• Don’t forget about HiDPI, Retina and High Resolutions displays.

• Proper fallbacks should be available if a connection is slow or features are disabled.

• Progressive enhancement, graceful degradation and responsive design are buzzwords you care about.

• Develop with modularity and extensibility in mind.

• Documentation is your friend.

Spacing

Important:• Use 4 spaces for indentation.

Not 2, 3 or 8 – no tabs – if you are able to do 3 3/4, that’s good enough

Line Length

Important:• Don’t breach 120 characters per line.

Not even for HTML. We even encourage you to use 80 characters per line. Yes, screens have got much bigger over thelast few years, but your brain hasn’t. Better to use screen estate for splits, anyway.

Naming

Important:• lowercase, camelCase or hyphened separation are all good; use no special characters except for underscore_.

• Use dashes - for file naming, unless expressly counterindicated (e.g. in HTML template names).

• Always use full words instead of abbreviations: number is better than nr.

• BEM is a nice methodology to be aware of.

“There are only two hard things in Computer Science: cache invalidation and naming things” – Phil Karlton

8 Chapter 1. Documentation

Page 13: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Quotes

Important:• We always use double "." quotes for everything, except in JavaScript, where we use single ’.’ quotes.

Comments

Note: If peppering your code with lots of comments is good, then having zillions of comments in your code must begreat, right? Not quite. It doesn’t make sense to comment every step your code makes, or to comment on things thatdon’t need to be explained.

Comments in code should describe:

• what is being done

• why it’s being done

They do not need to describe:

• how it is being done (the code already shows this)

• what you are thinking about

Section Comments

In addition to the regular comments, we introduced the section comment. Use this style to separate large chungs oflogic (which you should generally avoid). The line is exactly 80 characters long:

// #############################################################################// NAME

Inline Comments

When using comments inline, make use of the appropriate formats:

• {# ... #} or {% comment %} ... {% endcomment %} for Django templates and never <!--... -->

• // ... and /* ... */ for Sass and JavaScript

Notes

We also use several comment helpers which, if configured in your editor, add additional highlighting to your code:

FIXME:to annotate problems with the code

1.2. Guidelines 9

Page 14: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

function Calculator() {// FIXME: shouldn't use a global heretotal = 0;...

}

TODO:to annotate solutions to problems with the code

function Calculator() {// TODO: total should be configurable by an options paramthis.total = 0;...

}

DOCS:provides a simple docs link

// DOCS: https://django-cms.readthedocs.org/en/latest/

Formatting

Comments• Add proper whitespace.

• In general use lowercases except for the Notes.

bad//TODO: THIS NEEDS ADDITIONAL REVIEW//// square root of n with Newton-Raphson approximation/*** Contains various helpers, feel free to extend and adapt

*/

good// TODO: this needs additional review// square root of n with Newton-Raphson approximation/*** Contains various helpers, feel free to extend and adapt

** @class Utils

* @namespace Cl

*/

10 Chapter 1. Documentation

Page 15: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

YUIDoc

In 3.3.0 we introduced YUIDoc which uses syntax similar to JSDoc in order to further improve JavaScript documen-tation. We encourage using this style within your code, as shown in /static/js/addons/cl.utils.js.

Markup

Note: In addition to the General guidelines, the following sections describe markup specific rules.

Naming

Important:• Use underscores for HTML file naming.

• Use lowercase for all attributes.

// badtwo_column-template.html, tpl-master.html, askForAdditionalInformation.html

<DIV class="box boxHighlighted" DATA-rel="#my_modal"> ... </DIV>

// goodtwo_column_template.html, tpl_master.html or ask_for_additional_information.html

<div class="box box-highlighted" data-rel="#my-modal"> ... </div>

Indentation

Important:• Always add an indent after Django tags such as {% if %}, {% forloop %}, {% block %} and so on.

• Use single lines within {% addtoblock %} for files and multilines for <code>. It is important because ofhow sekizai works. Basically if two scripts are added through addtoblock and the contents of the block arethe same they are merged. That way you never have duplicate jQuery’s on the page. The caveat than is that thewhitespace around that script tag must match. To avoid mistakes we always do them in single line.

• Code readability always wins.

// bad{% block content %}<div class="plugin-blog">{% if true %}<p>Hello World</p>{% endif %}</div>{% endblock content %}

{% addtoblock "js" %}<script src="{% static "js/libs/jquery.min.js" %}"></script>{% endaddtoblock %}{% addtoblock "js" %}

<script>jQuery(document).ready(function ($) {

alert('hello world');});

1.2. Guidelines 11

Page 16: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

</script>{% endaddtoblock %}

// good{% block content %}

<div class="plugin-blog">{% if true %}

<p>Hello World</p>{% endif %}

</div>{% endblock content %}

{% addtoblock "js" %}<script src="{% static "js/libs/jquery.min.js" %}"></script>{% endaddtoblock %}{% addtoblock "js" %}<script>jQuery(document).ready(function ($) {

alert('hello world');});</script>{% endaddtoblock %}

IDs vs Classes

Important:• Avoid IDs wherever possible.

• Where it’s necessary to use IDs, always use unique names.

You should always use classes instead of IDs where you can. Classes represent a more OOP approach to adding andremoving style sets like box box-wide box-hint.

Try to avoid declaring ID’s at all. They should only be used to reference form elements or for in-page navigation inwhich case you need to make the name absolutely unique.

// bad<div class="box box-highlighted" id="box-8723"> ... </div><!-- IDs only for navigation jumper through <a href="#page-anchor-team"></a> --><div id="team"></div><!-- IDs only for form elements --><label for="firstname">Name</label><input type="text" name="firstname" id="firstname">

// good<div class="box box-highlighted box-8723"> ... </div><!-- IDs only for navigation jumper through <a href="#page-anchor-team"></a> --><div id="page-anchor-team"></div><!-- IDs only for form elements --><label for="field-id12-firstname">Name</label><input type="text" name="firstname" id="field-id12-firstname">

Modularity

Important: Try to keep HTML structure simple, avoiding unnecessary elements. It is sometimes easier to use asingle div with a single class rather than multiple divs with multiple classes.

12 Chapter 1. Documentation

Page 17: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

For example, lets take a look at the following code snippet:

<div class="addon-blog"><h2>My Blog</h2><p>Hello World</p>

</div>

We should build modular HTML, and take pains to avoid type selectors. Add additional classes for lead, content,author, meta info, tags and so on. The content section itself can then contain the usual HTML code:

<div class="addon-blog"><h2 class="blog-heading">My Blog</h2><p class="blog-lead">Hello World</p><div class="blog-content">

<h3>Details</h3><p>More</p><p>Content</p>

</div><div class="blog-author">Dummy Man</div><ul class="blog-tags tags">

<li class="blog-tag-items"><a href="#">News</a><li class="blog-tag-items"><a href="#">Blog</a><li class="blog-tag-items"><a href="#">Tags</a>

</ul></div>

Styles

Note: In addition to the General guidelines, the following sections describe stylesheet-specific rules.

Naming

Important:• Use lowercase in SCSS file names.

• Use only dashes in class/ID names.

// badSearch.scss, marketingSite.scss or theme-dark-blog.scss

class="blog blogItem blog_item__featured"

// goodsearch.scss, marketing_site.scss or theme_dark_blog.scss

class="blog blog-item blog-item-featured"

Nesting

Important:

1.2. Guidelines 13

Page 18: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

• Don’t overuse nesting; nest elements to a maximum of 4 indents.

With great power comes great responsibility (just wanted to throw that in here). When writing in Sass or Less lazinesscan have performance implications. While nesting is very powerful, we should avoid unnecessary levels or blocks thatcan be simplified.

// bad.nav-main {

ul {@extend list-reset;li {

padding: 5px 10px;a {

color: red;}

}}

}

// good.nav-main {

ul {@extend list-reset;

}li {

padding: 5px 10px;}a {

color: red;}

}

Formatting

Important:• Always add a space after the colon :.

• Only write one CSS property per line.

• Avoid using selectors such as div.container or ul > li > a (i.e. ad-hoc, non-namespaced) to deter-mine specificity.

• Write colour values in lowercase and avoid colour names.

// badarticle.item {

color: white;padding: 10px; margin-left: 0; margin-top: 0; margin-bottom: 10px;background-repeat: no-repeat;background-position: left top;

}

// good.item {

color: #fff;padding: 10px;

14 Chapter 1. Documentation

Page 19: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

margin: 0 0 10px 0;background: no-repeat left top;

}

Ordering

Important:• Use block-style, and group elements below.

• See scss-lint.json for a comprehensive ordering example.

1. includes (mixins)

2. extending

3. visibility, position

4. color, font-size, line-height, font-* (font relevant data)

5. width, height, padding, margin (box model relevant date)

6. border, background (box style data)

7. media, print (media queries)

8. :after, :before, :active (pseudo elements)

9. nested elements or parent referencing selectors

Note: Combine attributes such as background-image, background-color, background-repeat into a single linebackground: #fff url("image.png") no-repeat left top; when it makes sense. But remem-ber, that a shorthand like background cannot be overridden with just background-image, so use wisely!

Example

.addon-blog {// mixins@include border-radius(3px);@include box-shadow(0 0 2px #eee);// extending@extend .list-unstyled;// stylesdisplay: inline;position: relative;z-index: 1;color: white;font-size: 16px;line-height: 20px;width: 80%;height: 80%;padding: 5px;margin: 0 auto;border: 2px solid #ccc;background: #ddd;// desktop and up@media (min-width: $screen-md-min) {

1.2. Guidelines 15

Page 20: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

display: block;}// pseudo elements&:active,&:hover {

color: black;}

}

JavaScript

Note: In addition to the General guidelines, the following sections describe JavaScript specific rules. Code Conven-tions for the JavaScript Programming Language should be your Bible.

Naming

Important:• Use dot annotation test.base.js for JavaScript file naming.

• Use a library’s prefix, such as cl.xplorer.js or jquery.tablesorter.js, for file naming.

• Name variablesLikeThis, ClassesLikeThis, CONSTANTS_LIKE_THIS andevents-like-this.

• Use the js- prefix when working with JS-related selectors and do not add styling to it.

• Never use comma separation for variable declarations like var a, b, c;.

• Never use $ for variable names such as var $el = $(’.el’);.

• We are using the Cl. singleton for all custom JavaScript code.

When using jQuery to refer to a DOM instance, always use the js- prefix to separate styles from JavaScript function-ality. For example: <div class="addon addon-gallery js-addon-gallery"></div>.

In this example, addon and addon-gallery have styles attached to them, js-plugin-gallery refers to the JavaScriptfunctionality attached to the DOM element.

Even when removing the JS class (or just waiting for JavaScript to kick in), the addon should still look good.

// badCL.Utils.js, jquery_tooltip.js, testWebsiteCreateNew.js

var $jquery, current_state;var test-website-create-new;

// goodcl.utils.js, jquery.tooltip.js or test.website.create.new.js

var jquery;var currentState;var nextIndexValue;

16 Chapter 1. Documentation

Page 21: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Formatting

Important:• Always declare variables on top of the functions and not in between.

• Always use semicolons and full brackets, except in shorthand like var i = (true) ? ’yes’ :’no’;.

• Use proper spaces for if (true) {} else {} or function () {}.

// badfunction(cont){

var c = $(cont);if(c.length) {

// do something}else{

// so something else}

}

// goodfunction (container) {

var container = $(container);if (container.length) {

// do something} else {

// so something else}

}

Implementation

Important:• Keep <script> and the following starting closure on the same level.

• Separate all script tags using {% addtoblock "js" %}{% endaddtoblock %}.

• Never use JavaScript attributes on HTML elements such as onclick="" or onload="".

• Don’t add inline JavaScript within HTML, implement JavaScript through files only. Instantiate functionalityfrom within the JavaScript file instead.

// bad<div class="dashboard" id="dashboard"> ... </div>{% addtoblock "js" %}<script src="{% static "js/addons/cl.dashboard.js" %}"></script>{% endaddtoblock %}<!-- javascript gets initialised inside the template -->{% addtoblock "js" %}<script>jQuery(document).ready(function () {

Cl.dashboard.init('#dashboard');

1.2. Guidelines 17

Page 22: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

});</script>{% endaddtoblock "js" %}

// good<div class="dashboard js-dashboard" data-dashboard="..."> ... </div><!-- javascript gets initialised within the file -->{% addtoblock "js" %}<script src="{% static "js/addons/cl.dashboard.js" %}"></script>{% endaddtoblock %}

Patterns

Important:• Use the singleton pattern to avoid globals.

• Use the module pattern to structure code.

• Avoid the functional pattern

Structure

Note: This section covers naming conventions for folders and sub-directories. The correct placing of files is impera-tive for a common shared structure. It is easier to find code when you already know where it’s going to be.

General

Note: Let’s cover the core structure of this Boilerplate consisting of the main folders:

docs/private/static/templates/

The starting point for each entry is always named “base”‘‘”, with the appropriate file extension. For HTMLbase.html, Sass base.scss, JavaScript base.js – you get the idea. This way you always know which fileyou should look after first. Lets take a closer look at each individual folder:

private/

Important: This folder is not published, nor touched by preprocessing or other build libraries. Anything in hereshould be and remain safe.

This folder is intended for storing preprocessing library code (Sass, Less, Coffee, HAML, etc). Simply create a folderwithin /private with appropriate name: /sass, /less or /haml and so on as required. Always place requiredconfiguration files within the /private root.

private/- sass/

- base.sass

18 Chapter 1. Documentation

Page 23: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Hint: We are using /sass as folder name and not /scss as the language itself is called Sass. Always use the fullwritten acronym.

static/

Important: This folder is publicly available, all files can be accessed via http://yourwebserver/static/.

The default folder layout looks as follows:

static/- css/- fonts/- img/- js/- swf/- ...

If folders are not required, just simply remove them. When a folder reaches a certain file count, make use of groupingand create additional sub-directories such as /static/img/icons or /static/js/addons/jquery.

templates/

All django templates should be allocated within the /templates folder. This also applies for apps or inclusion files.When using Haml, set your configuration so templates get compiled into /templates.

The default index.html is always /templates/base.html.

Global inclusion files are placed within /templates/includes. Addons normally have their own /includes folderso they are not overcrowding the structure.

Private

Note: Let’s have a closer look at the Sass setup within /private and explain how we structured the code in there.These principles can be expanded to other preprocessors options such as Less or HAML.

Every folder within /private/sass has a file called _all.scss. This file ultimately gets imported by/private/sass/base.scss which gets compiled into /static/css/base.css. Update the _all.scss fileto include additional modules. To keep the file simple, do not include files directly within base.scss.

Let’s cover the folders individually:

components/

If a component is plug-and-playable, it probably belongs in here. Good examples are jQuery plugins or django CMSaddons. Sometimes larger application such as a shop might also be pluggable.

libs/

All independent files are placed within this folder. This implies that the order of inclusion does not matter within/sass/libs/_all.scss.

1.3. Structure 19

Page 24: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Hint: Libraries are, in their very core, plug-and-playable. The main difference between libraries and other plug-and-play components is, that if a library is removed, things will break.

mixins/

This folder is used to store additional functions or mixins which are not part of the default bootstrap eco-system.

We provide already some helper functions such as em(12px, 16px) that calculates the pixel values from a givensize in relation to the parent size.

Additionally we have mixins for managing z-index layers and hide-content.

settings/

It is very useful to store values, that are used more than twice, within their own variable. We even encourage storing allcolour values within the settings. Don’t repeat yourself. Create a sub-structure, similar to /sites if the structurebecomes more complex.

Warning: Do not add additional variables to /private/sass/settings/_bootstrap.scss. This fileis reserved for Bootstrap-only variables. Use /private/sass/settings/_custom.scss instead.

Static

Note: As /static is publicly accessible, avoid adding sensitive files into this directory.

Keep the root path of /static simple and clean. Only favicons should be placed there. They ultimately get pickedup by the base_root.html template.

css/

CSS gets automatically compiled via /private/config.rb into this folder. You can add additional files such as*.htc if required. But always add CSS files through Sass.

fonts/

All fonts should be placed here including icon fonts. You can create sub-directories to create a better overview. Thisfolder might not be required if you are implementing fonts via services such as Google Fonts or fonts.com.

img/

Demo images (which might be later integrated as media files via Filer) should be placed within/static/img/dummy. This folder will be ignored by the gulp preprocess and gulp images commands.

Make use of grouping and create additional sub-directories such as /static/img/icons or/static/img/visuals if the file count seems to be excessive.

20 Chapter 1. Documentation

Page 25: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

js/

The same structure approach as described within Private is applied to the JS directory. jQuery is an essential part andshould be treated the same as the Bootstrap component.

Templates

Note: django CMS Boilerplate Webpack follows django CMS good practices, and provides three layers of sitetemplate inheritance using {% extends %}. See Django template engine.

From the top down the three layers are:

• user-selectable page templates (base.html), which inherit from:

• base_root.html

base.html sets up the components that will rarely if ever need to be changed, and that you want to keep out of sightand out of mind as much as possible.

It contains fundamental HTML elements (<html> <body> and so on) so that these don’t need to be managed ininheriting templates.

It is also intended to be almost wholly content-agnostic - it doesn’t know or care about how your site’s pages aregoing to be structured, and shouldn’t need to. To this end it provides an empty {% block extend_root %}{%endblock %}, that inheriting templates will override to provide the page’s content.

In addition, Addons such as Aldryn News & Blog in the Divio Cloud Collection family of applications are designed touse the same JavaScript frameworks throughout, so there is no need for references to them to be made anywhere elsethan base_root.html.

content.html

content.html is the template that designers will be most interested in. It fills in the bare HTML elements ofbase.html, and allows page content structures and layouts (headings, divs, navigation menus and so on) to becreated within {% block extend_root %}.

content.html contains an empty {% block content %}, that - in templates that extend it - is filled with {%placeholder content %} as well as width cues for images etc.

User-selectable page templates

Finally, users can select templates that inherit from base.html. Even if your project has one ‘standard’ templateand some minor variations, it is wise for all of them to inherit from a base.html, so that they can all be editedindependently. Even if your ‘standard’ template changes nothing in base.html, you should not be tempted to makebase.html selectable by the user.

The following templates are always required:

• 404.html for 404 error handling. You are not obliged to construct an elaborate and hilarious tribute to sometrope in popular culture, because you are an adult.

• 500.html for critical errors, only add generic html without template tags

• base.html as entry point for {% extends %}

1.3. Structure 21

Page 26: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

includes/

Global inclusion files should be added here, for example the navigation, django messages or tracking codes. Createadditional /include folders within addons to avoid overcrowding this directory.

Page Templates

django CMS allows you to set CMS_TEMPLATES which can be chosen within the CMS by the user.

Page Types

You can save a CMS page as “Page Type” and re-use it later when creating a new page. Simply select Page > Save asPage Type .. and choose a name. You can create a new page by selecting Page > Add Page > New Page and choosethe “Page type” you want to use. That drop down does not show up if there are no page types saved.

Page types are listed separately within the menu tree underneath Page Types. This allows you to change or delete themat any time if required.

22 Chapter 1. Documentation

Page 27: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Blocks and Placeholders

The content block {% block content %}{% endblock %} and placeholder {% placeholder content%} always need to be present within page templates.

Coding Style

Note: Compare to the Guidelines and the Structure we offer many more coding conventions, most of them are beingcovered by certain linting tools such as ESLint and CSS Lint. You will also find good practice and common sensehere. Yet note that these are conventions and eventually will make their way to the guidelines.

JavaScript

Note: This section is heavily inspired by a Airbnb JavaScript Style Guide, Yandex Codestyle, Idiomatic Javascriptand lots of common sense, really.

Why?

“All code in any code-base should look like a single person typed it, no matter how many people con-tributed.” - Rick Waldron

1.4. Coding Style 23

Page 28: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

These are the fundamental principles we should follow when we design and develop software.

• Consistent code is easy to read.

• Simple code is easy to maintain.

• In simple expressions it’s harder to make mistakes.

Formatting

Blocks

Use braces with all blocks. Don’t do inline blocks.

// badif (test)

return false;

// badif (test) return false;

// goodif (test) {

return false;}

// badfunction () { return false; }

// goodfunction () {

return false;}

When you’re using multi-line blocks with if and else, put else on the same line as your if block’s closing brace.

// badif (test) {

thing1();thing2();

}else {

thing3();}

// goodif (test) {

thing1();thing2();

} else {thing3();

}

24 Chapter 1. Documentation

Page 29: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Comments

Follow the guidelines. Use // for single line comments. Place single line comments on a newline above the subjectof the comment. Between the // and the text of the comment should be one space character.

// badvar active = true; //is current tab

// good// is current tabvar active = true;

Most importantly, keep comments up to date if the code changes.

Whitespace

With proper .editoconfig and eslint setup these will be enforced automatically, but still:

• 4 spaces for tabs.

• Place 1 space before leading curly brace.

• Place 1 space before the opening parenthesis in if, while, etc.

• Place 1 space after colon.

• Place no space before the argument list in function calls and declarations, e.g. function fight() { ...}

• Set off operators with spaces, e.g. var x = 2 + 2;

• No whitespace at the end of line or on blank lines.

• Lines should be no longer than 120 characters. There are 2 exceptions, both allowing the line to exceed 120 characters:

– If the line contains a comment with a long URL.

– If the line contains a regex literal. This prevents having to use the regex constructor which requiresotherwise unnecessary string escaping.

• End files with a single newline character.

Use indentation when making long method chains. Use a leading dot, which emphasises that the line is a method call,not a new statement.

// bad$('#items').find('.selected').highlight().end().find('.open').updateCount();

// bad$('#items').

find('.selected').highlight().end().

find('.open').updateCount();

// good$('#items')

.find('.selected').highlight()

1.4. Coding Style 25

Page 30: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

.end().find('.open')

.updateCount();

Leave a blank line after blocks and before the next statement

// badif (foo) {

return bar;}return baz;

// goodif (foo) {

return bar;}

return baz;

// badvar obj = {

foo: function() {},bar: function() {}

};return obj;

// goodvar obj = {

foo: function() {},

bar: function() {}

};

return obj;

Use newlines to group logically related pieces of code. For example:

doSomethingTo(x);doSomethingElseTo(x);andThen(x);

nowDoSomethingWith(y);

andNowWith(z);

Commas

• Leading commas: God, no!

• Additional trailing comma: No

// badvar hero = {

firstName: 'Kevin',

26 Chapter 1. Documentation

Page 31: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

lastName: 'Flynn',};

var heroes = ['Batman','Superman',

];

// goodvar hero = {

firstName: 'Kevin',lastName: 'Flynn'

};

var heroes = ['Batman','Superman'

];

Semicolons

Yes, always.

// bad(function () {

var name = 'Skywalker'return name

})()

// good(function () {

var name = 'Skywalker';return name;

})();

// good (guards against the function becoming an argument when two files// with IIFEs are concatenated) this should not happen if the previous// example is enforced, but sometimes we have no control over vendor code;(function () {

var name = 'Skywalker';return name;

})();

Variables

General

Always use var to declare variables. Not doing so will result in global variables. We want to avoid polluting the globalnamespace

Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoistingrelated issues.

Use one var declaration per variable. It’s easier to add new variable declarations this way, and you never have to worryabout swapping out a ; for a , or introducing punctuation-only diffs.

1.4. Coding Style 27

Page 32: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

// badvar items = getItems(),

goSportsTeam = true,dragonball = 'z';

// bad// (compare to above, and try to spot the mistake)var items = getItems(),

goSportsTeam = true;dragonball = 'z';

// goodvar items = getItems();var goSportsTeam = true;var dragonball = 'z';

Objects

Use the literal syntax for object creation.

// badvar item = new Object();

// goodvar item = {};

Don’t use reserved words as keys.

// badvar superman = {

default: { clark: 'kent' },private: true

};

// goodvar superman = {

defaults: { clark: 'kent' },hidden: true

};

Do not use quotes for properties, it is only needed for screening reserved words which we are not supposed to use.

Arrays

Use the literal syntax for array creation.

// badvar items = new Array();

// goodvar items = [];

Use Array#push instead of direct assignment to add items to an array.

var someStack = [];

28 Chapter 1. Documentation

Page 33: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

// badsomeStack[someStack.length] = 'abracadabra';

// goodsomeStack.push('abracadabra');

To convert an array-like object to an array, use Array#slice. If you need to copy an array, use slice as well.

function trigger() {var args = Array.prototype.slice.call(arguments);...

}

var length = items.length;var itemsCopy = [];var index;

// badfor (index = 0; index < length; index++) {

itemsCopy[index] = items[index];}

// gooditemsCopy = items.slice();

Strings

Use single-quotes for strings. When programmatically building a string use Array#join instead of string concate-nation

// badvar template = '<div class="whatever">' +

message +'</div>';

// goodvar template = [

'<div class="whatever">',message,

'</div>'].join('');

If you have a complicated string buildup it’s always better to use javascript templating instead. That way templatescould have their own files with proper syntax highlighting and pre-compilation build step.

Functions

Function expressions:

// anonymous function expressionvar anonymous = function () {

return true;};

// named function expressionvar named = function named() {

1.4. Coding Style 29

Page 34: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

return true;};

// immediately-invoked function expression (IIFE)(function () {

console.log('Welcome to the Internet. Please follow me.');})();

Tend to avoid anonymous function expressions, try to always use named ones, it will save you a lot of pain goingthrough stack traces and debugging in general.

Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browserswill allow you to do it, but they all interpret it differently, which is really bad news.

// badif (currentUser) {

function test() {console.log('Nope.');

}}

// goodvar test;if (currentUser) {

test = function test() {console.log('Yup.');

};}

Never name a parameter arguments. This will take precedence over the arguments object that is given to every functionscope. It is also a reserved word.

// badfunction nope(name, options, arguments) {

// ...stuff...}

// goodfunction yup(name, options, args) {

// ...stuff...}

Prefer early returns.

// badfunction returnLate(foo) {

var value;

if (foo) {value = 'foo';

} else {value = 'quux';

}return value;

}

// good

function returnEarly(foo) {

30 Chapter 1. Documentation

Page 35: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

if (foo) {return 'foo';

}

return 'quux';}

// badfunction doThingsWithComponent(element) {

if (element.length) {// do things

}}

// goodfunction doThingsWithComponent(element) {

if (!element.length) {return false;

}

// do things}

Functions context

Prefer Function#bind over $.proxy(function (), scope).

doAsync(function () {this.fn();

}.bind(this));

If the context argument is available, it is preferred.

// bad[1, 2, 3].forEach(function (number) {

this.fn(number);}.bind(this));

// good[1, 2, 3].forEach(function (number) {

this.fn(number);}, this);

If assigning the current context to a variable, the variable should be named that:

var that = this;doAsync(function () {

that.fn();});

Properties

Use dot notation when accessing properties.

var luke = {jedi: true,

1.4. Coding Style 31

Page 36: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

age: 28};

// badvar isJedi = luke['jedi'];

// goodvar isJedi = luke.jedi;

Use subscript notation [] only when accessing properties with a variable.

var luke = {jedi: true,age: 28

};

function getProp(prop) {return luke[prop];

}

var isJedi = getProp('jedi');

Hoisting

Variable declarations get hoisted to the top of their scope, but their assignment does not.

// we know this wouldn't work (assuming there// is no notDefined global variable)function example() {

console.log(notDefined); // => throws a ReferenceError}

// creating a variable declaration after you// reference the variable will work due to// variable hoisting. Note: the assignment// value of `true` is not hoisted.function example() {

console.log(declaredButNotAssigned); // => undefinedvar declaredButNotAssigned = true;

}

// The interpreter is hoisting the variable// declaration to the top of the scope,// which means our example could be rewritten as:function example() {

var declaredButNotAssigned;console.log(declaredButNotAssigned); // => undefineddeclaredButNotAssigned = true;

}

Anonymous function expressions hoist their variable name, but not the function assignment.

function example() {console.log(anonymous); // => undefined

anonymous(); // => TypeError anonymous is not a function

32 Chapter 1. Documentation

Page 37: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

var anonymous = function() {console.log('anonymous function expression');

};}

Named function expressions hoist the variable name, not the function name or the function body.

function example() {console.log(named); // => undefined

named(); // => TypeError named is not a function

superPower(); // => ReferenceError superPower is not defined

var named = function superPower() {console.log('Flying');

};}

// the same is true when the function name// is the same as the variable name.function example() {

console.log(named); // => undefined

named(); // => TypeError named is not a function

var named = function named() {console.log('named');

}}

Function declarations hoist their name and the function body.

function example() {superPower(); // => Flying

function superPower() {console.log('Flying');

}}

For more information on hoisting refer to JavaScript Scoping & Hoisting by Ben Cherry.

Types

Type Casting and Coercion

Strings:

// => this.reviewScore = 9;

// badvar totalScore = this.reviewScore + '';

// goodvar totalScore = '' + this.reviewScore;

1.4. Coding Style 33

Page 38: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

// badvar totalScore = '' + this.reviewScore + ' total score';

// goodvar totalScore = this.reviewScore + ' total score';

Numbers: Use parseInt for Numbers and always with a radix for type casting.

var inputValue = '4';

// very badvar val = new Number(inputValue);

// badvar val = +inputValue;

// badvar val = inputValue >> 0;

// badvar val = parseInt(inputValue);

// okvar val = Number(inputValue);

// goodvar val = parseInt(inputValue, 10);

Booleans:

var age = 0;

// badvar hasAge = new Boolean(age);

// okvar hasAge = Boolean(age);

// goodvar hasAge = !!age;

Comparison Operators & Equality

Use === and !== over == and !=.

Comparison operators are evaluated using coercion with the ToBoolean method and always follow these simple rules:

• Objects evaluate to true

• Undefined evaluates to false

• Null evaluates to false

• Booleans evaluate to the value of the boolean

• Numbers evaluate to false if +0, -0, or NaN, otherwise true

• Strings evaluate to false if an empty string ‘’, otherwise true

34 Chapter 1. Documentation

Page 39: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

if ([0]) {// true// An array is an object, objects evaluate to true

}

• Use shortcuts.

// badif (name !== '') {

// ...stuff...}

// goodif (name) {

// ...stuff...}

// badif (collection.length > 0) {

// ...stuff...}

// goodif (collection.length) {

// ...stuff...}

More info in `Javascript Equality Table <https://dorey.github.io/JavaScript-Equality-Table/>`_

• Condition statements should not contain assignment operations:

// badvar foo;if ((foo = bar()) > 0) {

// ...}

// goodvar foo = bar();if (foo > 0) {

// ...}

• Logical operators should not be used for conditional branching:

// badcondition && actionIfTrue() || actionIfFalse();

// goodif (condition) {

actionIfTrue();} else {

actionIfFalse();}

• Conditions longer than the maximum line length should be divided as in the example:

// goodif (longCondition ||

anotherLongCondition &&

1.4. Coding Style 35

Page 40: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

yetAnotherLongCondition) {

// ...}

• The ternary operator should be written as in the examples:

var x = a ? b : c;

var y = a ?longButSimpleOperandB : longButSimpleOperandC;

var z = a ?moreComplicatedB :moreComplicatedC;

• If a statement is longer than the maximum line length, it is split into several lines and properly indented.

• Closing parentheses should be on a new line with the indentation of the current block statement. Tend to do thesame with object properties.

DoSomethingThatRequiresALongFunctionName(veryLongArgument1,argument2,argument3,argument4

);anotherStatement;

jQuery

Variables

Do not prefix jQuery variables with $. Always cache jQuery lookups.

// badfunction setSidebar() {

$('.sidebar').hide();$('.sidebar').css({

'background-color': 'pink'});

}

// badfunction setSidebar() {

var $sidebar = $('.sidebar');$sidebar.hide();$sidebar.css({

'background-color': 'pink'});

}

// goodfunction setSidebar() {

var sidebar = $('.sidebar');sidebar.hide();sidebar.css({

36 Chapter 1. Documentation

Page 41: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

'background-color': 'pink'});

}

Ajax

Prefer promise based $.ajax calls over callback passing into settings object.

// bad$.ajax('/url', {

dataType: 'json',success: function () {},error: function () {},complete: function () {}

});

// good$.ajax({

urls: '/url',dataType: 'json',

}).done(function myAjaxDone () {...

}).fail(function myAjaxFailed () {...

}).always(function myAjaxIsCompleted () {...

});

The nice thing about this is that the return value of $.ajax is now a deferred promise that can be bound to anywhereelse in your application. So let’s say you want to make this ajax call from a few different places. Rather than passingin your success function as an option to the function that makes this ajax call, you can just have the function return$.ajax itself and bind your callbacks with done, fail, then, or whatever. Note that always is a callback that will runwhether the request succeeds or fails. done will only be triggered on success.

It is also easier to process when you need to pass multiple success callbacks with few chained .done calls (which canalso be conditional) than passing array of functions into success property....getItems: function getItems(options) {

var opts = $.extend({url: '/items/',dataType: 'json',...

}, options);return $.ajax(opts);

}...

// and then in the appthis.getItems().done(function (products) {

...})

// and in all the different placesthis.getItems({ url: '/items/categories/12' }).done(function (products) {

1.4. Coding Style 37

Page 42: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

...});

Common patterns

Loops

Use for-in only for iterating over keys in an Object, never over an Array.

Naming conventions

Refer to guidelines. Use leading underscore to denote private methods/properties. The only place where it’s allowedto use single letter variable is in event callbacks:

// bad$('div.elem').on('click', function (clickEvent) {

...});

// good$('.js-element').on('click', function (e) {

...});

Events

When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events),pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload withoutfinding and updating every handler for the event. For example, instead of:

// bad$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {// do something with listingId

});

prefer:

// good$(this).trigger('listingUpdated', { listingId: listing.id });

...

$(this).on('listingUpdated', function(e, data) {// do something with data.listingId

});

38 Chapter 1. Documentation

Page 43: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Templates

When passing data to JS templates (using underscore.js / window.tmpl by J. Resig) - always pass an object that hasonly one property, and that property is the data you need.

Consider this template:

<% if (people) { %><%= people %>

<% } %>

// badvar markup = tmpl(template, { prop1: true, prop2: '1' });

This will throw a ReferenceError because these template engines use with underneath. Instead do this:

<% if (addon.people) { %><%= addon.people %>

<% } %>

// goodvar markup = tmpl(template, {

addon: {prop1: true,prop2: '1'

}});

You will have explicit scope without any unexpected behaviours.

Classes

It is a common pattern when creating javascript components to save all the ui elements under a common namespace.It is also a common mistake to declare an object called ui on a class.

// badvar Widget = new Class({

ui: {oneElement: null,anotherElement: null

},initialize: function (container, options) {

this._buildUI(container);},_buildUI: function (container) {

this.container = $(container);

// another bad thingthis.ui.oneElement = $('.js-one-element');this.ui.anotherElement = $('.js-another-element');

}});

There are several problems. The ui object is declared on prototype in this case, and as with all complex types isjavascript we are working with a reference to the value. That means that the same ui object will be shared across allinstances of the class, which in turn will mean that you won’t be able to use several instances on the page.

1.4. Coding Style 39

Page 44: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

// goodvar Widget = new Class({

initialize: function (container, options) {this._buildUI(container);

},_buildUI: function (container) {

this.container = $(container);this.ui = {

// scoping widget's moving parts under the same container is a good pattern as welloneElement: $('.js-one-element', this.container),anotherElement: $('.js-another-element', this.container)

};}

});

We do not always know how the widget will be used. Even if “it’s only gonna be on this page and it’s gonna bethis particular instance” seems like a valid reason not to change - it never is. We should always strive for makingcomponents independent and reusable, it’s usually not a big effort (especially if you think about before writing thewidget) and it can solve a lot of problems for you in the future.

Passing data to components

Avoid instantiating components in inline scripts. Instead pass the data to the components through data attributes.

Avoid spreading options into multiple data attributes, as it might happen that two different javascript components liveon the same DOM node and require an option with the same name. Instead use json notation.

Bad:

<div class="js-component-1 js-component-2"data-something="false" {# for component 2 #}data-value="for component 1"data-value="for component 2"> {# aw maaan #}Sad panda :(

</div>

Imagine in this case component 1 functionality is significantly affected by an option that is meant for component 2.Also if they share the same option property name, such as value - sad panda.

Good:

<div class="js-component-first js-component-second"data-component-first='{

"value": "for component 1"}'data-component-second='{

"value": "for component 2","something": false

}'>Happy panda!

</div>

Passing the data to the components is also very straightforward. This way you have the same initialisation method forall existing instances of the widget even if they have different options.

var componentElements = $('.js-component-2');var defaults = {

x: 0,

40 Chapter 1. Documentation

Page 45: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

y: 0,something: true

};componentElements.each(function () {

var componentElement = $(this);var options = $.extend({}, defaults, componentElement.data('component-second'));new ComponentSecond(componentElement, options);

}):

Magic numbers

• Avoid magic numbers. Try to parametrise or use constants.

// badsetTimeout(function () {

if (failed && count < 5) {count++;return;

}// or do stuff

}, 3000);

// bettervar POLLING_TIMEOUT = 3000;var MAX_FAILURES_COUNT = 5;

setTimeout(function () {if (failed && count < MAX_FAILURES_COUNT) {

count++;return;

}// or do stuff

}, POLLING_TIMEOUT);

switch (e.keyCode) {case keyCodes.ENTER:case keyCodes.SPACE:

x();break;

case keyCodes.TABcase keyCodes.ESCAPE:

y();break;

default:z();

}

ECMAScript 5

Use where appropriate. Use array methods for working with arrays, but don’t use them when working with array-likeobjects such as jQuery collections. For them use $.fn.each instead.

Prefer Array#forEach over for () {} loop.

var fighters = [{

1.4. Coding Style 41

Page 46: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

name: 'Jonny Cage',dead: true

},{

name: 'Kung Lao',dead: true

},{

name: 'Raiden',dead: false

}];

// badvar i;var l = fighters.length;

for (; i < l; i++) {console.log(fighters[i].name + ' ' + (fighters[i].dead ? 'lost' : 'did not lose'));

}

// goodfighters.forEach(function (fighter) {

console.log(fighter.name + ' ' + (fighter.dead ? 'lost' : 'did not lose'));});

More info on ES5 compatibility here

Styles

General

Formatting, nesting, ordering and everything else is covered by Guidelines

Main problem with CSS

There are two types of problems in CSS: cosmetic problems and architectural problems. Cosmetic prob-lems—issues like vertical centering or equal-height columns—usually engender the most vocal com-plaints, but they’re almost never showstoppers. They’re annoying, sure, but they don’t break the build.

Philip Walton Side Effects in CSS

Since CSS is global, every rule you write or override has the potential to break completely unrelated things. With thatin mind, try to avoid selectors that are too unspecific (e.g. type selectors or overly specific selectors, like .nav > ul> li > a. That selector is going to be extremely painful to extend and override if there’s going to be a “special” listitem for example. That also brings us to

Selector performance

It is always said that css selectors performance is not that important and there are no “easy-to-follow” rules for fixingit. But just to reiterate, main points:

• If your project is sufficiently big and complex or really dynamic, css selector performance may play a majorrole in the perceived rendering performance.

42 Chapter 1. Documentation

Page 47: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

• Selectors are interpreted by the browser from right to left, meaning .my-class > * will select all the ele-ments on the page all the time and check if their immediate parent has a class my-class. If there would be no> it would traverse the tree all the way up for every element, which is not very good. It is true that browsers dooptimize things like this, but you should always check for yourself.

JS selectors

We use js- prefixed selectors for referencing DOM Nodes from javascript. That means that these classes have a purefunctional purpose and styles should never be applied to them. Same type of widget could be easily represented bycompletely different sets of markup.

Magic numbers

Tend not to use magic numbers in CSS. Let’s say you want to position an element in a specific place. Try to be agnosticof the environment and don’t use values that are too specific.

.nav {height: 30px;

}

// bad.dropdown {

// it works, but imagine we are going to change// the height of the nav. we'll need to go all over the css and change// the value nowtop: 35px;

}

// good.dropdown {

top: 100%;margin-top: 5px;

}

Another example of magic numbers could be computed values. Let’s say you have a component that is created on topof existing component, like a bootstrap styled select.

// bad.custom-select {

height: 38px;padding: 14px 17px;

}

// much better.custom-select {

height: $input-height-base - 2px;padding: ($padding-base-vertical - 1px) ($padding-base-horizontal - 1px);

}

Avoid magic numbers like the plague..

Sass

1.4. Coding Style 43

Page 48: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Sass or SCSS

That one is a no-brainer. We use SCSS flavor because it is closer to CSS and easier to pick up for everyone. It alsoresolves subtle issues with indentation.

Nesting

Optimal nesting level is 2. You can go up to 4 levels (scss-lint rule), but try not to. Overused nesting usually meansthat something is wrong with the code.

Extends

In general, try to avoid extend unless you know exactly what you are doing. Only use @extend when the rulesets thatyou are trying to DRY out are inherently and thematically related.

Do not force relationships that do not exist: to do so will create unusual groupings in your project, as wellas negatively impacting the source order of your code.

http://csswizardry.com/2014/11/when-to-use-extend-when-to-use-a-mixin/

Color manipulation

When using alpha transparent colors keep in mind that rgba supports passing colors, so you can do things like this:

// badcolor: rgba(0, 0, 0, 0.85);

// goodcolor: rgba(black, 0.85);color: rgba(#000, 0.85);color: rgba($color, 0.85);

Autoprefixer

For generating vendor prefixes one should use Autoprefixer instead of relying on mixins. That way we reduce sasscompilation time and ensure that we have only prefixes that we actually need. As a good side effect we will use actualstandard CSS syntax.

Bootstrap

When using settings/_bootstrap.scss make sure that you have all the variables overwritten in the file,because overriding only some of them can lead to subtle bugs like this:

// this is what happens in the bootstrap/_variables.scss$line-height-computed: 20px !default;$padding-base-vertical: 6px !default;

// and this is a computed property from bootstrap, 34px by default$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;

// now what we want to do is to override line-height-computed in our settings file$line-height-computed: 23px;

44 Chapter 1. Documentation

Page 49: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Now we would expect that $input-height-base will be 37px, but it will be still 34px because computed prop-erties are already calculated and won’t be changed. Since bootstrap components dimensions are all interconnected tothese computed variables we should always have the full settings file. Order matters too.

Media queries

In general when using media queries with bootstrap variables, use appropriate values for appropriate type of a query.

// bad@media (min-width: $screen-sm-max) {

...}

@media (max-width: $screen-sm-min) {...

}

// good@media (min-width: $screen-md-min) {

...}

@media (max-width: $screen-xs-max) {...

}

These values differ only by 1 pixel, but it’s a very important one.

Open for discussion

• Screenshot regression testing

• autoprefixer implementation

Tips and Tricks

Note: There are several tips & tricks we found over the time that are worth mentioning.

Floating

When using float: left;, display: block; is not required anymore as every element which is floatedautomatically gets the block state. This does not apply to sub-elements.

Hidden Attribute

With modern HTML5 we can use the hidden="hidden" attribute which is a softer version of display:none;. This state can easily be overwritten using CSS or JavaScript. As such the attribute is ideal for hiding el-ements which are later displayed through JavaScript to prevent jumping behaviours. But be aware of the currentsupport.

1.5. Tips and Tricks 45

Page 50: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Image Optimisation

Images are the number one source of optimisation when it comes to file size. Optimise images using tools like CodeKit,ImageOptim or our internal Gulp command: gulp images.

Contribution

Note: You are very welcome improving this boilerplate for Divio Cloud and your everyday use, especially thedocumentation always needs love. Feel free to fork and send us pull requests and follow the guidelines from withinthis section.

Code of Conduct

• Ensure code validates against or own guidelines

• Write documentation about what you are doing

Documentation

To extend and run the documentation, you will need Python and Virtualenv installed on your computer. You also needGit and a GitHub account obviously.

In addition, follow the steps underneath to get them running:

1. clone the repository using git clone https://github.com/divio/djangocms-boilerplate-webpack.git

2. navigate to the documentation through cd djangocms-boilerplate-webpack/docs

3. run make install to install additional requirements

4. run make run to let the server run

Now you can open http://localhost:8000 on your favourite browser and start changing the rst files within docs/.

You need to be aware of reStructuredText to format the documentation properly.

Guidelines• Always start paths with a / and leave the trailing slash.

• Leave two spaces before a title.

• Write “Django”, “django CMS” or “Divio Cloud”.

• Write names properly: Sass, Bootstrap, JavaScript instead of sass (or SASS), bootstrap and javascript.

• Additional guidelines from django CMS apply.

Pull Requests

Before starting to work on issues or features, please mind the branching model:

• master is used for hotfix releases (1.1.x)

• develop is used for features and issues (1.x.x)

46 Chapter 1. Documentation

Page 51: django CMS Boilerplate Webpack Documentation

django CMS Boilerplate Webpack Documentation, Release 1.0.0

Everything that is merged to develop will be released within the next proper release (1.x.x). Major releases (x.0.0) willhave their own branches but are always merged to develop before releasing to master.

A pull request needs the consent of two developers familiar with this repository to be merged.

Releases

• Adapt the CHANGELOG.rst

• Adapt AUTHORS.rst if required

• Bump version in boilerplate.json

• Create a GitHub tag

• Add the release notes on the GitHub tag

• Build new tag on readthedocs.org

• Run bash tools/release.sh before release on Divio Cloud

• Run divio boilerplate upload to release on Divio Cloud

• Test, inform, present

1.6. Contribution 47