Webpack 2 issues with Semantic UI

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

Answers:

Answer

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.

Answer

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

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;

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.