4
votes

Been struggling to get semantic-ui setup using Webpack 2. I a few errors relating to the fonts in the default semantic-ui theme and another error regarding image-webpack-loader:

ERROR in ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less
Module not found: Error: Can't resolve './themes/themes/default/assets/fonts/icons.eot' in '/Users/djthomps/Desktop/demo/semantic/src'
 @ ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less 6:285117-285174 6:285197-285254
 @ ./semantic/src/semantic.less
 @ ./app/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/index.js

# same for icons.woff2

# same for icons.woff

# same for icons.ttf

# same for icons.svg

ERROR in ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less
Module not found: Error: Can't resolve 'image-webpack' in '/Users/djthomps/Desktop/demo'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.
                 You need to specify 'image-webpack-loader' instead of 'image-webpack'.
 @ ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less 6:218646-218697
 @ ./semantic/src/semantic.less
 @ ./app/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/index.js

The ultimate goal is to use react semantic-ui components with a custom theme that I can simply import into my .jsx files as seen in this example.

I've been following this guide to get semantic-ui setup with Webpack 1 using Webpack 2, fixing the less-loader differences along the way. Nevertheless, I can't seem to fix these issues after scouring other projects like font-awesome-webpack2 and sifting through github comments. Here's the a very small, verifiable example:

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const RewriteImportPlugin = require('less-plugin-rewrite-import');

const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
    template: './app/index.html',
    filename: 'index.html',
    inject: 'body' // inject scripts before closing body tag
});

module.exports = {
    entry: './app/index.js', // where the bundler starts the bundling process
    output: { // where the bundled code is saved
        path: path.resolve('dist'),
        filename: 'index_bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.(png|jpg|gif|woff|svg|eot|ttf|woff2)$/,
                loader: 'url-loader?limit=1024&name=[name]-[hash:8].[ext]!image-webpack'
            },
            {
                test: /\.less$/, // import css from 'foo.less';
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            // importLoaders: 1,
                            lessPlugins: [
                                new RewriteImportPlugin({
                                    paths: {
                                        '../../theme.config':  __dirname + '/theme.config',
                                    },
                                })
                            ]
                        }
                    },
                    'less-loader'
                ]
            },
            {
                test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'file-loader'
            }
        ]
    },
    devtool: 'eval-source-map',
    devServer: { compress: true },
    plugins: [ HtmlWebpackPluginConfig ]
};

package.json

{
    "name": "demo",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "scripts": {
        "start": "webpack-dev-server"
    },
    "devDependencies": {
        "css-loader": "^0.26.1",
        "html-webpack-plugin": "^2.28.0",
        "image-webpack-loader": "^3.2.0",
        "less-loader": "^2.2.3",
        "less-plugin-rewrite-import": "^0.1.1",
        "semantic-ui": "^2.2.7",
        "style-loader": "^0.13.1",
        "url-loader": "^0.5.7",
        "webpack": "^2.2.1",
        "webpack-dev-server": "^2.3.0"
    }
}

app/index.js

import css from '../semantic/src/semantic.less';

app/index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Demo</title>
</head>
<body>
    <button class="ui button">Follow</button>
</body>
</html>

theme.config

 // truncated for brevity
 @button     : 'gmail';

My project structure is as follows:

.
├── app
│   ├── index.html
│   └── index.js
├── package.json
├── semantic
│   ├── gulpfile.js
│   ├── src
│   └── tasks
├── semantic.json
├── theme.config
└── webpack.config.js

Update 1

I've been contemplating possible solutions:

  1. postinstall script that moves my theme.config into the semantic folder and then build semantic kind of like this tutorial
  2. postinstall script to replace all of the theme.config imports with my version (what the RewriteImportPlugin ought to be handling)
  3. Setup a separate gulp task to handle the moving of files and building of semantic-ui
  4. Use webpack 2 end-to-end (preferred)

Update 2

ERROR in ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less
Module not found: Error: Can't resolve 'image-webpack' in '/Users/djthomps/Desktop/demo'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.
                 You need to specify 'image-webpack-loader' instead of 'image-webpack'.
 @ ./~/css-loader?{"lessPlugins":[{"options":{"paths":{"../../theme.config":"/Users/djthomps/Desktop/demo/theme.config"}}}]}!./~/less-loader!./semantic/src/semantic.less 6:218646-218697
 @ ./semantic/src/semantic.less
 @ ./app/index.js
 @ multi (webpack)-dev-server/client?http://localhost:8080 ./app/index.js

is fixed by adjusting the config file:

 loader: 'url-loader?limit=1024&name=[name]-[hash:8].[ext]!image-webpack-loader' // note the loader at the end
3
If you want to use semantic with React, they are working on a nice component library: react.semantic-ui.com/introduction. You still have to include the css manually. With any custom css/sass... Good luck, I wasted a lot of time getting it working.Balázs Édes
@BalázsÉdes I'm aware of the component library. The idea is I want to be able to inject my own theme and import .less files directly into the component.djthoms
So I can tell you I spent a ridiculously long time on this too (for use with VueJS) and finally I just built semantic ui using their gulp task and included the generated CSS and JS files from semantics dist. It actually works pretty well, gulp watch picks up changes to the theme and rebuilds and then webpack hot reloads,Justin
@Justin I started down this path actually... Good to know others are struggling with the same thing and thinking the same thing.djthoms
@Justin can you shed some details on just how you got this to work using Webpack 2? I'm still getting the same errors when I use regular old cssdjthoms

