Webpack + Customizable Semantic UI 2.x (LESS)

Author Artem Butusov · Published on September 11th, 2016

The goal: Get configurable Semantic UI without requirement to copy/paste all Semantic UI source code, ideally a way to enable/disable any components and override theme styles.

Let’s say we have application folder structure:

Assumptions

Let’s assume that we would like to put all Semantic UI related overrides somewhere in project source folder, for example, src/semantic.

Fix Semantic UI

Unfortunately, but Semantic UI is not designed to be easily included via webpack.

We need to apply some fixes on Semantic UI less sources to make it work.

We can do that in automatic way after each npm install.

./semantic-fix.js:

var fs = require('fs');

// relocate default config
fs.writeFileSync(
  'node_modules/semantic-ui-less/theme.config',
  "@import '../../src/semantic/theme.config';\n",
  'utf8'
);

// fix well known bug with default distribution
fixFontPath('node_modules/semantic-ui-less/themes/default/globals/site.variables');
fixFontPath('node_modules/semantic-ui-less/themes/flat/globals/site.variables');
fixFontPath('node_modules/semantic-ui-less/themes/material/globals/site.variables');

function fixFontPath(filename) {
  var content = fs.readFileSync(filename, 'utf8');
  var newContent = content.replace(
    "@fontPath  : '../../themes/",
    "@fontPath  : '../../../themes/"
  );
  fs.writeFileSync(filename, newContent, 'utf8');
}

package.json:

  ...
  "scripts": {
    ...
    "postinstall": "node semantic-fix.js",
    ...
  }
  ...

Install

npm install --save semantic-ui-less && node semantic-fix.js

semantic-ui package has more features, but it runs gulp install automatically so it is not suitable (for me at least).

Copy semantic.less

Copy node_modules/semantic-ui-less/semantic.less into src/semantic/semantic.less.

Fix all imports to begin with @import ~semantic-ui-less/.

Create semantic.js

Create src/semantic/semantic.js:

import 'semantic-ui-less/definitions/globals/site';

import 'semantic-ui-less/definitions/behaviors/api';
import 'semantic-ui-less/definitions/behaviors/colorize';
import 'semantic-ui-less/definitions/behaviors/form';
import 'semantic-ui-less/definitions/behaviors/state';
import 'semantic-ui-less/definitions/behaviors/visibility';
import 'semantic-ui-less/definitions/behaviors/visit';

import 'semantic-ui-less/definitions/modules/accordion';
import 'semantic-ui-less/definitions/modules/checkbox';
import 'semantic-ui-less/definitions/modules/dimmer';
import 'semantic-ui-less/definitions/modules/dropdown';
import 'semantic-ui-less/definitions/modules/embed';
import 'semantic-ui-less/definitions/modules/modal';
import 'semantic-ui-less/definitions/modules/nag';
import 'semantic-ui-less/definitions/modules/popup';
import 'semantic-ui-less/definitions/modules/progress';
import 'semantic-ui-less/definitions/modules/rating';
import 'semantic-ui-less/definitions/modules/search';
import 'semantic-ui-less/definitions/modules/shape';
import 'semantic-ui-less/definitions/modules/sidebar';
import 'semantic-ui-less/definitions/modules/sticky';
import 'semantic-ui-less/definitions/modules/tab';
import 'semantic-ui-less/definitions/modules/transition';
// import 'semantic-ui-less/definitions/modules/video';

Copy theme.config

Copy node_modules/semantic-ui-less/theme.config.example into src/semantic/theme.config.

Set variable @siteFolder : '../../src/semantic/site';.

Fix theme import like @import "~semantic-ui-less/theme.less";.

Test

You could create test override to check if configuration works well. Create src/semantic/site/elements/button.variables and override @backgroundColor to any color.

And something like that could help you to test:

<button className="ui button">Button with custom background</button>

Autoprefixer

Semantic UI comes with autoprefixer configuration. It is included in semantic-ui but not in semantic-ui-less. It could be loaded in webpack with:

var LessPluginAutoPrefix = require('less-plugin-autoprefix');

// that could be possible if semantic-ui will not run intstall
// var autoprefixerBrowsers = require('semantic-ui/tasks/config/tasks').settings.prefix.browsers;

// workaround until (hardcoded value from file behind)
var autoprefixerBrowsers = ['last 2 versions', '> 1%', 'opera 12.1', 'bb 10', 'android 4'];

module.exports = {
  module: {
    loaders: [
      { test: /\.less$/, loader: ... }
    ]
  },
  lessLoader: {
    lessPlugins: [
      new LessPluginAutoPrefix({ browsers: autoprefixerBrowsers })
    ]
  }
};

Import

Put code below somewhere in main entry point to import css and javascript part of Semantic UI.

import './semantic/semantic';
import './semantic/semantic.less';