Create a Library

A guide to creating a Frontal Library

In this guide we will walk through how to create a fully featured Frontal Library that extends Bootstrap and jQuery, below is our final library structure:

├── components
│   ├── buttons
│   │   ├── buttons.config.js
│   ├── modals
│   │   ├── modals.config.js
├── assets
│   ├── style
│   │   ├── variables.scss
└── library.config.js

Scripts

The first thing we need is to import jquery and bootstrap javascript assets within our library, for that we will be using the lib.js.import() method from within our library's setup function.

// library/library.config.js
module.exports = (opts, lib) => {
    // import jquery and make it globally available with '$' and 'jQuery'
    lib.js.import({path: 'jquery', provideAs: ['$', 'jQuery']});

    // import bootstrap core javascript
    lib.js.import('bootstrap/js/src');
}
The same syntax used when configuring assets within frontal.config.js can used with lib.js.import(), hence the way jquery is imported with the provideAs feature.

Now once the Library is used by any Frontal application, Frontal is instructed to load jquery and bootstrap and make them globally available.

Styles

The same concept of importing javascript can be used with styles, if we follow the instructions given by bootstrap when extending themes, we will notice that there are variables and mixins files that should be loaded before loading bootstrap style files, for that we can use the lib.style.global() method:

// library/library.config.js
module.exports = (opts, lib) => {
    // ...

    // Apply bootstrap globals
    lib.style.global(
        '@library/assets/style/variables.scss',
        'bootstrap/scss/functions',
        'bootstrap/scss/variables',
        'bootstrap/scss/mixins',
    )
}
Note: Style files that are loaded as globals should never include any styling that applies to a page (no side effects), global files should only include things like Variables, Mixins and so on.
The @library/assets/style/variables.scss file will include all the variables that will override default bootstrap variables.

After applying global style files that applies to all other style files, we can now start importing the actual bootstrap style files using the lib.style.import() method:

// library/library.config.js
module.exports = (opts, lib) => {
    // ...

    // Apply bootstrap style files
    lib.style.import(
        'bootstrap/scss/_reboot.scss',
        'bootstrap/scss/_type.scss',
        'bootstrap/scss/_images.scss',
        'bootstrap/scss/_code.scss',
        'bootstrap/scss/_grid.scss',
        'bootstrap/scss/_utilities.scss',
        '@library/assets/style/main.scss'
    )
}
The reason we import bootstrap's sass files like that bootstrap/scss/_reboot.scss instead of just bootstrap/scss/reboot as we normally would in a sass file, is because, frontal loads these assets from javascript files and therefore the entire path and the extension should be applied.

Since bootstrap's variables are imported via the global method, they are available to each file we import using the import method, therefore the @library/assets/style/main.scss can have the following contents:

// @library/assets/style/main.scss
body {
  color: $white; // the $white variable is available with no imports due to the global imports
}

Now feel free to import as many files you would like in order to enable all components within bootstrap.

Components

Frontal accepts registering components in two ways:

  • the lib.components.add() method, which takes in an object as argument, that object should define the name and setup properties.
  • the lib.components.register() method, which takes in an absolute path to a component's config file that exports a component's object definition.

Since too many components can exist within a library, Frontal provides a convenient method to register all components automatically using the lib.components.autoRegister() method:

// library/library.config.js
module.exports = (opts, lib) => {
    ...

    // Register all components with the given config path filter
    lib.components.autoRegister(
        lib.path('components/**/*.config.js')
    );
}
The lib.path() method takes in a path and returns an absolute path within the library directory.

Setting up the Modal component

We will create the component's config file at components/modals/modals.config.js with the following contents:

// library/components/modals/modals.config.js
module.exports = () => ({
    // the name of the component
    name: 'modals',

    // the setup method of the component
    setup(lib, opts) {
        // import the modal.js from within the bootstrap package
        lib.js.import('bootstrap/js/src/modal');

        // import the style file for modal
        lib.style.import('bootstrap/scss/_modal.scss');
    }
})

As seen in the previous config file, we export a function that returns an object, that object is the component's definition object, couple of things to note:

  • the name property should include the component's name.
  • the setup property is a function that accepts two arguments, the lib which provides the same API used within the library.config.js and the opts variable which is an options object that can be passed when using the component.

Now the import rules defined within the setup method will be applied by Frontal in the bundles that actually uses that component by name, for example, one could use the modals component from within their frontal.config.js as follows:

// frontal.config.js
module.exports = {
  bundles: {
    main: {
      pages: ['**/*.html'],
      components: {
        modals: true,
        // an options object can be passed instead of a boolean
        // modals: {opt1: 'val1'}
      }
    }
  }
}

Setting up the Button component

// library/components/buttons/buttons.config.js
module.exports = () => ({
  name: 'buttons',
  setup(lib, opts) {
    lib.style.import(
      'bootstrap/scss/_buttons.scss',
      'bootstrap/scss/_button-group.scss'
    );
  }
})
This library example is available on Github.

Final Thoughts

This guide was showing the basic concept of what a Frontal Library can do, a library can be a lot more complex depending on your work, for example, each component can provide a WebComponent, giving the Library user the ability to even use dynamic components within their HTML pages.

Since Frontal was made with HTML in mind, features such as tree-shaking was not applicable due to the nature of HTML projects, that's why components makes it a lot easier, for users to selectively choose which components should be used in which pages.

Would You Like To KnowAbout Our Next Products & Free Tools?