Webpack + Customizable Semantic UI 2.x (LESS)

Published on Author Artem Butusov20 Comments

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:

  • src/index.jsx
  • package.json
  • node_modules

Assumptions

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

  • src/semantic/theme.config – theme configuration, we could define what is the default theme for each component.
  • src/semantic/semantic.less – main less include file, we could define here what css components we want to enable.
  • src/semantic/semantic.js – main js include file, we could define here what js components we want to enable.
  • src/semantic/site – site theme, structure should match with http://learnsemantic.com/developing/customizing.html

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';

20 Responses to Webpack + Customizable Semantic UI 2.x (LESS)

  1. You shuold also provide @themesFolder value. Otherwise you will get a error
    “Module build failed: variable @themesFolder is undefined”

  2. Thanks for your howto!
    I struggled some (more) time with this issues.

    My (more easy?) solution which seems to work:
    1.) have a theme.config anywhere in your src
    2.) “postinstall”: “ln -s ../../src/semantic-ui-theme.config node_modules/semantic-ui-less/theme.config”
    3.) Have the font-var-overwrite in your theme.config: @fontPath : ‘../../../themes/@{site}/assets/fonts’;

  3. Hey at the install step, should the command be:

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

    It looks like you leave out the “install”. Great guide in any case.

  4. Hi Artem,

    After doing all the steps described in your article I’m getting next error:

    ERROR in ./~/semantic-ui-less/themes/default/assets/images/flags.png
    Module parse failed: /Users/eugene-vilder/Projects/control-app/node_modules/semantic-ui-less/themes/default/assets/images/flags.png Line 1: Unexpected token ILLEGAL
    You may need an appropriate loader to handle this file type.
    (Source code omitted for this binary file)
    @ ./~/css-loader!./~/less-loader!./src/app/app.less 2:219903-219988

    Any Idea why ?

    Thank you.

  5. I rarely comments on blog posts but this article has been hugely helpful. I have even managed to make it work with Laravel Mix. Thank you ever so much! 🙂

    • Would you mind sharing how you got it to work with Laravel Mix? It would be quite helpful if you could. Thanks.

  6. ERROR in ./~/semantic-ui-react/src/elements/Button/index.js
    Module parse failed: /Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/semantic-ui-react/src/elements/Button/index.js Unexpected token (1:20)
    You may need an appropriate loader to handle this file type.
    SyntaxError: Unexpected token (1:20)
    at Parser.pp$4.raise (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:2221:15)
    at Parser.pp.unexpected (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:603:10)
    at Parser.pp.semicolon (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:581:61)
    at Parser.pp$1.parseExport (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:1176:27)
    at Parser.pp$1.parseStatement (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:719:71)
    at Parser.pp$1.parseTopLevel (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:638:25)
    at Parser.parse (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:516:17)
    at Object.parse (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/acorn/dist/acorn.js:3098:39)
    at Parser.parse (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/webpack/lib/Parser.js:902:15)
    at NormalModule. (/Users/rob/projects/stoke-brain/app.stokebrain.com/node_modules/webpack/lib/NormalModule.js:104:16)
    @ ./src/components/component.curve.editor.list.js 16:14-62
    webpack: Failed to compile.

  7. I’m trying to use this with overrides like site/globals/site.variables, but they aren’t working for me with this setup. What changes do I need?

  8. Hello! Thank you for writing this. I am new, and have been trying to set up semantic-ui theming with Webpack 3 for a few days. There are handful information about this I could find on line, and this one looks like is the working one.
    I think I am almost there. I can see semantic-ui definition in the webpack main css after build, however l only see comments being included, like:

    /
    /*******************************
    Theme Selection
    *******************************/
    /
    To override a theme for an individual element
    specify theme name below
    /
    /
    Global /
    /
    Elements /
    /
    Collections /
    /
    Modules /
    /
    Views */

    Any idea what I am missing?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.