Semantic-ui-react: How to work with custom semantic-ui-less theme, css-modules and semantic-ui-react simultaneously using craco

Created on 21 Nov 2019  路  5Comments  路  Source: Semantic-Org/Semantic-UI-React

Hello 馃憢,

Originaly my question was posted to #3761. But the conversations was too complicated to not having its own issue I thought.

@scorsi said at 20 novembre 15:47 UTC+1:

Hello @layershifter,

I had an old code base using old semantic-ui-react setup with webpack which now have a lot of vulnerabilities. I so changed everything to use CRA + CRACO + @semantic-ui-react/craco-less (without ejecting configurations).
I was looking for the repository of @semantic-ui-react/craco-less for posting the issue without success. Hope, this is the right place.

I need to use the CSS Modules (to avoid too much codebase changes), I so do in the craco.config.js file :

module.exports = {
  plugins: [{
    plugin: require('@semantic-ui-react/craco-less'),
    options: {
      cssLoaderOptions: {
        modules: true,
        localIdentName: '[local]_[hash:base64:5]',
      },
    },
  }],
};

But still got a weird issue.
If I use import * as styles from ... or import styles from ..., I got undefined values.
If I rename my style files to my-file-name.module.less (as hinted here : https://create-react-app.dev/docs/adding-a-css-modules-stylesheet), I got an error where the webpack loader seems to not recognized the file type : Module parse failed: Unexpected token (1:0). You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

Do you have any clue ?

@layershifter said at 20 novembre 16:03 UTC+1:

You can temporary use craco-less for CSS modules: https://www.npmjs.com/package/craco-less#css-modules

It should work, can you please check?

@scorsi said at 20 novembre 16:05 UTC+1:

I already tried that but got a weird issue with semantic-ui-less files.

@import (multiple) '../../theme.config';
^
Can't resolve '../../theme.config' in '/somewhere/node_modules/semantic-ui-less/definitions/modules'
      in /somewhere/node_modules/semantic-ui-less/definitions/modules/transition.less (line 19, column 0)

Which is fixed by @semantic-ui-react/craco-less, right ?

@rickysullivan said at 20 novembre 20:18 UTC+1:

@layershifter Why not just allow pluginOptions to be passed down? See my gist.

I so did my own loader following the @rickysullivan gist. I pass pluginOptions through CracoLessPlugin and it works greatly. It is a really good idea which should be applied to official @semantic-ui-react/craco-less.

I achieved to have my own styles importing as css-module but the all the semantic-ui-less files are also css-module imported and so aren't applied to whole semantic-ui-react components.

I didn't name my files following the official React tips (https://create-react-app.dev/docs/adding-a-css-modules-stylesheet) cause I still got the same error : Module parse failed.

Do you have any clue how I can import my own styles as css-modules but semantic-ui-less files with standard loader (without css-modules enabled) ?

Thanks ! 馃槉

Most helpful comment

Ok, good news !

I finally succeed to use css-modules + semantic-ui. I renamed my styling files to *.module.less and set two less loader to the craco configuration file.
I modified the @semantic-ui-react/craco-less loader to allow passing pluginOptions through CracoLessPlugin.

craco.config.js :

const {
  getLoader,
  loaderByName,
  removeLoaders,
  throwUnexpectedConfigError,
} = require('@craco/craco');

const CracoLessPlugin = require('craco-less');

const path = require('path');

// Overriding CracoLessPlugin as @semantic-ui-react/craco-less to correctly load semantic-ui less files
const SemanticUiCracoLessPlugin = {
  overrideWebpackConfig: ({
    context,
    webpackConfig,
    pluginOptions,
  }) => {
    // add alias to theme.config
    webpackConfig.resolve.alias['../../theme.config$'] = path.join(context.paths.appSrc, '/semantic-ui/theme.config');

    // file-loader:
    // theme.config, *.variables and *.overrides files should be excluded
    const {
      isFound,
      match: fileLoaderMatch,
    } = getLoader(webpackConfig, loaderByName('file-loader'));

    if (!isFound) {
      throwUnexpectedConfigError({
        packageName: '@semantic-ui-react/craco-less',
        message: `Can't find "file-loader" in the ${context.env} webpack config!`,
      });
    }

    fileLoaderMatch.loader.exclude.push(/theme\.config$/);
    fileLoaderMatch.loader.exclude.push(/\.variables$/);
    fileLoaderMatch.loader.exclude.push(/\.overrides$/);

    // resolve-url-loader:
    // should be removed as it causes bugs
    // https://github.com/Semantic-Org/Semantic-UI-React/issues/3761
    removeLoaders(webpackConfig, loaderByName('resolve-url-loader'));

    // less-loader:
    // craco-less is reused
    return CracoLessPlugin.overrideWebpackConfig({
      context,
      webpackConfig,
      pluginOptions,
    });
  },
};

module.exports = {
  plugins: [
    {
      plugin: SemanticUiCracoLessPlugin,
    },
    {
      plugin: SemanticUiCracoLessPlugin,
      options: {
        modifyLessRule: (lessRule) => ({
          ...lessRule,
          test: /\.(module)\.(less)$/,
          exclude: /node_modules/,
        }),
        cssLoaderOptions: {
          modules: true,
          localIdentName: '[path][name]__[local]--[hash:base64:5]',
        },
      },
    },
  ],
};

Hope it can help someone ! :)

