Skip to content

Commit

Permalink
chore(): add multipleScopeVars[].includeStyles
Browse files Browse the repository at this point in the history
  • Loading branch information
GitOfZGT committed Sep 19, 2021
1 parent 99992b2 commit c17387f
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 102 deletions.
97 changes: 85 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
# @zougt/some-loader-utils

开始作为[`@zougt/less-loader`](https://github.com/GitOfZGT/less-loader)[`@zougt/sass-loader`](https://github.com/GitOfZGT/less-loader)的公共依赖

提供了方法:

- [getAllStyleVarFiles](#getAllStyleVarFiles)
- [getVarsContent](#getVarsContent)
- [getScopeProcessResult](#getScopeProcessResult)

之后可能不再维护[`@zougt/less-loader`](https://github.com/GitOfZGT/less-loader)[`@zougt/sass-loader`](https://github.com/GitOfZGT/less-loader)同步 fork 更新,提供了[`less-loader`](https://github.com/webpack-contrib/less-loader)[`sass-loader`](https://github.com/webpack-contrib/sass-loader)`implementation` 版本的多主题变量文件编译方案的方法:
提供了[`less-loader`](https://github.com/webpack-contrib/less-loader)[`sass-loader`](https://github.com/webpack-contrib/sass-loader)`implementation` 版本的多主题变量文件编译方案的方法:

- [getLess](#getLess)
- [getSass](#getSass)

使得基于`less``sass`的(新、旧)项目实现在线预设主题的动态切换变得很简单,并且兼容性最好。
使得基于`less``sass`的(新、旧)项目实现在线预设主题的动态切换变得很简单,并且兼容性最好,很优雅的一种实现方案

![主题切换效果](./example.gif)
![主题切换效果](./images/example.gif)

## 安装与使用

Expand Down Expand Up @@ -45,6 +37,12 @@ const multipleScopeVars = [
{
scopeName: 'theme-default',
path: path.resolve('src/theme/default-vars.less'),
// v1.3.0 支持 includeStyles
includeStyles: {
'.el-button--primary:hover, .el-button--primary:focus': {
color: '#FFFFFF',
},
},
},
{
scopeName: 'theme-mauve',
Expand Down Expand Up @@ -106,7 +104,7 @@ module.exports = {
rules: [
{
test: /\.scss$/i,
// 请确保支持 implementation 属性的 sass-loader版本
// 请确保支持 implementation 属性的 sass-loader版本
loader: 'sass-loader',
options: {
sassOptions: {
Expand Down Expand Up @@ -375,6 +373,81 @@ const allStyleVarFiles = getAllStyleVarFiles(
);
```

### multipleScopeVars[].includeStyles

> v1.3.0 支持 includeStyles
Type: `Object`

当存在以下情况时,可以用这个属性处理

```css
.theme-blue .el-button:focus,
.theme-blue .el-button:hover {
/*这里的color值由 $primary-color 编译得来的,所以选择器前面加了 .theme-blue 提高了权重*/
color: #0281ff;
border-color: #b3d9ff;
background-color: #e6f2ff;
}
.el-button--primary:focus,
.el-button--primary:hover {
/*这里的color值不是由 变量 编译得来的,这时就会被上面那个 color 覆盖了, 实际上这里的color才是需要的效果*/
color: #fff;
}
```

```js
const includeStyles = {
'.el-button--primary:hover, .el-button--primary:focus': {
color: '#FFFFFF',
},
};
const multipleScopeVars = [
{
scopeName: 'theme-default',
path: path.resolve('src/theme/default-vars.less'),
includeStyles
},
{
scopeName: 'theme-mauve',
path: path.resolve('src/theme/mauve-vars.less'),
includeStyles
},
];
const allStyleVarFiles = getAllStyleVarFiles(
{
emitError: (msg) => {
throw new Error(msg);
},
},
{ multipleScopeVars }
);
```

得到

```css
.theme-blue .el-button:focus,
.theme-blue .el-button:hover {
/*这里的color值由 $primary-color 编译得来的,所以选择器前面加了 .theme-blue 提高了权重*/
color: #0281ff;
border-color: #b3d9ff;
background-color: #e6f2ff;
}
.theme-blue .el-button--primary:focus,
.theme-blue .el-button--primary:hover {
/*这里的color值不是由 变量 编译得来的,这时就会被上面那个 color 覆盖了, 实际上这里的color才是需要的效果*/
color: #FFFFFF;
}
```
出现权重问题效果图

![includeStyles](./images/includeStyles_p.png)

使用了 includeStyles 的效果图

![includeStyles](./images/includeStyles_r.png)

## getVarsContent

Type `Function`
Expand Down
File renamed without changes
Binary file added images/includeStyles_p.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/includeStyles_r.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zougt/some-loader-utils",
"version": "1.2.2",
"version": "1.3.0",
"description": "implementation for less-loader or sass-loader. Compiles Less or sass to CSS.",
"license": "MIT",
"repository": "GitOfZGT/some-loader-utils",
Expand Down Expand Up @@ -38,7 +38,8 @@
"sass": "^1.32.8"
},
"dependencies": {
"postcss": "^8.2.9"
"postcss": "^8.2.9",
"parse-color": "^1.0.0"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
Expand Down
11 changes: 10 additions & 1 deletion src/getLess.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ import {
*/
export function getLess(opt = {}) {
const packname = 'less';
const less = opt.implementation || require(packname);
let less = opt.implementation;
if (!less) {
try {
less = require(packname);
} catch (e) {
throw new Error(
`Dependency "${packname}" not found. Did you install it?`
);
}
}
const { render } = less;
// eslint-disable-next-line func-names
less.render = function (input, options = {}, callback) {
Expand Down
12 changes: 10 additions & 2 deletions src/getSass.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ import {
export function getSass(opt = {}) {
const packname = "sass";

const sass = opt.implementation || require(packname);

let sass = opt.implementation;
if (!sass) {
try {
sass = require(packname);
} catch (e) {
throw new Error(
`Dependency "${packname}" not found. Did you install it?`
);
}
}
const { render } = sass;

// eslint-disable-next-line func-names
Expand Down
107 changes: 95 additions & 12 deletions src/postcss-addScopeName.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import postcss from 'postcss';

import colorParse from 'parse-color';

export default (
opts = { allStyleVarFiles: [], allCssCodes: [], startIndex: 0 }
) => {
const { allStyleVarFiles } = opts;
function addScopeName(selector, scopeName) {
if (/^html/i.test(selector)) {
return selector.replace(
/^html[^\s]*(?=\s*)/gi,
(word) => `${word}.${scopeName}`
);
}
return `.${scopeName} ${selector}`;
}
// allStyleVarFiles的个数与allCssCodes对应的
// 除去startIndex的,其他的css转成ast
const restCssAsts = opts.allCssCodes
.filter((item, i) => i !== opts.startIndex)
.map((code) => postcss.parse(code));
return {
postcssPlugin: 'postcss-addScopeName',
Rule(rule) {
Rule(rule, { Rule, Declaration }) {
// 与当前样式规则不相同的其他主题样式规则
const themeRules = [];
// 当前规则中与其他主题规则中不相同的属性
Expand Down Expand Up @@ -58,8 +70,8 @@ export default (
childNodes.push(themeRuleNodeMap[prop]);
currentThemeProps[prop] =
currentRuleNodeMap[prop].value;
delete themeRuleNodeMap[prop];
}
delete themeRuleNodeMap[prop];
});
// 假如比对后还有剩余,也纳入主题属性
Object.keys(themeRuleNodeMap).forEach((prop) => {
Expand Down Expand Up @@ -92,23 +104,94 @@ export default (
value: currentThemeProps[key],
});
});

// 保持themeRules的顺序对应 opts.allStyleVarFiles的顺序,然后添加scopeName
themeRules.splice(opts.startIndex, 0, ruleClone);
themeRules.forEach((item, i) => {
if (item && item.nodes.length) {
// eslint-disable-next-line no-param-reassign
item.selectors = item.selectors.map((selector) => {
if (/^html/i.test(selector)) {
return selector.replace(
/^html[^\s]*(?=\s*)/gi,
(word) =>
`${word}.${opts.allStyleVarFiles[i].scopeName}`
);
item.selectors = item.selectors.map((selector) =>
addScopeName(
selector,
allStyleVarFiles[i].scopeName
)
);
root.insertBefore(rule, item);
}
});
const selectorMap = rule.selectors.reduce((tol, key) => {
return { ...tol, [key]: true };
}, {});
allStyleVarFiles.forEach((item) => {
if (
item.includeStyles &&
typeof item.includeStyles === 'object' &&
!Array.isArray(item.includeStyles)
) {
const includeKey = Object.keys(item.includeStyles).find(
(key) => {
const selectors = key
.replace(/,\s+/g, ',')
.split(',');
return selectors.every((s) => selectorMap[s]);
}
);
if (includeKey) {
const newRule = new Rule({
selector: rule.selector,
});
newRule.selectors = newRule.selectors.map(
(selector) =>
addScopeName(selector, item.scopeName)
);
Object.keys(item.includeStyles[includeKey]).forEach(
(prop) => {
const decl = new Declaration({
prop,
value: item.includeStyles[includeKey][
prop
],
});
newRule.append(decl);
const currDecl = rule.nodes.find((node) => {
if (node.prop === decl.prop) {
if (node.value === decl.value) {
return true;
}

return `.${opts.allStyleVarFiles[i].scopeName} ${selector}`;
});
root.insertBefore(rule, item);
let colorHex = null;
let isQueit = false;

try {
colorHex = colorParse(
node.value
);

if (
colorHex &&
colorHex.hex ===
colorParse(decl.value)
.hex
) {
isQueit = true;
}
} catch (e) {
console.warn(e);
}

return isQueit;
}

return false;
});

if (currDecl) {
rule.removeChild(currDecl);
}
}
);
root.insertBefore(rule, newRule);
}
}
});

Expand Down
Loading

0 comments on commit c17387f

Please sign in to comment.