Webpack + postcss + themes + hot reloading

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-05 15:32:34

Here is a solution using SASS. It's basically your solution 1 but easier to write and maintain. It seams that you're not using SASS but since it's the best solution I could find for my personal use, I thought it worth sharing...

Here is the SCSS code (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);
  }
}

It requires this to work:

@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;
}

Resulting CSS:

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

This is heavily inspired by:

One possible approach could be as follow

  1. Not to use style-loader because it inserts css automatically, but do it manually when we need and what we need.

for example:

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

(we need raw-loader here)

  1. then we just insert required style to document.

for example:

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. then you can change your theme when you need

just put another style to href:

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

or let's do same via 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;

it'll work if you set the raw-loader to handle css file in webpack.config

{
  test: /\.css$/,
  loader: 'raw'
},
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!