All 5 comments

馃憢 Thanks for opening your first issue here! If you're reporting a 馃悶 bug, please make sure you've completed all the fields in the issue template so we can best help.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.

Ok, good news !

I finally succeed to use css-modules + semantic-ui. I renamed my styling files to *.module.less and set two less loader to the craco configuration file.
I modified the @semantic-ui-react/craco-less loader to allow passing pluginOptions through CracoLessPlugin.

craco.config.js :

const {
  getLoader,
  loaderByName,
  removeLoaders,
  throwUnexpectedConfigError,
} = require('@craco/craco');

const CracoLessPlugin = require('craco-less');

const path = require('path');

// Overriding CracoLessPlugin as @semantic-ui-react/craco-less to correctly load semantic-ui less files
const SemanticUiCracoLessPlugin = {
  overrideWebpackConfig: ({
    context,
    webpackConfig,
    pluginOptions,
  }) => {
    // add alias to theme.config
    webpackConfig.resolve.alias['../../theme.config$'] = path.join(context.paths.appSrc, '/semantic-ui/theme.config');

    // file-loader:
    // theme.config, *.variables and *.overrides files should be excluded
    const {
      isFound,
      match: fileLoaderMatch,
    } = getLoader(webpackConfig, loaderByName('file-loader'));

    if (!isFound) {
      throwUnexpectedConfigError({
        packageName: '@semantic-ui-react/craco-less',
        message: `Can't find "file-loader" in the ${context.env} webpack config!`,
      });
    }

    fileLoaderMatch.loader.exclude.push(/theme\.config$/);
    fileLoaderMatch.loader.exclude.push(/\.variables$/);
    fileLoaderMatch.loader.exclude.push(/\.overrides$/);

    // resolve-url-loader:
    // should be removed as it causes bugs
    // https://github.com/Semantic-Org/Semantic-UI-React/issues/3761
    removeLoaders(webpackConfig, loaderByName('resolve-url-loader'));

    // less-loader:
    // craco-less is reused
    return CracoLessPlugin.overrideWebpackConfig({
      context,
      webpackConfig,
      pluginOptions,
    });
  },
};

module.exports = {
  plugins: [
    {
      plugin: SemanticUiCracoLessPlugin,
    },
    {
      plugin: SemanticUiCracoLessPlugin,
      options: {
        modifyLessRule: (lessRule) => ({
          ...lessRule,
          test: /\.(module)\.(less)$/,
          exclude: /node_modules/,
        }),
        cssLoaderOptions: {
          modules: true,
          localIdentName: '[path][name]__[local]--[hash:base64:5]',
        },
      },
    },
  ],
};

Hope it can help someone ! :)

Now we just need pluginOptions!

@rickysullivan do you have an example with the pluginOptions I can't seem to make it work.

Thanks

@inkubux look at my code just before

Was this page helpful?
0 / 5 - 0 ratings