Webpack + postcss + 主题 + 热加载
Posted
技术标签:
【中文标题】Webpack + postcss + 主题 + 热加载【英文标题】:Webpack + postcss + themes + hot reloading 【发布时间】: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.css
或theme2-main.css
或类似的东西。问题是我不知道如何支持开发环境。
这样做的好处是我的 css 文件不需要任何额外且难以维护的逻辑:
.myComponent
margin: 10px;
width: 100px;
background: $myComponent_background;
解决方案 3
使用原生 css 变量。然后可以在运行时更新它们,这将反映已经加载的 css 并在生产和开发环境中正常工作。我的组件也看起来像(或类似于)解决方案 2。这里的问题是它们本身并没有得到广泛的支持,我不确定是否有任何值得研究的 polyfill 可以为我做这种事情。
总而言之,这些是我的想法。我还没有得出任何明确的结论,并希望得到所有关于如何解决这个问题的反馈。也许我在想这一切都错了,有一种更好的方法可以做我想做的事。
提前致谢!
【问题讨论】:
我认为解决方案 2 更好,前提是您可以自动完成(为单个主题构建网站,并且自动制作其他捆绑包)。 @AshishChaudhary 当然可以,但是我如何启用它进行开发?我在开发过程中不请求 CSS 包。 您最终找到解决方案了吗?也遇到了这个确切的问题。 @Dean 不。我暂时选择了解决方案 1,直到它在我的脸上爆炸。最好的解决方案是在原生 CSS 变量可用时使用它们。 【参考方案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;
这在很大程度上受到了以下启发:
https://www.sitepoint.com/sass-theming-neverending-story/ https://jaicab.com/sass-vary/【讨论】:
【参考方案2】:一种可能的方法如下
-
不要使用
style-loader
,因为它会自动插入 css,而是手动执行何时我们需要和我们需要什么。
例如:
const css1 = require("raw!./App1.css");
const css2 = require("raw!./App2.css");
(这里需要raw-loader
)
-
然后我们只需将所需的样式插入到文档中。
例如:
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);
-
然后您可以根据需要更改主题
给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" />
<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'
,
【讨论】:
以上是关于Webpack + postcss + 主题 + 热加载的主要内容,如果未能解决你的问题,请参考以下文章
【Webpack4】CSS 配置之 postcss-loader
Webpack postcss loader,它的目的是啥?
postcss 不能与 webpack 5 和 sass 结合使用