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
Contents
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';
You shuold also provide @themesFolder value. Otherwise you will get a error
“Module build failed: variable @themesFolder is undefined”
Variable
@themesFolder
insrc/semantic/theme.config
is relative tonode_modules/semantic-ui-less
so it is correct path.Sorry, I made a mistake when configuring build. Everything is ok in the article.
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’;
Thanks for feedback. I need to test. It looks like less lazy variable evaluation could definitely simplify this manual.
Very useful. It would be great if you create an NPM package based on this article.
It is actually on github: https://github.com/sormy/skeleton-react-ts
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.
thanks, fixed
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.
Not sure, could you please post somewhere your package.json ?
Hi, Eugene,
I believe this is because you need to declare loaders for all file extensions, including images, in your
webpack.config.js
(otherwise it won’t know how to bundle these files). Take a look at this example (look forurl-loader
): https://github.com/vuejs-templates/webpack/blob/master/template/build/webpack.base.conf.jsI hope this helped!
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.
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.
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?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?
Hold on. Let me take this back. Actually all css definition are there (in webpack main js file) But the problem is that all semantic class name are hashed. So it related to this post:
https://github.com/Semantic-Org/Semantic-UI-React/issues/802#issuecomment-258990274
Need to prevent CSS modules from running on semantic-ui/semantic-ui.less. But how?
I figured this out. It’s ‘modules’ option in css-loader. Check this in your webpack configuration file. Either set “modules” to “false”, or just commented it out.
In case you use https://github.com/bertho-zero/react-redux-universal-hot-example, I forked the repository to implement it with semantic-ui instead of bootstrap. The repo is here: https://github.com/dongcai/react-redux-semantic-ui
[…] Artem Butusov has posted a very effective fix for Semantic UI which helps us integrate Semantic UI (LESS) with Webpack. This helps us customize which modules we require from the framework separately and we can comment the remaining ones. […]