compile-css 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -43
- package/compileCss.js +103 -78
- package/package.json +6 -3
- package/compileCssConfig.js +0 -10
package/README.md
CHANGED
|
@@ -1,71 +1,100 @@
|
|
|
1
|
-
# CSS
|
|
1
|
+
# CSS 编译工具
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
支持 SCSS、PostCSS、TailwindCSS 的 CSS 编译工具,自带文件监听功能。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g compile-css
|
|
9
|
-
#
|
|
9
|
+
# 或
|
|
10
10
|
npm install --save-dev compile-css
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## 使用方法
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
直接在项目根目录运行:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
# Compile once
|
|
19
18
|
compile-css
|
|
20
|
-
|
|
21
|
-
# Watch for changes
|
|
22
|
-
compile-css --watch
|
|
23
|
-
|
|
24
|
-
# Use custom config
|
|
25
|
-
compile-css --config ./my-config.js
|
|
26
19
|
```
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```javascript
|
|
31
|
-
const compileCss = require('compile-css');
|
|
32
|
-
|
|
33
|
-
// Use default config
|
|
34
|
-
compileCss();
|
|
21
|
+
工具会自动读取根目录下的 `compileCssConfig.js` 配置文件,启动文件监听并开始编译。
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
compileCss({
|
|
38
|
-
watch: true,
|
|
39
|
-
config: './custom-config.js'
|
|
40
|
-
});
|
|
41
|
-
```
|
|
23
|
+
## 配置说明
|
|
42
24
|
|
|
43
|
-
|
|
25
|
+
在项目根目录创建 `compileCssConfig.js` 文件。
|
|
44
26
|
|
|
45
|
-
|
|
27
|
+
### 配置示例
|
|
46
28
|
|
|
47
29
|
```javascript
|
|
48
30
|
const path = require('path');
|
|
49
31
|
|
|
50
32
|
module.exports = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
presets: [
|
|
34
|
+
{
|
|
35
|
+
name: 'pc', // 标识名称,用于日志输出
|
|
36
|
+
scss: path.resolve('./scss/pc'), // SCSS 源文件目录
|
|
37
|
+
content: path.resolve('./html/pc'), // TailwindCSS 扫描目录
|
|
38
|
+
temp: path.resolve('./temp/pc'), // 编译临时目录
|
|
39
|
+
dist: path.resolve('./html/pc', 'css'), // 编译输出目录
|
|
40
|
+
scssIgnore: [], // 忽略的 SCSS 文件
|
|
41
|
+
watchIgnore: [] // 忽略的监听文件
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'mobile',
|
|
45
|
+
scss: path.resolve('./scss/mobile'),
|
|
46
|
+
content: path.resolve('./html/mobile'),
|
|
47
|
+
temp: path.resolve('./temp/mobile'),
|
|
48
|
+
dist: path.resolve('./html/mobile', 'css'),
|
|
49
|
+
scssIgnore: [],
|
|
50
|
+
watchIgnore: []
|
|
51
|
+
}
|
|
52
|
+
]
|
|
57
53
|
};
|
|
58
54
|
```
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
### 配置项说明
|
|
57
|
+
|
|
58
|
+
| 配置项 | 类型 | 必填 | 说明 |
|
|
59
|
+
|--------|------|------|------|
|
|
60
|
+
| `name` | `string` | 否 | 标识名称,用于控制台日志输出,方便区分不同 preset 的编译信息 |
|
|
61
|
+
| `scss` | `string` | 是 | SCSS 源文件目录。递归扫描该目录下所有非 `_` 开头的 `.scss` 文件作为入口文件编译 |
|
|
62
|
+
| `content` | `string` | 是 | TailwindCSS 扫描目录。该目录下的文件变化会触发 `common.css` 重新编译。会与 `tailwind.config.js` 中的 `content` 合并 |
|
|
63
|
+
| `temp` | `string` | 是 | 编译临时目录。SCSS 先编译为普通 CSS 存放到此,再交给 PostCSS 处理。**每次启动时自动清空** |
|
|
64
|
+
| `dist` | `string` | 是 | 最终输出目录。经过 tailwindcss、autoprefixer、cssnano 处理后的 CSS 文件输出到这里 |
|
|
65
|
+
| `scssIgnore` | `string[]` | 否 | SCSS 忽略列表。支持文件名、相对路径或正则表达式。被忽略的文件不会作为入口文件编译 |
|
|
66
|
+
| `watchIgnore` | `string[]` | 否 | 监听忽略列表。`content` 目录中匹配的文件变化不会触发重新编译 |
|
|
67
|
+
|
|
68
|
+
### 忽略规则
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
70
|
+
`scssIgnore` 和 `watchIgnore` 支持四种匹配方式:
|
|
71
|
+
|
|
72
|
+
- **完整相对路径**:`'scss/common.scss'` — 匹配项目根目录下 `scss/common.scss`
|
|
73
|
+
- **目录前缀**:`'scss/lib'` — 匹配 `scss/lib` 目录下的所有文件
|
|
74
|
+
- **文件名**:`'_variables.scss'` — 匹配所有名为 `_variables.scss` 的文件
|
|
75
|
+
- **正则表达式**:`/^scss\/lib\//` — 使用正则匹配相对路径
|
|
76
|
+
|
|
77
|
+
### 注意事项
|
|
78
|
+
|
|
79
|
+
- `scss` 目录中以 `_` 开头的文件(如 `_variables.scss`)被视为模块文件,不会作为入口文件编译。但当模块文件发生变化时,会触发所有入口文件重新编译
|
|
80
|
+
- 每个 preset 的 `temp` 目录必须唯一,不能与其他 preset 共享
|
|
81
|
+
- 每个 preset 的 `temp` 目录启动时自动清空重建
|
|
82
|
+
- `tailwind.config.js` 必须放在项目根目录
|
|
83
|
+
- `content` 字段与 `tailwind.config.js` 中的 `content` 会合并,无需重复配置
|
|
84
|
+
|
|
85
|
+
## 编译流程
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
SCSS 文件 ──sass编译──▶ temp 目录(临时 CSS) ──tailwindcss + autoprefixer + cssnano──▶ dist 目录(最终 CSS)
|
|
89
|
+
```
|
|
68
90
|
|
|
69
|
-
|
|
91
|
+
1. SCSS 文件变化 → `sass` 编译到 `temp` 目录
|
|
92
|
+
2. `temp` 目录 CSS 文件变化 → PostCSS(tailwindcss + autoprefixer + cssnano)编译到 `dist` 目录
|
|
93
|
+
3. `content` 目录文件变化 → 重新编译 `common.css`,更新 TailwindCSS 工具类
|
|
70
94
|
|
|
71
|
-
|
|
95
|
+
## 功能特性
|
|
96
|
+
- SCSS 编译
|
|
97
|
+
- PostCSS 处理(tailwindcss、autoprefixer、cssnano)
|
|
98
|
+
- 文件变化自动监听编译
|
|
99
|
+
- 支持多套配置(PC、手机等多端项目)
|
|
100
|
+
- 启动时自动清理临时目录
|
package/compileCss.js
CHANGED
|
@@ -21,20 +21,13 @@ function loadUserConfig(configName) {
|
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
//
|
|
25
|
-
const config = loadUserConfig('compileCssConfig.js')
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const scss = config.paths.scss;
|
|
35
|
-
const template = config.paths.template;
|
|
36
|
-
const temp = config.paths.temp;
|
|
37
|
-
const dist = config.paths.dist;
|
|
24
|
+
// 加载编译配置
|
|
25
|
+
const config = loadUserConfig('compileCssConfig.js');
|
|
26
|
+
if (!config || !config.presets) {
|
|
27
|
+
console.error('错误:未找到 compileCssConfig.js 或配置缺少 presets 字段。');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
var presets = config.presets;
|
|
38
31
|
|
|
39
32
|
// 加载Tailwind配置(必须由用户提供)
|
|
40
33
|
const toption = loadUserConfig('tailwind.config.js');
|
|
@@ -43,14 +36,33 @@ if (!toption) {
|
|
|
43
36
|
process.exit(1);
|
|
44
37
|
}
|
|
45
38
|
|
|
39
|
+
/**
|
|
40
|
+
* 检查文件是否被忽略
|
|
41
|
+
* @param {string} filePath 文件路径
|
|
42
|
+
* @param {[string]} ignoreList 忽略列表,每个元素可以是字符串或正则表达式
|
|
43
|
+
* @return {boolean} 是否被忽略
|
|
44
|
+
*/
|
|
45
|
+
function isIgnored(filePath, ignoreList) {
|
|
46
|
+
const relative = path.relative(process.cwd(), filePath);
|
|
47
|
+
return ignoreList.some(ignored => {
|
|
48
|
+
if (typeof ignored === 'string') {
|
|
49
|
+
return relative === ignored || relative.startsWith(ignored + path.sep) || path.basename(filePath) === ignored;
|
|
50
|
+
}
|
|
51
|
+
if (ignored instanceof RegExp) {
|
|
52
|
+
return ignored.test(relative);
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
/**
|
|
47
59
|
* 获取入口文件列表
|
|
48
60
|
* @param {string|[string]} entrance 入口 文件路径或文件路径数组,可以是文件也可以是目录,目录要递归查找
|
|
61
|
+
* @param {[string]} ignoreList 忽略列表
|
|
49
62
|
* @return {[string]} 返回入口文件列表
|
|
50
63
|
*/
|
|
51
|
-
function getEntranceFiles(entrance) {
|
|
64
|
+
function getEntranceFiles(entrance, ignoreList) {
|
|
52
65
|
const result = new Set();
|
|
53
|
-
|
|
54
66
|
const entrances = Array.isArray(entrance) ? entrance : [entrance];
|
|
55
67
|
|
|
56
68
|
function walk(p) {
|
|
@@ -61,15 +73,14 @@ function getEntranceFiles(entrance) {
|
|
|
61
73
|
if (stat.isFile()) {
|
|
62
74
|
const ext = path.extname(p);
|
|
63
75
|
const name = path.basename(p);
|
|
64
|
-
|
|
65
|
-
// 只收集非 "_" 开头的 scss 文件
|
|
66
|
-
if (ext === '.scss' && !name.startsWith('_')) {
|
|
76
|
+
if (ext === '.scss' && !name.startsWith('_') && !isIgnored(p, ignoreList)) {
|
|
67
77
|
result.add(path.resolve(p));
|
|
68
78
|
}
|
|
69
79
|
return;
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
if (stat.isDirectory()) {
|
|
83
|
+
if (isIgnored(p, ignoreList)) return;
|
|
73
84
|
const files = fs.readdirSync(p);
|
|
74
85
|
for (const file of files) {
|
|
75
86
|
walk(path.join(p, file));
|
|
@@ -105,7 +116,10 @@ function postcssCompile(file, output, tcontent) {
|
|
|
105
116
|
|
|
106
117
|
let option = { ...toption };
|
|
107
118
|
if (tcontent) {
|
|
108
|
-
option.content =
|
|
119
|
+
option.content = [
|
|
120
|
+
...(Array.isArray(option.content) ? option.content : []),
|
|
121
|
+
...tcontent
|
|
122
|
+
];
|
|
109
123
|
}
|
|
110
124
|
let css = `@tailwind base;
|
|
111
125
|
@tailwind components;
|
|
@@ -139,67 +153,78 @@ function postcssCompile(file, output, tcontent) {
|
|
|
139
153
|
|
|
140
154
|
}
|
|
141
155
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
var
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (['add', 'change'].includes(eventName)) { //新增或者修改文件 进行编译操作
|
|
158
|
-
if (pathfile.endsWith('.scss')) {
|
|
159
|
-
// 获取文件名
|
|
160
|
-
let fileName = path.basename(pathfile);
|
|
161
|
-
let entranceFiles = [];
|
|
162
|
-
if(fileName.startsWith('_')){ //如果是模块,编译所有入口文件
|
|
163
|
-
entranceFiles = getEntranceFiles(scss);
|
|
164
|
-
}else{ //如果是普通文件,编译该文件
|
|
165
|
-
entranceFiles = [pathfile];
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// 编译入口文件
|
|
169
|
-
entranceFiles.forEach(entranceFile => {
|
|
170
|
-
let output = '';
|
|
171
|
-
output = entranceFile.replace(scss, temp);
|
|
172
|
-
//将文件扩展名改为css
|
|
173
|
-
output = output.replace(/\.scss$/, '.css');
|
|
174
|
-
sassCompile(entranceFile, output)
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
}
|
|
156
|
+
// 为每个 preset 启动独立的 watcher
|
|
157
|
+
presets.forEach(function (preset) {
|
|
158
|
+
var scssDir = preset.scss;
|
|
159
|
+
var contentDir = preset.content;
|
|
160
|
+
var tempDir = preset.temp;
|
|
161
|
+
var distDir = preset.dist;
|
|
162
|
+
var scssIgnore = preset.scssIgnore || [];
|
|
163
|
+
var watchIgnore = preset.watchIgnore || [];
|
|
164
|
+
var presetName = preset.name || 'default';
|
|
165
|
+
|
|
166
|
+
// 构建 TailwindCSS content 路径
|
|
167
|
+
var tailwindContent = [];
|
|
168
|
+
if (contentDir) {
|
|
169
|
+
tailwindContent.push(path.resolve(contentDir, '**/*'));
|
|
170
|
+
}
|
|
178
171
|
|
|
172
|
+
// 启动时清理并重新创建 temp 目录
|
|
173
|
+
if (fs.existsSync(tempDir)) {
|
|
174
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
175
|
+
}
|
|
176
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
177
|
+
|
|
178
|
+
var watchPaths = [
|
|
179
|
+
path.resolve(scssDir),
|
|
180
|
+
path.resolve(tempDir),
|
|
181
|
+
];
|
|
182
|
+
if (contentDir) {
|
|
183
|
+
watchPaths.push(path.resolve(contentDir));
|
|
184
|
+
}
|
|
179
185
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
chokidar.watch(watchPaths, {
|
|
187
|
+
ignored: [
|
|
188
|
+
...scssIgnore.map(function (i) { return path.resolve(process.cwd(), i); }),
|
|
189
|
+
...watchIgnore.map(function (i) { return path.resolve(process.cwd(), i); }),
|
|
190
|
+
],
|
|
191
|
+
persistent: true,
|
|
192
|
+
})
|
|
193
|
+
.on('all', function (eventName, pathfile, stats) {
|
|
194
|
+
try {
|
|
195
|
+
console.log('[' + presetName + ']', eventName, pathfile)
|
|
196
|
+
if (['add', 'change'].includes(eventName)) {
|
|
197
|
+
if (pathfile.endsWith('.scss')) {
|
|
198
|
+
var fileName = path.basename(pathfile);
|
|
199
|
+
var entranceFiles = [];
|
|
200
|
+
if (fileName.startsWith('_')) {
|
|
201
|
+
entranceFiles = getEntranceFiles(scssDir, scssIgnore);
|
|
202
|
+
} else {
|
|
203
|
+
entranceFiles = [pathfile];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
entranceFiles.forEach(function (entranceFile) {
|
|
207
|
+
var output = entranceFile.replace(scssDir, tempDir);
|
|
208
|
+
output = output.replace(/\.scss$/, '.css');
|
|
209
|
+
sassCompile(entranceFile, output);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
190
212
|
|
|
213
|
+
if (pathfile.endsWith('.css')) {
|
|
214
|
+
var output = pathfile.replace(tempDir, distDir);
|
|
215
|
+
postcssCompile(pathfile, output, tailwindContent);
|
|
216
|
+
}
|
|
191
217
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
input = path.resolve(temp, 'common.css');
|
|
198
|
-
output = path.resolve(dist, 'common.css');
|
|
199
|
-
postcssCompile(input, output, tcontent);
|
|
218
|
+
if (contentDir && !isIgnored(pathfile, watchIgnore)) {
|
|
219
|
+
var input = path.resolve(tempDir, 'common.css');
|
|
220
|
+
var output = path.resolve(distDir, 'common.css');
|
|
221
|
+
postcssCompile(input, output, tailwindContent);
|
|
222
|
+
}
|
|
200
223
|
}
|
|
224
|
+
} catch (e) {
|
|
225
|
+
console.log(e);
|
|
201
226
|
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
console.log('[' + presetName + '] 监听已启动: scss=' + scssDir + ', content=' + (contentDir || '未设置'));
|
|
230
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compile-css",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A CSS compilation tool that supports SCSS, PostCSS, and TailwindCSS",
|
|
5
5
|
"main": "compileCss.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
"url": "https://gitee.com/coder_home/compile-css/issues"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"compileCss": "node compileCss.js"
|
|
28
|
+
"compileCss": "node compileCss.js",
|
|
29
|
+
"publish-major": "npm version major && git push --follow-tags && npm publish --registry=https://registry.npmjs.org/",
|
|
30
|
+
"publish-minor": "npm version minor && git push --follow-tags && npm publish --registry=https://registry.npmjs.org/",
|
|
31
|
+
"publish-patch": "npm version patch && git push --follow-tags && npm publish --registry=https://registry.npmjs.org/"
|
|
29
32
|
},
|
|
30
33
|
"dependencies": {
|
|
31
34
|
"chokidar": "^4.0.3",
|
|
@@ -48,4 +51,4 @@
|
|
|
48
51
|
"devDependencies": {
|
|
49
52
|
"requirejs": "^2.3.8"
|
|
50
53
|
}
|
|
51
|
-
}
|
|
54
|
+
}
|