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 CHANGED
@@ -1,71 +1,100 @@
1
- # CSS Compile Tool
1
+ # CSS 编译工具
2
2
 
3
- A powerful CSS compilation tool that supports SCSS, PostCSS, and TailwindCSS with file watching capabilities.
3
+ 支持 SCSSPostCSSTailwindCSS CSS 编译工具,自带文件监听功能。
4
4
 
5
- ## Installation
5
+ ## 安装
6
6
 
7
7
  ```bash
8
8
  npm install -g compile-css
9
- # or
9
+ #
10
10
  npm install --save-dev compile-css
11
11
  ```
12
12
 
13
- ## Usage
13
+ ## 使用方法
14
14
 
15
- ### Command Line
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
- ### Programmatic Usage
29
-
30
- ```javascript
31
- const compileCss = require('compile-css');
32
-
33
- // Use default config
34
- compileCss();
21
+ 工具会自动读取根目录下的 `compileCssConfig.js` 配置文件,启动文件监听并开始编译。
35
22
 
36
- // With custom options
37
- compileCss({
38
- watch: true,
39
- config: './custom-config.js'
40
- });
41
- ```
23
+ ## 配置说明
42
24
 
43
- ## Configuration
25
+ 在项目根目录创建 `compileCssConfig.js` 文件。
44
26
 
45
- Create a `compileCssConfig.js` file:
27
+ ### 配置示例
46
28
 
47
29
  ```javascript
48
30
  const path = require('path');
49
31
 
50
32
  module.exports = {
51
- paths: {
52
- scss: path.resolve('./scss'),
53
- template: path.resolve('./html'),
54
- temp: path.resolve('./temp'),
55
- dist: path.resolve('./html', 'css')
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
- ## Features
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
- - SCSS compilation
63
- - ✅ PostCSS processing
64
- - TailwindCSS integration
65
- - File watching
66
- - Auto-prefixing
67
- - CSS optimization
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
- ## License
91
+ 1. SCSS 文件变化 → `sass` 编译到 `temp` 目录
92
+ 2. `temp` 目录 CSS 文件变化 → PostCSS(tailwindcss + autoprefixer + cssnano)编译到 `dist` 目录
93
+ 3. `content` 目录文件变化 → 重新编译 `common.css`,更新 TailwindCSS 工具类
70
94
 
71
- MIT
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
- paths: {
27
- scss: path.resolve('./scss'),
28
- template: path.resolve('./html'),
29
- temp: path.resolve('./temp'),
30
- dist: path.resolve('./html', 'css')
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 = tcontent;
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
- let paths = [
143
- path.resolve(template),
144
- path.resolve(scss),
145
- path.resolve(temp),
146
- ];
147
- var watcher = chokidar.watch(paths, {
148
- ignored: [
149
- // watchRootPath+'/ThinkPHP',
150
- ],
151
- persistent: true,
152
- // followSymlinks:false
153
- })
154
- .on('all', (eventName, pathfile, stats) => {
155
- try {
156
- console.log(eventName, pathfile)
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
- if (pathfile.endsWith('.css')) {
181
- let output = '';
182
- //输出的目录结构应该保持和scss目录结构 或者 temp目录结构一致
183
- //如果是来源时scssDir目录结构,那么输出的目录结构应该是 distDir 目录结构
184
- let tcontent = [];
185
- tcontent = [path.resolve(template, '**/*.{html,htm}')];
186
-
187
- output = pathfile.replace(temp, dist);
188
- postcssCompile(pathfile, output, tcontent)
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
- if (pathfile.endsWith('.html')) {
193
- let tcontent;
194
- let input = '';
195
- let output = '';
196
- tcontent = [path.resolve(template, '**/*.{html,htm}')];
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
- } catch (e) {
203
- console.log(e)
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": "1.0.0",
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
+ }
@@ -1,10 +0,0 @@
1
- const path = require('path');
2
-
3
- module.exports = {
4
- paths: {
5
- scss: path.resolve('./scss'),
6
- template: path.resolve('./html'),
7
- temp: path.resolve('./temp'),
8
- dist: path.resolve('./html', 'css')
9
- }
10
- };