Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to have multiple themes when working with Webpack. #67

Open
andrewplummer opened this issue Jul 8, 2019 · 5 comments
Open

No way to have multiple themes when working with Webpack. #67

andrewplummer opened this issue Jul 8, 2019 · 5 comments

Comments

@andrewplummer
Copy link

Hi... first off thanks for the awesome library. The concept is fanstaic. However some of the implementation such as reversing the imports for the config (ie. importing theme.config from the "inside out" -- from inside the node module into your source directory) make it very brittle to use with webpack it would seem. First off, is the only approach really to use webpack's resolve.alias? Aside from feeling hacky, it leads to situations like where I want to compile multiple entry points and it doesn't seem possible... for example:

  resolve: {
    alias: {
      '../../theme.config$': path.resolve('./src/app1/theme.config'),
      '../../theme.config$': path.resolve('./src/app2/theme.config')
    }
  },

What is the official way to resolve the conflict with the above 2 lines? Yes of course I could split the webpack entry points out to different webpack configs but then I would lose the benefit of chunking as well as a lot of other hassles to deal with.

@ghost
Copy link

ghost commented Jan 11, 2020

Thanks for the question. Have the same problem here... How build many themes using Webpack in order to use theme with a Theme selector in a React app ?

@aautem
Copy link

aautem commented Aug 25, 2020

@andrewplummer Were you ever able to find a solution for this?

@andrewplummer
Copy link
Author

@aautem not really.. I find overriding the theming cumbersome anyway so I've been manually importing the specific styles I need for "functional styles" (like hiding/showing modals) and writing everything else from scratch

@skolmer
Copy link

skolmer commented Dec 2, 2020

There is a way to build multiple themes in one project using less-loader:

This is the minimum configuration required for webpack:

{
  resolve: {
    alias: {
      '../../theme.config$': path.join(paths.appSrc, '/semantic-ui/theme.config')
    }
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          {
            loader: "less-loader",
            options: {
              additionalData: (content, loaderContext) => {
                const { resourceQuery } = loaderContext;
                const theme = /[?&]theme=([^?&]+)/.exec(resourceQuery);
                if (theme) {
                  console.log("building custom theme: " + theme[1]);
                  return "@custom_theme: " + theme[1] + ";" + content;
                }

                return content;
              },
            },
          },
        ],
      },
    ],
  },
}

or use craco config:

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

module.exports = {
  plugins: [{ 
    plugin: CracoLessPlugin,
    options: {
      lessLoaderOptions: {
        additionalData: (content, loaderContext) => {
          const { resourceQuery } = loaderContext;
          const theme = /[?&]theme=([^?&]+)/.exec(resourceQuery);
          if (theme) {
            console.log("building custom theme: " + theme[1]);
            return "@custom_theme: " + theme[1] + ";" + content;
          }

          return content;
        }
     }
   }
  }]
};

In your theme.config you can now use multiple site directories or do other customizations based on the loaded theme:

/* Path to site override folder */
@siteFolder  : '../../src/semantic-ui/@{custom_theme}/site';

Now you are able to lazy load your theme at runtime by adding a JS module for each theme like this one (./src/semantic-ui/dark.js):

import 'semantic-ui-less/semantic.less?theme=dark';

To load the theme based on a query string for example you could do this in your main module:

const urlParams = new URLSearchParams(window.location.search);
const theme = urlParams.get('theme');

if (theme === 'dark') {
  import('./semantic-ui/dark.js').then(render).catch(console.error);
} else {
  import('./semantic-ui/light.js').then(render).catch(console.error);
}

const render = () => {
  // theme is now loaded. render your app...
}

@alolis
Copy link

alolis commented Jul 18, 2023

@skolmer, in case you are still watching this, any insights on how to make your proposed solution work dynamically on re-render (based on some component prop for example) instead of page reload?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants