# qss文件编译器qcsc

qml文件编译器，请参考<https://git.code.oa.com/QQMiniApp/qcc>

目标：

- 实现`qss`文件编译器`qcsc`
- 完善的测试用例支持
- 完善的性能测试
- 客观的编译性能
- 支持windows\linux\macos

## 项目如何使用qcsc

tnpm安装qcsc依赖：

```sh
tnpm install @tencent/qcsc --save
```

代码示例：

```nodejs
const QCSC = require('@tencent/qcsc').QCSC;
const compileConfig = {};
const FILES = ["./app.wxss", "./pages/index/index.wxss"]; // 需要编译的文件列表
const FILESBASE = "/user/xxx/qqMiniAppProj"; // 需要编译项目的目录
compileConfig.cmd = ["-om", "-db", "-pc", FILES.length]; // qcsc编译的cmd参数
compileConfig.FILES = FILES; // qcsc编译的FILES参数
compileConfig.FILESBASE = FILESBASE; // qcsc编译的FILESBASE参数
const qcsc = new QCSC(compileConfig);
qcsc.compile().then((map) => {
  console.log("qcsc编译完成，生成的map为: ", map);
}).catch((err) => {
  //err: {code: -1, message: "错误信息"}
  console.error("qcsc编译失败，失败失败信息: ", err.message);
});
```

## 本地开发qcsc

### 下载代码

```sh
git clone http://git.code.oa.com/QQMiniApp/qcsc.git
cd qcsc
npm install
```

### 代码提交前的自动化测试：***已经累计上百个小程序的测试样例***

样例只支持`macOs`和`windows`，不支持`linux`

1 正向用例（qcc和wcc的正常运行且运行结果必须完全一致）

```sh
npm run test
```

2 反向用例（qcc和wcc都必须运行报错，提示开发者报错信息，报错信息不要求完全一致）

```sh
npm run test:fail
```

### 代码提交前的性能测试

样例只支持`macOs`和`windows`，不支持`linux`

对`125`个小程序项目跑进行编译后统计性能：

```sh
npm run benchmark
```

对`125`个小程序项目开启`cache`参数，没个项目编译`n`次后统计性能：

```sh
npm run benchmark:cache
```

对`suit1`小程序项目开启`cache`参数和不开启`cache`参数，对比性能：

```sh
npm run benchmark:cache1Suit
```

### 发布tnpm

确保测试样例全部通过

更新`package.json`中的`version`和`versionInfo`，然后运行：

```sh
npm run tnpm:publish
```

## 关于微信的wcsc工具

微信开发者工具中的二进制编译器，用来将`wxss`文件，编译成`js`文件，

`js`文件在`jsCore`中执行后，可以得到`setCssToHead`函数，`setCssToHead`函数用来把样式挂载到页面

如何获得`wcsc`？ [下载mac版本微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)，安装后，打开`Applications`目录，找到微信开发者工具，右键`Show Package Contents`，在`Contents/Resources/package.nw/js/vender/wcsc`（该目录可能会被调整）。

### wcsc编译用法

```sh
wcsc [-lc] [-o OUTPUT] [-s <NAME OF FILE>] [-st] [-js] [-db] [-cp <CLASS PREFIX>] [-pc <FILE COUNT>] <[-sd <SOURCE DIRECTLY>] | <root_css_file..> [import_css_files..]>
-lc: need to lint the css
-sd: 'someclass { font-size: 18px }'
-s: read from stdin
-o: output destination (default stdout)
-st: print tree
-db: add debug attr
-js: js formate output
-cp: add class prefix
-pc: page wxss files count
```

## 编译参数支持

已经支持的参数如下：

### [-db]

在生成的样式中插入一些调试调试信息。

主要是插入了wxcs_originclass、wxcs_fileinfo、wxcs_style_xxx等

### [-pc]

需要编译的传入文件的数目，如果传入了多余需要编译的数目，

会按照字典排序后，去掉后面多余的文件。

### [-om] out put map directly

`wcsc`输出的是一串字符串，需要进行`split`后才能得到最终需要的`map`

`qcsc`对其进行了优化，传入该参数，可以直接得到最终需要的`map`

### [--subpackage]

如果小程序存在独立分包，需要传递该参数，同时传递独立分包的路径。

例如：

```sh
wcsc -db -pc 3 ./index.wxss ./subpackage/index.wxss ./subpackage/index1.wxss --subpackage ./subpackage/
```

### [--cache]

如果需要启用编译cache，可以开启该参数。

如果是服务器端，不建议开启该参数，因为服务器端内存缓存的作用不大，命中率不高。

根据压测结果，开启该参数至少有20%的编译耗时提升。

## 自动化测试

运行：

```sh
npm run test
```

```sh
npm run test:fail
```

测试样例地址：

<https://git.code.oa.com/QQMiniApp/qcc/tree/master/test/succSuit>
<https://git.code.oa.com/QQMiniApp/qcsc/tree/master/test/failSuit>

完善的测试样例，用例还在持续增加，以覆盖到大部分的场景。

正向用例-测试流程要点：

1. `qcsc`将完整的小程序qss源码，编译成`json`[map.qcsc.json](https://git.code.oa.com/QQMiniApp/qcsc/blob/master/test/succSuit/suit0/out/map.qcsc.json)
2. `wcsc`将完整的小程序wxss源码，编译成`json`代码[map.wcsc.json](https://git.code.oa.com/QQMiniApp/qcsc/blob/master/test/succSuit/suit0/out/map.wcsc.json)
3. 构建一个模拟浏览器的沙箱环境，提取qcsc生成的`map.qcsc.json`的所有`setCssToHead`函数然后运行，得到最终生成的所有`css`样式`qcsc.css`
4. 构建一个模拟浏览器的沙箱环境，提取wcsc生成的`map.qcsc.json`的所有`setCssToHead`函数然后运行，得到最终生成的所有`css`样式`wcsc.css`
5. 对比`qcsc.css`和`wcsc.css`是否完全一致

反向用例-测试流程要点：

测试样例均是不合法的样例

1. `qcsc`编译样例项目，报错
2. `wcsc`编译样例项目，报错
3. `qcsc`和`wcsc`是否都报错了

## 各种边缘条件的覆盖和处理

持续迭代中

## 代码目录

- `src`逻辑代码
- [`lib/postcss`](https://github.com/postcss/postcss)postcss库代码，打包在一起是为了做一个地方的修改，需要支持`import`，改动位置: <https://git.code.oa.com/QQMiniApp/qcsc/blob/master/lib/postcss/lib/parser.js#L306>，增加判断import后面的`;`
- [`lib/postcss-value-parser`](https://github.com/TrySound/postcss-value-parser)用来把css的值解析成ast树的库，这个库为什么打包起来，暂时想不起来了，以后想到再补充
- `test`测试代码目录

## 目标代码的格式

参考微信的`wcsc`工具输出

思路是一个文件导出一个函数，函数调用后获得该文件的样式内容并挂到页面上

样式是打包在一个数组上

## 更多的细节

参考`docs/qcc&qcsc.pptx`，<https://git.code.oa.com/QQMiniApp/qcc/blob/master/docs/qcc&qcsc.pptx>的`qcsc`部分
