Skip to content

Component Pattern

Old version

The first version of patternlab components was straight-forward because the component consisted of a single js file returning an object that most of the time has only one init function.

Chart.js

js
// ...

    /*
     * Initialize the module with custom settings
     *
     * @method
     * @public
     * @param {Settings} settings - The settings that will overwrite the default settings
     */
    exports.init = (settings) => {
        config = $.extend(true, {}, defaults, settings);

        if ($(config.selector.chart).length) {
            $(config.selector.chart).easyPieChart(config.options);
        } else {
            return;
        }
    };

    /**
     * Public access to the module
     *
     * Any access point to this module to interact with other modules.
     */
    return exports;
})($);
export {Chart};

New version

But now we built on top of that and the core functionality is still in used but with a few changes.

The core functionality that returns an object with appropriate properties (e.g. init function) is outsourced in a factory function.

js
const factory = (_$) => {
  if (typeof _$ === 'undefined') {
    throw new Error('Chart requires jQuery')
  }
  // ...

Then the factory exports our component object like the old version (it is the old code only outsourced in factory).

js
// ...
const exports = {}

/*
* Initialize the module with custom settings
*
* @method
* @public
* @param {Settings} settings - The settings that will overwrite the default settings
*/
exports.init = (settings = {}) => {
  config = _$.extend(true, {}, defaults, settings)

  if (_$(config.selector.chart).length) {
    _$(config.selector.chart).easyPieChart(config.options)
  }
}
// ...

API of Components

js
// ...
export { Chart, factory }

Although we export that factory function the end-users (target projects' developers) must still import the old Chart Object from Chart.js file! So the changes don't affect the target projects that already have patternlab components imported except the path of files (we will discuss it later).

Wrapper of factory

Chart Object is a wrapper of factory and its puprose is to remain the old API / using convention of patternlab components.

js
const Chart = {
  init (settings = {}, _$) { // a wrapper for old code, nothing changed for outside use of old Chart
    if (typeof $ === 'undefined' && typeof _$ === 'undefined') throw new Error('Chart requires jQuery')
    const preprocessed = factory(_$ || $) // $
    preprocessed.init(settings)
    return preprocessed
  },
}

Async Components

Almost every patternlab component like Chart.js has an alternative version named AsyncChart.js.

TIP

The convention of async files is the Async as prefix and the component's filename e.g. (Async)Chart.js

Purpose of adding asynchronous

INFO

The main reason of adding asynchronous functionality is to resolve components' dependencies.

Assuming you wanted to use the select2 component then u had to install and import the select2 project before importing the patternlab's select2 component Or the target project had to install JQuery.

We outsourced the core functionality into factory so that we are able to use this factory function in Async version of components as well.

js
/**
 * Chart
 *
 * @author Laura Redeker <redeker@pharma4u.de>
 * @module Chart
 * TODO: zur zeit hard gecodete hex-codes (und nur pharma4u rot)
 */

// #region import-factory
// ...
import { factory } from './Chart'
// ...
// #endregion import-factory
import { asyncResolveEasyPieChart } from 'utility/DependencyResolves' // asyncResolveJQuery,

export async function AsyncChart () {
  const { _jQuery } = await asyncResolveEasyPieChart({ errMsg: 'Chart requires JQuery' })

  // #region async-consists
  return {
    Chart: factory(_jQuery),
    _$:    _jQuery,
  }
}

INFO

In our example Chart component depends on easy-pie-chart so we have to resolve that first. The advantage of this is that the user of Chart doesn't need to solve the dependency issues by himself and furthermore to know the underneath dependencies.

Important

Every AsyncComponent exports an object named as the async file name.
That means AsyncChart.js exports AsyncChart object.

js
/**
 * Chart
 *
 * @author Laura Redeker <redeker@pharma4u.de>
 * @module Chart
 * TODO: zur zeit hard gecodete hex-codes (und nur pharma4u rot)
 */

// #region import-factory
// ...
import { factory } from './Chart'
// ...
// #endregion import-factory
import { asyncResolveEasyPieChart } from 'utility/DependencyResolves' // asyncResolveJQuery,

export async function AsyncChart () {
  const { _jQuery } = await asyncResolveEasyPieChart({ errMsg: 'Chart requires JQuery' })

  // #region async-consists
  return {
    Chart: factory(_jQuery),
    _$:    _jQuery,
  }
}

In our example AsyncChart object consists of the Chart object and an instance of JQuery.

js
/**
 * Chart
 *
 * @author Laura Redeker <redeker@pharma4u.de>
 * @module Chart
 * TODO: zur zeit hard gecodete hex-codes (und nur pharma4u rot)
 */

// #region import-factory
// ...
import { factory } from './Chart'
// ...
// #endregion import-factory
import { asyncResolveEasyPieChart } from 'utility/DependencyResolves' // asyncResolveJQuery,

export async function AsyncChart () {
  const { _jQuery } = await asyncResolveEasyPieChart({ errMsg: 'Chart requires JQuery' })

  // #region async-consists
  return {
    Chart: factory(_jQuery),
    _$:    _jQuery,
  }
}

Usage

Prerequirement

In order to use any component Patternlab needs to be installed or linked via npm first.

Install

sh
npm i -D @pharma4u/patternlab

or link

In root directory of patternlab /patternlab-vite execute the following command:

sh
npm link

Now switch to target project (root directory of project) and link the patternlab as follow:

sh
npm link patternlab-vite

Install Patternlab's dependencies (global)

There are some scenarios and use cases that lead to several ways of the dependencies' registration and usage

js
// ...
import { asyncResolveDependencies } from 'patternlab-vite'

asyncResolveDependencies()
// ...
js
// ...
import { asyncResolveDependencies } from 'patternlab-vite'

asyncResolveDependencies((registry) => {
    registry.asyncResolveEasyPieChart()
    // ...
})
// ...
js
// ...
import { asyncResolveEasyPieChart } from 'patternlab-vite'

asyncResolveEasyPieChart()
// ...

Normal version

js
// ...
import {
  Chart,
  asyncResolveEasyPieChart
} from 'patternlab-vite'

// if easy-pie-chart isn't installed already
asyncResolveEasyPieChart().then(({ _jQuery }) => {
  const settings = {}
  Chart.init(settings, _jQuery)
})
// ...
js
// ...
import {
  Chart,
  asyncResolveDependencies
} from 'patternlab-vite'

// if (all) dependencies aren't installed already
asyncResolveDependencies().then(() => {
  const settings = {}
  Chart.init(settings)
})
// ...

Async version

The most simplest

In the normal version we still have to call/register the components dependencies asynchronously.
But this burden doesn't exist in using of asynchronous version.

js
// ...
import { AsyncChart } from 'patternlab-vite'

AsyncChart().then(({ Chart }) => {
  const settings = {}
  Chart.init(settings)
})
// ...

INFO

That's all about async version of components.