Search code examples
javascriptwebpacklesssemantic-uiwebpack-2

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

Solution

  • 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.