Skip to content

Commit 7aa1e47

Browse files
author
zougt
committed
feat(): create vite-plugin-theme-preprocessor
0 parents  commit 7aa1e47

24 files changed

+564
-0
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# editorconfig.org
2+
3+
[*]
4+
charset = utf-8
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false

.eslintignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/coverage
2+
/dist
3+
/node_modules
4+
/test/fixtures

.eslintrc.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
root: true,
3+
extends: ["@webpack-contrib/eslint-config-webpack", "prettier"],
4+
};

.gitattributes

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package-lock.json -diff
2+
* text=auto
3+
bin/* eol=lf
4+
yarn.lock -diff

.gitignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
logs
2+
*.log
3+
npm-debug.log*
4+
.eslintcache
5+
6+
/coverage
7+
/dist
8+
/local
9+
/reports
10+
/node_modules
11+
index.js
12+
13+
.DS_Store
14+
Thumbs.db
15+
.idea
16+
*.iml
17+
.vscode
18+
*.sublime-project
19+
*.sublime-workspace
20+
.nyc_output
21+
test/outputs

.prettierignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/coverage
2+
/dist
3+
/node_modules
4+
/test/fixtures
5+
CHANGELOG.md
6+
/test/sass
7+
/test/scss

LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright JS Foundation and other contributors
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
'Software'), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# @zougt/vite-plugin-theme-preprocessor
2+
3+
一个[vite v2.0+](https://cn.vitejs.dev/)插件,用于实现多个 `less``sass` 变量文件编译出多主题的 css
4+
5+
使得基于`less``sass`以及`css modules`的主题样式在线动态切换变得很简单
6+
7+
使用了插件钩子:
8+
9+
- config
10+
- configResolved
11+
- buildStart
12+
- generateBundle
13+
- transformIndexHtml
14+
15+
> 注:由于 vite 内置 css 插件未提供外接`less``sass`的口子(类似[`webpack-contrib/less-loader`](https://github.com/webpack-contrib/less-loader)`implementation`),在`@zougt/vite-plugin-theme-preprocessor`的 buildStart 内替换了相对于根目录的 node_modules 里面的`less``sass`
16+
17+
## 安装与使用
18+
19+
```bash
20+
# use npm
21+
npm install @zougt/vite-plugin-theme-preprocessor -D
22+
# use yarn
23+
yarn add @zougt/vite-plugin-theme-preprocessor -D
24+
```
25+
26+
**vite.config.js**
27+
28+
```js
29+
import themePreprocessorPlugin, {
30+
getModulesScopeGenerater,
31+
} from "@zougt/vite-plugin-theme-preprocessor";
32+
export default {
33+
plugins: [
34+
themePreprocessorPlugin({
35+
scss: {
36+
multipleScopeVars: [
37+
{
38+
scopeName: "theme-default",
39+
path: path.resolve("src/theme/default-vars.scss"),
40+
},
41+
{
42+
scopeName: "theme-mauve",
43+
path: path.resolve("src/theme/mauve-vars.scss"),
44+
},
45+
],
46+
// 默认取 multipleScopeVars[0].scopeName
47+
defaultScopeName: "",
48+
// 在生产模式是否抽取独立的主题css文件,extract为true以下属性有效
49+
extract: true,
50+
// 独立主题css文件的输出路径,默认取 viteConfig.build.assetsDir 相对于 (viteConfig.build.outDir)
51+
outputDir: "",
52+
// 会选取defaultScopeName对应的主题css文件在html添加link
53+
themeLinkTagId: "theme-link-tag",
54+
// "head"||"head-prepend" || "body" ||"body-prepend"
55+
themeLinkTagInjectTo: "head",
56+
// 是否对抽取的css文件内对应scopeName的权重类名移除
57+
removeCssScopeName: false,
58+
// 可以自定义css文件名称的函数
59+
customThemeCssFileName: (scopeName) => scopeName,
60+
},
61+
// less: {
62+
// multipleScopeVars: [
63+
// {
64+
// scopeName: "theme-default",
65+
// path: path.resolve("src/theme/default-vars.less"),
66+
// },
67+
// {
68+
// scopeName: "theme-mauve",
69+
// path: path.resolve("src/theme/mauve-vars.less"),
70+
// },
71+
// ],
72+
// },
73+
}),
74+
],
75+
};
76+
```
77+
78+
## 多主题编译示例(以 sass 为例)
79+
80+
```scss
81+
//src/theme/default-vars.scss
82+
/**
83+
*此scss变量文件作为multipleScopeVars去编译时,会自动移除!default以达到变量提升
84+
*同时此scss变量文件作为默认主题变量文件,被其他.scss通过 @import 时,必需 !default
85+
*/
86+
$primary-color: #0081ff !default;
87+
```
88+
89+
```scss
90+
//src/theme/mauve-vars.scss
91+
$primary-color: #9c26b0;
92+
```
93+
94+
```scss
95+
//src/components/Button/style.scss
96+
@import "../../theme/default-vars";
97+
.un-btn {
98+
position: relative;
99+
display: inline-block;
100+
font-weight: 400;
101+
white-space: nowrap;
102+
text-align: center;
103+
border: 1px solid transparent;
104+
background-color: $primary-color;
105+
.anticon {
106+
line-height: 1;
107+
}
108+
}
109+
```
110+
111+
编译之后
112+
113+
src/components/Button/style.css
114+
115+
```css
116+
.un-btn {
117+
position: relative;
118+
display: inline-block;
119+
font-weight: 400;
120+
white-space: nowrap;
121+
text-align: center;
122+
border: 1px solid transparent;
123+
}
124+
.theme-default .un-btn {
125+
background-color: #0081ff;
126+
}
127+
.theme-mauve .un-btn {
128+
background-color: #9c26b0;
129+
}
130+
.un-btn .anticon {
131+
line-height: 1;
132+
}
133+
```
134+
135+
### 并且支持 Css Modules
136+
137+
对于`*.module.scss`,得到的 css 类似:
138+
139+
```css
140+
.src-components-Button-style_un-btn-1n85E {
141+
position: relative;
142+
display: inline-block;
143+
font-weight: 400;
144+
white-space: nowrap;
145+
text-align: center;
146+
border: 1px solid transparent;
147+
}
148+
.theme-default .src-components-Button-style_un-btn-1n85E {
149+
background-color: #0081ff;
150+
}
151+
.theme-mauve .src-components-Button-style_un-btn-1n85E {
152+
background-color: #9c26b0;
153+
}
154+
.src-components-Button-style_un-btn-1n85E
155+
.src-components-Button-style_anticon-1n85E {
156+
line-height: 1;
157+
}
158+
```
159+
160+
## 在线切换主题 css 文件
161+
162+
```js
163+
const toggleTheme = (scopeName = "theme-default") => {
164+
let styleLink = document.getElementById("theme-link-tag");
165+
if (styleLink) {
166+
// 假如存在id为theme-link-tag 的link标签,直接修改其href
167+
styleLink.href = `/${scopeName}.css`;
168+
// 注:如果是removeCssScopeName:true移除了主题文件的权重类名,就可以不用修改className 操作
169+
document.documentElement.className = scopeName;
170+
} else {
171+
// 不存在的话,则新建一个
172+
styleLink = document.createElement("link");
173+
styleLink.type = "text/css";
174+
styleLink.rel = "stylesheet";
175+
styleLink.id = "theme-link-tag";
176+
styleLink.href = `/${scopeName}.css`;
177+
// 注:如果是removeCssScopeName:true移除了主题文件的权重类名,就可以不用修改className 操作
178+
document.documentElement.className = scopeName;
179+
document.head.append(styleLink);
180+
}
181+
};
182+
```
183+
184+
webpack 版本的实现方案请查看[`@zougt/some-loader-utils`](https://github.com/GitOfZGT/some-loader-utils#getSass)

babel.config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const MIN_BABEL_VERSION = 7;
2+
3+
module.exports = (api) => {
4+
api.assertVersion(MIN_BABEL_VERSION);
5+
api.cache(true);
6+
7+
return {
8+
presets: [
9+
[
10+
"@babel/preset-env",
11+
{
12+
targets: {
13+
node: "12.0.0",
14+
},
15+
},
16+
],
17+
],
18+
};
19+
};

commitlint.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
extends: ["@commitlint/config-conventional"],
3+
};

husky.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
hooks: {
3+
"pre-commit": "lint-staged",
4+
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
5+
},
6+
};

jest.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
testEnvironment: "node",
3+
};

lint-staged.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
"*.js": ["eslint --fix", "prettier --write"],
3+
"*.{json,md,yml,css,ts}": ["prettier --write"],
4+
};

package.json

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"name": "@zougt/vite-plugin-theme-preprocessor",
3+
"version": "1.0.0",
4+
"description": "css theme preprocessor plugin for vite",
5+
"license": "MIT",
6+
"repository": "GitOfZGT/vite-plugin-theme-preprocessor",
7+
"author": "zougt",
8+
"homepage": "https://github.com/GitOfZGT/vite-plugin-theme-preprocessor",
9+
"bugs": "https://github.com/GitOfZGT/vite-plugin-theme-preprocessor/issues",
10+
"main": "dist/index.js",
11+
"engines": {
12+
"node": ">= 12.0.0"
13+
},
14+
"scripts": {
15+
"start": "npm run build -- -w",
16+
"clean": "del-cli dist",
17+
"prebuild": "npm run clean",
18+
"build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
19+
"commitlint": "commitlint --from=master",
20+
"security": "npm audit",
21+
"lint:prettier": "prettier --list-different .",
22+
"lint:js": "eslint --cache .",
23+
"lint": "npm-run-all -l -p \"lint:**\"",
24+
"pretest": "npm run lint",
25+
"prepare": "npm run build",
26+
"release": "standard-version"
27+
},
28+
"files": [
29+
"dist"
30+
],
31+
"dependencies": {
32+
"@zougt/some-loader-utils": "^1.1.0",
33+
"fs-extra": "^9.1.0",
34+
"string-hash": "^1.1.3"
35+
},
36+
"devDependencies": {
37+
"@babel/cli": "^7.12.10",
38+
"@babel/core": "^7.12.10",
39+
"@babel/preset-env": "^7.12.11",
40+
"@commitlint/cli": "^11.0.0",
41+
"@commitlint/config-conventional": "^11.0.0",
42+
"@webpack-contrib/defaults": "^6.3.0",
43+
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
44+
"babel-jest": "^26.6.3",
45+
"cross-env": "^7.0.3",
46+
"del": "^6.0.0",
47+
"del-cli": "^3.0.1",
48+
"enhanced-resolve": "^5.5.0",
49+
"eslint": "^7.13.0",
50+
"eslint-config-prettier": "^7.1.0",
51+
"eslint-plugin-import": "^2.22.1",
52+
"foundation-sites": "^6.6.3",
53+
"husky": "^4.3.6",
54+
"jest": "^26.6.3",
55+
"less": "^4.1.1",
56+
"lint-staged": "^10.5.4",
57+
"npm-run-all": "^4.1.5",
58+
"prettier": "^2.2.1",
59+
"sass": "^1.32.8",
60+
"semver": "^7.3.4",
61+
"standard-version": "^9.1.0",
62+
"stylus": "^0.54.8"
63+
},
64+
"keywords": [
65+
"vite-plugin",
66+
"theme",
67+
"css",
68+
"less",
69+
"sass",
70+
"stylus",
71+
"preprocessor"
72+
],
73+
"publishConfig": {
74+
"registry": "https://registry.npmjs.org"
75+
}
76+
}

src/substitute/less/bin/lessc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env node
2+
3+
// eslint-disable-next-line import/no-unresolved
4+
require("@zougt/vite-plugin-theme-preprocessor/original/less/bin/lessc");

src/substitute/less/dist/less.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// eslint-disable-next-line import/no-unresolved
2+
export * from "@zougt/vite-plugin-theme-preprocessor/original/less/dist/less";

src/substitute/less/dist/less.min.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// eslint-disable-next-line import/no-unresolved
2+
export * from "@zougt/vite-plugin-theme-preprocessor/original/less/dist/less.min";

0 commit comments

Comments
 (0)