3 Answers

5
votes

After beating my head for three days, I finally was able to figure it out for the most part.

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './app/index.js', // where the bundler starts the bundling process
    output: { // where the bundled code is saved
        path: path.resolve('dist'),
        filename: 'index_bundle.js'
    },
    resolve: {
        alias: {
            semantic: path.resolve(__dirname, 'semantic/src/'),
            jquery: path.resolve(__dirname, 'node_modules/jquery/src/jquery')
        }
    },
    module: {
        loaders: [
            {
                test: /\.(png|gif)$/,
                loader: 'url-loader?limit=1024&name=[name]-[hash:8].[ext]!image-webpack-loader'
            },
            {
                test: /\.jpg$/,
                loader: 'file-loader'
            },
            {
                test: /\.less$/, // import css from 'foo.less';
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.(ttf|eot|svg|woff2?)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'file-loader'
            }
        ]
    },
    devtool: 'eval-source-map',
    devServer: { compress: true },
    plugins: [
        new HtmlWebpackPlugin({
            template: './app/index.html',
            filename: 'index.html',
            inject: 'body' // inject scripts before closing body tag
        }),
        new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
        'window.jQuery': 'jquery'
    })
    ]
};

but the catch is, if you want to use the bundled fonts you need to fix the paths because they're resolved incorrectly after we execute the less-loader loader (where the bug is remains a mystery). I've created a handy template as a very minimal example with some additional details.

3
votes

Hopefully this will point you in the right direction even though its not a complete solution. As I mentioned I spent a ridiculous amount of time trying to get Semantic-UI working with Webpack 2. I'm using the Webpack template from vue-cli for a VueJS project. I tried stripping the Vue configuration out of the template to get an example that was framework agnostic but that didn't go well.

It looks like you might just be trying to get Semantic-UI CSS setup, and not their JS components. All the additions I made to the Vue Webpack template are related to JS, basically just to include jQuery for Semantic-UI. So if you're only interested in getting the CSS working these additions aren't necessary.

In order to get the template's configuration to work with Semantic-UI JS, I added this to module-exports

alias: {
  ...
  jquery: "jquery/src/jquery",
},
...
plugins: [
  new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery",
    "window.jQuery": "jquery"
  })
]  

I run Semantic's Gulp task to build to its own dist folder, and then I can simply include those files in my main.js entry for webpack.

import '../semantic/dist/semantic.css'
import '../semantic/dist/semantic'
1
votes

This should be the most elegant way of making semantic ui theming work for webpack2.

Thanks for the idea from this issue, I have updated my tutorial React+Webpack1/2/3+Semantic UI and how to do theming and the demo project

Please follow the tutorial or scroll to the bottom to see the main changes you need to make. These two key differences from Webpack1 is:

  • By default, less-loader will use webpack’s resolver to resolve all the less files, making plugins like less-plugin-rewrite-import fail to handle less files. That’s why you will find the plugin not working for webpack2. To make less-loader use its own resolver, you need to manually specify option paths for it to search (take a look at the webpack config pasted below)
  • Since now we are using less resolver, we are not able to use ~ to refer modules in the node_modules anymore, so open your theme.config and change the @import "~semantic-ui-less/theme.less"; to @import "semantic-ui-less/theme.less";

    const path = require('path');
    const webpack = require('webpack');
    const RewriteImportPlugin = require("less-plugin-rewrite-import");
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const ROOT_DIR = path.resolve(__dirname);
    const SRC_DIR = path.resolve(__dirname, 'app');
    const BUILD_DIR = path.resolve(__dirname, 'build');
    const NODE_MODULES_DIR = path.resolve(__dirname, 'node_modules');

    var webpackConfig = {
      devtool: 'eval',
      entry: {
        index: path.resolve(SRC_DIR, 'index.js'),
      },
      output: {
        path: BUILD_DIR,
        filename: '[name].[hash:8].js',
      },
      resolve: {
        modules: [ROOT_DIR, 'node_modules'],
      },
      module: {
        rules: [
          {
            test: /\.(less|config)/,
            use: [
              'style-loader',
              'css-loader',
              {
                loader: 'less-loader',
                options: {
                  paths: [ROOT_DIR, NODE_MODULES_DIR],
                  plugins: [
                    new RewriteImportPlugin({
                      paths: {
                        '../../theme.config':  __dirname + '/app/semantic-ui/theme.config',
                      },
                    }),
                  ],
                },
              },
            ],
          },
          {
            test: /\.(png|jpg|gif|woff|svg|eot|ttf|woff2)$/,
            use: [
              { loader: 'file-loader' },
            ],
          },
          {
            test: /\.html$/,
            loader: 'html-loader',
          },
          {
            test: /\.jsx?$/,
            exclude: /(node_modules|bower_components)/,
            loader: 'babel-loader',
            query: {presets: ['es2015']}
          },
        ],
      },

      plugins: [
        new HtmlWebpackPlugin({
          inject: 'body',
          template: 'app/index.html',
          filename: 'index.html',
          chunks: ['index'],
          chunksSortMode: 'dependency',
          env: process.env,
        }),
      ],
    };

module.exports = webpackConfig;