【问题标题】:Webpack + postcss + themes + hot reloadingWebpack + postcss + 主题 + 热加载
【发布时间】:2016-12-22 03:25:21
【问题描述】:

我想允许用户在我的网站上选择主题,他们将通过下拉菜单来选择。不过,我目前在不编写愚蠢代码的情况下无法弄清楚如何支持此功能。

我目前使用 css-modules 和 postcss 来让我的生活更轻松。 Webpack 用于将所有内容捆绑在一起。我在开发过程中使用热重载,在此期间我使用样式加载器。

完整配置如下所示

{
  test: /\.css$/,
  loader: !isDev
    ? ExtractTextPlugin.extract('style-loader', 'css-loader?sourcemap&minimize&modules&importLoaders=1&localIdentName=[name]-[local]-[hash:base64:5]!postcss-loader')
    : 'style-loader!css-loader?sourcemap&minimize&modules&importLoaders=1&localIdentName=[name]-[local]-[hash:base64:5]!postcss-loader'
},

解决方案 1

在 body 标记上放置一个类名以确定加载的主题。然后用于从每个组件 css 中选择正确的主题。这很乏味,我想避免,但它看起来像这样:

.myComponent {
  margin: 10px;
  width: 100px;
}

:global(.theme1) {
  .myComponent {
    background: $theme1_myComponent_background;
  }
}

:global(.theme2) {
  .myComponent {
    background: $theme2_myComponent_background;
  }
}

这很快就会变成难以扩展和不可维护的事情,这就是我想避免它的原因。

解决方案 2

为 css 生成预先主题的静态包。当用户请求/main.css 时,服务器上的处理程序确定要发送哪个主题(可能是查询字符串)并发送它们theme1-main.csstheme2-main.css 或类似的东西。问题是我不知道如何支持开发环境。

这样做的好处是我的 css 文件不需要任何额外且难以维护的逻辑:

.myComponent {
  margin: 10px;
  width: 100px;
  background: $myComponent_background;
}

解决方案 3

使用原生 css 变量。然后可以在运行时更新它们,这将反映已经加载的 css 并在生产和开发环境中正常工作。我的组件也看起来像(或类似于)解决方案 2。这里的问题是它们本身并没有得到广泛的支持,我不确定是否有任何值得研究的 polyfill 可以为我做这种事情。


总而言之,这些是我的想法。我还没有得出任何明确的结论,并希望得到所有关于如何解决这个问题的反馈。也许我在想这一切都错了,有一种更好的方法可以做我想做的事。

提前致谢!

【问题讨论】:

  • 我认为解决方案 2 更好,前提是您可以自动完成(为单个主题构建网站,并且自动制作其他捆绑包)。
  • @AshishChaudhary 当然可以,但是我如何启用它进行开发?我在开发过程中不请求 CSS 包。
  • 您最终找到解决方案了吗?也遇到了这个确切的问题。
  • @Dean 不。我暂时选择了解决方案 1,直到它在我的脸上爆炸。最好的解决方案是在原生 CSS 变量可用时使用它们。

标签: css reactjs themes webpack postcss


【解决方案1】:

这是一个使用 SASS 的解决方案。它基本上是您的解决方案 1,但更易于编写和维护。看起来你没有使用 SASS,但由于它是我能找到的供我个人使用的最佳解决方案,我认为值得分享......

这是 SCSS 代码 (CodePen here):

// Define theme variables

$themes: (
  default: ( // default theme
    bg-color: white,
    text-color: black,
  ),
  dark: (
    bg-color: black,
    text-color: white,
  ),
  colorful: (
    bg-color: green,
    text-color: orange,
  )
);

// This is how you use your themes

.example{
  padding: 10px;
  @include themify {
    background: theme-get(bg-color);
    color: theme-get(text-color);
  }
}

它需要这样才能工作:

@mixin themify() {
  // Iterate over the themes
  @each $theme-name, $theme in $themes {
    $current-theme: $theme !global;
    @if $theme-name == 'default' {
      @content;
    } @else {
      .theme-#{$theme-name} & {
        @content;
      }
    }
  }
}

@function theme-get($key, $theme: $current-theme) {
  $ret: map-get($theme, $key);
  @if not $ret {
    @error 'Your theme doesn\'t have a value for `#{$key}`.';    
  }
  @return $ret;
}

生成的 CSS:

.example {
  padding: 10px;
  background: white;
  color: black;
}
.theme-dark .example {
  background: black;
  color: white;
}
.theme-colorful .example {
  background: green;
  color: orange;
}

这在很大程度上受到了以下启发:

【讨论】:

    【解决方案2】:

    一种可能的方法如下

    1. 不要使用style-loader,因为它会自动插入 css,而是手动执行何时我们需要和我们需要什么

    例如:

    const css1 = require("raw!./App1.css");
    const css2 = require("raw!./App2.css");
    

    (这里需要raw-loader

    1. 然后我们只需将所需的样式插入到文档中。

    例如:

    const style = document.createElement("link");
    style.type = "stylesheet/text-css";
    style.rel = "stylesheet";
    style.href=`data:text/css,${css1}`;
    // style.href=`data:text/css,${css2}`;
    style.id = "theming";
    
    document.querySelector("head").appendChild(style);
    
    1. 然后您可以根据需要更改主题

    href换个风格就行了:

    style.href=`data:text/css,${css2}`
    

    或者让我们通过 React 做同样的事情:

    import React, { Component } from 'react';
    import logo from './logo.svg';
    
    class App extends Component {
      constructor(props) {
        super(props);
    
        this.cssThemes = [];
        this.cssThemes.push(require("./App.css"));
        this.cssThemes.push(require("./App1.css"));
        this.cssThemes.push(require("./App2.css"));
        this.cssThemes.push(require("./App3.css"));
    
        this.state = { 
          themeInd: 0,
        }
      }
      render() {
        return (
          <div >
          <style>
            {this.cssThemes[this.state.themeInd]}
          </style>
            <div className="App-header">
              <img src={logo} className="App-logo" alt="logo" />
              <h2>Welcome to React</h2>
            </div>
            <p >
              To get started, edit <code>src/App.js</code> and save to reload.
            </p>
            <button 
              onClick={() => this.setState({themeInd: this.state.themeInd+1})}
            >
              Change theme
            </button>
          </div>
        );
      }
    }
    
    export default App;
    

    如果你在 webpack.config 中设置 raw-loader 来处理 css 文件就可以了

    {
      test: /\.css$/,
      loader: 'raw'
    },
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-03
      • 2019-07-08
      • 2022-07-18
      • 2016-10-24
      • 2016-10-26
      • 2017-12-30
      • 1970-01-01
      • 2017-07-07
      相关资源
      最近更新 更多