@undkonsorten/frontend-library

3.2.0 • Public • Published

Frontend Library

@undkonsorten/frontend-library

This package is a block based (BEM) template basis based on Foundation for Sites by ZURB. It provides generalised and reusable features we are using in our Integration Library Frontend development.

Overview

Installation

cd project/frontend
yarn add @undkonsorten/frontend-library

Configuration

The following configuration is already done inside the Integration Library.

Once you have installed the package in your project, you need to do some configuration in order to use the library properly.

Note: The following instructions are based on the folder structure provided by the Foundation for Sites template.

config.yml

The config.yml file, which provides several configuration presets, needs to be adjusted in order to use the Frontend Library resources properly.

Note: You may need to create your own config.yml file by copying the config.sample.yml. Read more about it here.

LIBRARY variable

If not already exists, add the following configuration to your config.yml file:

LIBRARY: "node_modules/@undkonsorten/frontend-library/"

This variable is not necessarily needed, but it allows you to easily access various resources out of the Frontend Library by just appending the appropriate path to the LIBRARY variable. For example: LIBRARY + "src/assets/scss"

Additional Sass path

Extend PATHS.sass with the following line:

PATHS:
  sass:
    ...
    - "node_modules/@undkonsorten/frontend-library/src/assets/scss"

You need this to tell Sass the path of the additional Frontend Library resources in order to import and use them properly. At this point, it's not possible to use the previously defined LIBRARY variable since YAML doesn't have the possibility to reuse some predefined configurations.

gulpfile.babel.js

The gulpfile.babel.js provides all necessary Gulp tasks which are being used to build the Frontend out of the desired features and contents which are developed for the project.

LIBRARY variable declaration

If not already exists, add the previously defined LIBRARY variable to the configuration load process:

const { ..., LIBRARY, ... } = loadConfig();

Note: The order of variable declaration needs to be equal to the variable definition inside your config.yml file! If you define LIBRARY for example as second parameter in your config.yml file, you need to declare it as the second variable inside the const { ... } declaration.

Extend pages Task

Foundation for Sites makes use of the company-own file generator Panini. When generating the pages, Panini needs some resource paths in order to generate the appropriate files out of the given resources. Since the Frontend Library provides many features for the generation of pages, those resource paths need to be passed over.

Add the following to your pages Task to include the Frontend Library source paths:

function pages() {
  return gulp.src('src/pages/**/*.{html,hbs,handlebars}')
    .pipe(panini({
      root: 'src/pages/',
      layouts: 'src/layouts/',
      partials: ['src/blocks/', LIBRARY + 'src/blocks/'], // <- add the Frontend Library source here
      helpers: ['src/helpers/', LIBRARY + 'src/helpers/'], // <- and here
      data: 'src/data'
    }))
    .pipe(gulp.dest(PATHS.dist[buildTarget]));
}

Note that the source declaration for partials and helpers turned from string to array.

Extend watch Task

In case you are working with a linked version of the Frontend Library, it might be helpful to watch those resources and run the appropriate Gulp Tasks again in case any changes were made.

Add the following to your watch Task:

gulp.watch(LIBRARY + 'src/blocks/**/*.html').on('all', gulp.series(resetPages, pages, reload));
gulp.watch(LIBRARY + 'src/{assets,blocks}/**/*.scss').on('all', sass);
gulp.watch(LIBRARY + 'src/helpers/*.js').on('all', gulp.series(javascript, pages, reload));

The above code is only useful if you link your project with the Frontend Library using

yarn link path/to/frontend-library

Add a new feature

New features are always welcome :)

When you'd like to add a new feature, please think about the following:

  • Is it a common feature which might be used again?
  • Does the new feature solve a very own problem or is it a solution for an existing one?
  • Which contents should be provided through the Frontend Library and which one's are too specific?
  • Is it necessary to provide some settings to customize the feature? Please try to build the feature as general as possible to avoid unnecessary markup and runtime.

If you decided to build a new feature for the Frontend Library, please follow these rules:

General

  • Directory of all features: src/blocks
  • Create a new directory for your new feature, e.g. src/blocks/my-feature
  • All contents of your new feature should be located inside this folder!

Handlebars

Handlebars is used to split features into partials which can then be loaded into several files. Each feature which is available within the Frontend Library describes a Handlebars Partial. Please take a look at the usage of Handlebars in Foundation if you aren't used to it.

Naming of files

We use BEM for the naming of files.

The file name of your main file equals the name of your previously created directory for your feature: src/blocks/my-feature/my-feature.html

When you create more files for your new feature, please use the following convention:

BEM component File name
Block my-feature.html
Element my-feature__element.html
Modifier
  • my-feature--modifier.html
  • my-feature__element--modifier.html

Try to use a minimum of files for your feature. Not every Element or Modifier needs an own file!

Define Settings

At the beginning of each file, please name the Handlebars Settings which are available for the related Partial:

{{! my-feature
    ==========
    my-feature-setting-1 = <string>
    my-feature-setting-2 = <int>
    my-feature-setting-3 = [0/1] (default: 0)
    my-feature-setting-4 = [yellow, red] (default: 'yellow')
}}

Initialize default variables

After defining the settings, you can initialize the default variables. This is useful if you have defined a default for any of your variables which makes use of an explicit value, such as 1 or yellow.

Here's an example on how to initialize default values for variables:

{{var "my-variable" (ifDefault my-variable "default value")}}

This would initialize the variable my-variable with the value default value if it has not been initialized yet.

Usage

After creating the files, you can call them as Handlebars Partials from everywhere:

{{> my-feature}}
{{> my-feature__element}}
{{> my-feature--modifier}}
{{> my-feature__element--modifier}}

Sass

We use SCSS as stylesheet language, which is a modern variation of Sass.

Naming of files

For the naming of SCSS files, we also use BEM.

The file name of your main SCSS file again equals the directory name: src/blocks/my-feature/my-feature.scss

Please refer to the naming of Handlebars files in connection to BEM when creating additional SCSS files. It is useful to create separate files for specific Modifiers since you can easily import each of them when using the following described file structure.

File structure

Your SCSS files should contain the following structural elements:

  1. Import of necessary dependencies, e.g.
    // Dependencies
    // @depends helpers/inverted <- you can also specify soft dependencies to files which are always included
    @import '../feature1/feature1.scss'; // <- the '.scss' extension is not necessarily needed
    @import '../feature2/feature2--modifier'; // <- it's also possible to set modifiers of features as dependency
  2. Definition of default values for each variable which is used only in this file with the name of your feature as prefix, e.g.
    // Default Variables
    $my-feature-width: 100% !default;
    $my-feature-height: 150px !default;
  3. Mixin as content wrapper with the name of your file and frontend-library- prefix, e.g.
    @mixin frontend-library-my-feature {
        // type your style definitions here...
    }
    Note: Please replace any non-alphanumerical character with a hpyhen (-) and do not use BEM for mixin names.

Import SCSS files

The reason why the whole content of SCSS files is wrapped into a mixin is because of the separation between import and inclusion. The Frontend Library is used to provide several features, but you might not need all of them in your project. That's why all resources are provided through the inclusion of the Frontend Library itself, but to explicitly use one of them, you have to include the appropriate mixin.

In order to import each SCSS file from your feature within the Frontend Library, add the imports of your files to the src/assets/scss/frontend-library.scss file:

@import '../../blocks/my-feature/my-feature';

Attention: In case you defined some dependencies in your SCSS files, it's useful to import the dependencies first. Otherwise, please import alphabetically.

Include your feature's SCSS in your project

Inside your project, you can now include the SCSS of your new feature:

@include frontend-library-my-feature();

List of all features

A complete list and documentation of features can be found here.

Add a new Handlebars Helper

New Handlebars helpers are also very welcome since they allow us to use custom JavaScript within our Handlebars Partials. If you'd like to add a new Handlebars helper, please think about the following:

  • Is it a useful and reusable Helper which is used in any feature?
  • Does any Panini Helper already solve the problem you want to solve with your own Helper?
  • Can Handlebars already solve the problem by it's own? Please take a look at it's documentation.

If you decide to add the new Helper, please follow these rules:

General

  • Directory of all Helpers: src/helpers
  • Create a new file for your new Helper, e.g. src/helpers/my-helper.js

File structure

Your Helpers JavaScript file should be structured this way:

  1. Documentation of your Helper, including the following elements:
    • Problem and solution
    • Description
    • Usage (Handlebars Syntax)
  2. Function declaration using Node's module export:
    module.exports = function() { ... }
    
  3. Function parameters, depending on what problem you want to solve:
Parameter Usage Example
Named parameters, e.g. function(width, height) Solve a solution depending on several defined settings {{my-helper 10 20}}
Non-named parameters, e.g. function(options) Provide multiple settings without explicitly defining them {{my-helper width=10 height=20 depth=30}}
Context parameter: function(..., context) Access content area provided within the Helpers call {{#my-helper}}I like that.{{else}}I really don't like it.{{/my-helper}}

You can certainly combine all variants.

Backwards compatibility

The library has several methods to handle backwards compatibility.

SCSS

In our SCSS files we use a version-dependent system for backwards compatibility. As the name points out, the system relies on the version of the package.

The current version is defined in the frontend-library.scss file:

$appVersion: "1.2.0";

The file _dev.scss provides a mixin to handle deprecated variables, mixins and functions:

@mixin deprecate($nameOfDeprecated, $nameOfCurrent, $versionOfDeprecation, $versionOfRemoval, $type: variable) {}

In case a variable/mixin/function is marked as deprecated, the mixin should be used to inform the developer about the deprecation. For this, add the following to the appropriate file where the deprecated variable/mixin/function is declared:

// For variables
@if global-variable-exists(old-variable-name) {
  $new-variable-name: $old-variable-name;
  @include deprecate(old-variable-name, new-variable-name, "1.2.0", "2.0.0");
}

// For variables without replacement (just set the second parameter to "null")
@if global-variable-exists(old-variable-name) {
  @include deprecate(old-variable-name, null, "1.2.0", "2.0.0");
}

// For mixins
@mixin old-mixin-name {
  @include new-mixin-name();
  @include deprecate(old-mixin-name, new-mixin-name, "2.0.0", "3.0.0", mixin);
}

// For mixins without replacement (just set the second parameter to "null")
@mixin old-mixin-name {
  @include deprecate(old-mixin-name, null, "2.0.0", "3.0.0", mixin);
}

Apparently, there is no useful method to use this in deprecated functions. So please make sure to handle useful backwards compatibility for functions and try to inform your users about the deprecation as well.

Handlebars

Within Handlebars, it's also possible to use backwards compatibility. Currently, this is only possible for variables and partials. The Handlebars Helper deprecate provides a deprecation system to handle deprecated variables and partials:

module.exports = (name, context) => {}

It can be used as follows:

{{deprecate "old-var" replacement="new-var" since="2.2.0" remove="3.0.0" type="var"}}
{{deprecate "old-partial" replacement="new-partial" since="2.2.0" remove="3.0.0" type="partial"}}

This would generate a warning in your console if the variable old-var is set and marked as deprecated. The same behaviour can be achieved for partials. For this, use the type partial as argument instead.

When raising deprecation notices for variables, it's also possible to set the value of the replacing variable with the value of the deprecated variable in the current context. For this, pass the parameter replace with value 1:

{{deprecate "old-var" replacement="new-var" since="2.2.0" remove="3.0.0" type="var" replace=1}}

Overview of accepted parameters:

Parameter Description Accepted values
<initial> Name of the deprecated resource <string>
replacement Name of the resource which replaces the deprecated one <string>
since Version of deprecation <float>
remove Version of removal <float>
type Resource type var, partial
replace Set new variable with value of deprecated variable <boolean>

Note: When using both default variables and backwards compatibility, make sure to keep the order of definition as follows:

  1. Default variables
  2. Backwards compatibility

Publish the package

When you made all necessary changes to the Frontend Library, you can publish the updated package to npm. For this, you need to update the version number and then push the updated package.

Please remember to log all notable changes to the Changelog.

Semantic Versioning

If you want to push the updated package to npm, you need to set a higher version number first. According to Semantic Versioning, there exist three types of version numbers:

  • Major version: 1.0.0 -> 2.0.0 (breaking changes)
  • Minor version: 1.0.0 -> 1.1.0 (new functionality with backwards compatibility)
  • Patch version: 1.0.0 -> 1.0.1 (bug fixes)

Please make sure to follow the rules of Semantic Versioning when updating the package.

Note: Your Git working directory needs to be clean in order to increase the version number.

Publish using bash script

You can use a bash script to publish your changes.

./sbin/publish.sh <update_type> [-m MESSAGE] [-p] [-f]

Replace <update_type> with one of the version number types described above (major, minor or patch).

Parameter Description
-m MESSAGE Release message (will be used as commit message as well)
-p Push Git version commit (otherwise, this needs to be done manually)
-f Force publishing the package to npm (this skips the prompt asking to publish the package)

Do it manually

Alternatively, the publish process can also be done manually.

Set version number

Depending on which type of Semantic Versioning you have chosen for the update, you may use one of the following statements (%s will be replaced with the new version number):

npm version major -m "New template structure added in %s"
npm version minor -m "New feature `my-feature` added in %s"
npm version patch -m "Fixed bug #12345 in %s"

When running npm version, a new Git commit containing the new version number as commit message will be added which updates the version number inside the package.json file. It also creates a new tag pointing to the version commit.

Update new version number for SCSS

Now we have to update the version number variable in SCSS with the new version number we have previously generated using npm version.

For this, update the variable $appVersion at the top of the src/assets/scss/frontend-library.scss file:

$appVersion: "1.1.0";

After updating the version number for SCSS, you have to commit this change and amend it to the previously generated commit:

git commit --all --amend
git tag -f $(git tag | tail -n1)

Now push the version commit and tag:

git push --follow-tags

If the above command does not push both your commits and tags, you need to push them separately:

git push && git push --tags

Publish

Once you have changed the version number, you can publish the new version to the npm registry.

npm publish

Changelog

For detailed changes across each version take a look at the Changelog.

Readme

Keywords

none

Package Sidebar

Install

npm i @undkonsorten/frontend-library

Weekly Downloads

3

Version

3.2.0

License

MIT

Unpacked Size

238 kB

Total Files

156

Last publish

Collaborators

  • undkonsorten