将CSScomb集成到微信小程序项目中

简介: 将CSScomb集成到微信小程序项目中

前言


最近在看 AlloyTeam 团队的 Code Guide 代码书写习惯,其中一项是 CSS 属性编写顺序


虽然 CSS 属性顺序先后并不影响我们的程序,那为什么要做这件事呢?我理解是可分类、有迹可循、有利于排查错误。


由于属性众多,那么人总是会犯错的,所以我们借助一个工具来处理,它就是 CSScomb,用于 CSS 格式化、且可排序。官方描述是:CSScomb is a coding style formatter for CSS.


本文旨在使得 CSScomb 支持格式化小程序样式 .wxss同时也支持支付宝小程序 .acss,而百度小程序样式文件的扩展名是 .css,所以它天生就可以直接使用了。


正文


一、CSScomb 安装使用


创建一个微信小程序项目,因过于简单,忽略该步骤。


1. 本地安装

$ yarn add csscomb --dev


2. 添加配置文件


在项目根目录下,添加配置文件 .csscomb.json

若无配置文件,CSScomb 的默认配置请看 csscomb.js/config/csscomb.json

而本文均采用 AlloyTeam 推荐的排序规则,而非默认。但由于 sort-order 很长,影响文章篇幅,部分配置没贴上去,完整配置请看看  csscomb-mini/.csscomb.json


关于该配置文件是按我平常编写代码的习惯调整有所调整的,并非 CSScomb 默认配置。具体配置项所指可细看  CSScomb Configuration Options。注意 CSScomb 所能做的事情并非就只有属性排序哦,比如设置缩进、颜色值十六进制大小写、前导零也是可以的。

{
  "exclude": [".git/**", "node_modules/**", "bower_components/**"],
  "verbose": true,
  "always-semicolon": true,
  "block-indent": 2,
  "color-case": "lower",
  "color-shorthand": true,
  "element-case": "lower",
  "eof-newline": true,
  "leading-zero": false,
  "quotes": "single",
  "remove-empty-rulesets": false,
  "space-before-colon": 0,
  "space-after-colon": 1,
  "space-before-combinator": 1,
  "space-after-combinator": 1,
  "space-before-opening-brace": 1,
  "space-after-opening-brace": "\n",
  "space-before-closing-brace": "\n",
  "space-before-selector-delimiter": 0,
  "space-after-selector-delimiter": "\n",
  "space-between-declarations": "\n ",
  "strip-spaces": true,
  "unitless-zero": true,
  "vendor-prefix-align": false,
  "sort-order": []
}


3. 添加 NPM 脚本


为了测试效果,根目录下创建一个 app.css 文件。

{
  "scripts": {
    "csscomb": "csscomb app.css"
  }
}


4. 运行脚本

$ yarn run csscomb
✓ app.css
  Done in 0.45s.


5. 效果


按以上配置文件的排序规则,padding-right 属性在 padding-left 之前,所以可以看到修改前后的对比如下:

/* before */
view {
  padding-left: 30px;
  padding-right: 30px;
}
/* after */
view {
  padding-right: 30rpx;
  padding-left: 30rpx;
}


二、微信小程序如何使用 csscomb


由于 CSScomb 仅支持扩展名为 .css.sass.scss.less 的文件,那么怎么处理呢?


只能利用 Gulp 来曲线救国了。

大致思路,利用 Gulp 将 WXSS 文件临时转为 CSS 扩展名,使用 CSScomb 格式化之后,再将其转换回 WXSS 的扩展名,以达到曲线救国的目的。


插了一下,恰巧有一款 Gulp 插件 gulp-csscomb 可用,话不多说。


1. 安装相关依赖包

$ yarn add --dev gulp gulp-debug gulp-csscomb gulp-rename


2. 创建 Gulp 任务


在项目根目录下创建 gulpfile.js 文件。而 gulp-csscomb 的使用方法很简单,于是我们很快可以写出:

const { src, dest } = require('gulp')
const rename = require('gulp-rename')
const debug = require('gulp-debug')
const csscomb = require('gulp-csscomb')
const wxssTask = cb => {
  return src('app.wxss')
    .pipe(debug()) // 打印一些调试信息
    .pipe(
      rename({
        extname: '.css'
      })
    )
    .pipe(csscomb()) // 格式化操作
    .pipe(
      rename({
        extname: '.wxss'
      })
    )
    .pipe(dest(file => file.base))
}
module.exports = {
  wxssTask
}


修改 NPM 脚本:

{
  "scripts": {
    "csscomb": "gulp wxssTask"
  }
}


执行脚本 yarn run csscomb 可以看到:

$ yarn run csscomb
yarn run v1.22.4
$ gulp wxssformat
[15:34:11] Using gulpfile ~/Desktop/Web/MyGitHub/csscomb-mini/gulpfile.js
[15:34:11] Starting 'wxssformat'...
[15:34:11] gulp-debug: app.wxss
Failed to configure "remove-empty-rulesets" option:
 Value must be one of the following: true.
Failed to configure "vendor-prefix-align" option:
 Value must be one of the following: true.
[15:34:11] gulp-debug: 1 item
[15:34:11] Finished 'wxssformat' after 98 ms
  Done in 1.05s.


此时 app.wxss 文件已经被格式化了,但很遗憾我们看到两行 Failed 信息:

Failed to configure "remove-empty-rulesets" option:
 Value must be one of the following: true.
Failed to configure "vendor-prefix-align" option:
 Value must be one of the following: true.


它不支持 remove-empty-rulesetsvendor-prefix-align 配置选项,估计是 gulp-csscomb “年久失修”了。当前安装 csscomb 是最新版本 4.3.0(本文编写时),而 gulp-csscomb 里面引用的 csscomb 版本还是 3.1.7,猜测是旧版本不支持该选项。

# 查看依赖包版本
$ npm view <package> versions


再次曲线救国一下,干脆自己实现一个 csscomb-gulp 插件的功能。


三、编写 Gulp 插件


顺便学习一下,如何写一个 Gulp 插件哦。


第一次写的同学,可简单看下这篇文章:Gulp 插件编写入门


我看了 gulp-csscombCSScomb Core 的源码,发现自己实现一个插件不难,同时还发现可以少一步 wxsscss 来回切换的转换过程。


首先是 gulp-csscomb 的源码(gulp-csscomb),截取了一部分下来:

// 部分源码
var comb = new Comb(config || 'csscomb'); // 根据配置实例化对象
var syntax = options.syntax || file.path.split('.').pop(); // 获取 syntax,从参数或者扩展名获取,即 css、less、sass、scss
try {
  var output = comb.processString( // 关键就是这步,对我们的文件进行格式化
    file.contents.toString('utf8'), {
      syntax: syntax,
      filename: file.path
    });
  file.contents = new Buffer(output); // 将格式化后的字符串替换回文件中
} catch (err) {
  this.emit('error', new PluginError(PLUGIN_NAME, file.path + '\n' + err));
}


从以上源码可以看到,关键在于 comb.processString() 方法。于是找到 CSScomb 的核心源码(CSScomb Core),该方法的描述如下:

comb.processString(string, options)
Params:
  {String} Code to process
  {{context: String, filename: String, syntax: String}} Options (optional) where context is Gonzales PE rule, filename is a file's name that is used to display errors and syntax is syntax name with css being a default value.
Return: {Promise} Resolves with processed string.


syntax is syntax name with css being a default value.


所以只要在调用 comb.processString() 方法时,对微信小程序的样式文件,传值为 {syntax: 'css'} 即可。


上代码,框架大致是这样:


先安装必要依赖

$ yarn add --dev gulp-csscomb through2

// gulpfile.js
const { src, dest } = require('gulp')
const rename = require('gulp-rename')
const debug = require('gulp-debug')
const csscomb = require('gulp-csscomb')
const through = require('through2')
// csscomb 插件
const csscombPlugin = () => {
  return through.obj(function (file, enc, cb) {
    // 暂时什么都没做...
    return cb()
  })
}
// Gulp 任务
const csscombTask = cb => {
  try {
    return src('app.wxss')
      .pipe(debug())
      .pipe(csscombPlugin())
      .pipe(dest(file => file.base))
  } catch (e) {
    console.warn(e)
  }
}
module.exports = {
  csscombTask
}


创建新脚本,并运行 yarn run csscomb:mini

{
  "scripts": {
    "csscomb:mini": "gulp csscombTask"
  }
}


看样子是可以正常跑起来的,接下来就实现 csscomb 转化过程。

frankie@iMac csscomb-mini %  yarn run csscomb:mini
yarn run v1.22.10
$ gulp csscombTask
[20:29:25] Using gulpfile ~/Desktop/Web/Git/csscomb-mini/gulpfile.js
[20:29:25] Starting 'csscombTask'...
[20:29:25] gulp-debug: app.wxss
[20:29:25] gulp-debug: 1 item
[20:29:25] Finished 'csscombTask' after 14 ms
  Done in 0.51s.


如对 Gulpthrough2 不了解,可去官网了解一下。through2 是快速创建一个 transform stream 的工具函数。


编写 csscombPlugin 实现


安装必要依赖


$ yarn add --dev plugin-error

const fs = require('fs')
const path = require('path')
const { src, dest } = require('gulp')
const rename = require('gulp-rename')
const debug = require('gulp-debug')
const Comb = require('csscomb')
const csscomb = require('gulp-csscomb')
const through = require('through2')
const PluginError = require('plugin-error') // 用于处理异常
// csscomb 插件
const csscombPlugin = () => {
  // 默认支持扩类型
  const defaultExts = ['.css', '.sass', '.scss', '.less']
  // 扩展类型,假设以后兼容字节跳动小程序,可加上 .ttss
  const expandExts = ['.wxss', '.acss']
  const supportExts = defaultExts.concat(expandExts)
  return through.obj(async function (file, enc, cb) {
    let syntax = 'css'
    const filePath = file.path
    const extname = path.extname(filePath)
    // 获取 csscomb 配置
    const combConfigPath = Comb.getCustomConfigPath(path.resolve(__dirname, '.csscomb.json'))
    const combConfig = Comb.getCustomConfig(combConfigPath)
    if (file.isNull()) {
      // 文件为空不做处理,直接返回进入下一个 pipe()
      return cb()
    } else if (file.isStream()) {
      // 不支持对流(Stream)进行操作,抛出异常
      this.emit('error', new PluginError('csscombPlugin', 'Streams are not supported!'))
      return cb()
    } else if (file.isBuffer() && supportExts.includes(extname)) {
      // 默认支持类型,通过扩展名获取。其余当做 css
      if (defaultExts.includes(extname)) {
        syntax = extname.split('.').pop()
      }
      // 找不到配置文件
      if (combConfigPath && !fs.existsSync(combConfigPath)) {
        this.emit('error', new PluginError('csscombPlugin', 'Configuration file not found: ' + configPath))
        return cb()
      }
      try {
        // 实例化
        const comb = new Comb(combConfig)
        // 对所要转换的文件进行格式化
        const output = await comb.processString(
          file.contents.toString('utf8'),
          {
            syntax,
            filename: filePath
          }
        )
        // 创建 Buffer,并将格式化后的字符串替换原本的 contents
        file.contents = Buffer.from(output, 'utf-8')
        this.push(file)
        return cb()
      } catch (e) {
        this.emit('error', new PluginError('csscombPlugin', filePath + '\n' + e))
      }
    } else {
      // 其余情况,直接返回。例如 file 为 JS 文件等
      return cb()
    }
  })
}
// Gulp 任务
const csscombTask = cb => {
  try {
    return src('app.wxss')
      .pipe(debug())
      .pipe(csscombPlugin())
      .pipe(dest(file => file.base))
  } catch (e) {
    console.warn(e)
  }
}
module.exports = {
  csscombTask
}


我们再次运行脚本 yarn run csscomb:mini,可以看到 app.wxss 文件的变化:

/* before */
.container {
  height: 100%;
  padding: 200rpx 0;
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: space-between;
  box-sizing: border-box;
}
/* after */
.container {
  display: flex;
  box-sizing: border-box;
  padding: 200rpx 0;
  height: 100%;
  align-items: center;
  flex-direction: column;
  justify-content: space-between;
}


至此,我们的工作完成了 90%... 还可以继续优化。

你注意到我们 csscombTask 方法里面是针对一个相对固定的路径或者文件了吗?假设我每次格式化其他目录的文件,都需要修改此方法,显然是不合理的。


我们可在 NPM 脚本进行传参,然后通过 process.argv 来获取,我们处理下再传入 gulp.src() 方法即可。


四、优化


先约定好传参规则:


  • --path 表示符合 glob 文件匹配模式的路径,多个路径是用 , 隔开,并用单引号 ' 括起来,还有我限制了仅支持项目下的文件。
  • --ext 表示扩展名,如 .css.wxss 等。(此选项目前没什么用,保留下来后续优化用)


若对 Glob 模式不了解,可看 Glob 详解。其中 gulp.src(globs[, options]) 第一个参数就是这种模式的。


{
  "scripts": {
    "csscomb:mini": "gulp csscombTask --path '<filepath>' --ext <extension>"
  }
}


我们借助 minimist 来获取 NPM 参数,通过

安装必要依赖,

$ yarn add --dev minimist

// gulp.js
// 这里省略其他部分,仅修改了 csscombTask 方法
const minimist = require('minimist')
// Gulp 任务
const csscombTask = cb => {
  try {
    // 获取参数,如 { _: [ 'csscomb:mini' ], path: 'xxx', ext: 'xxx' }
    const options = minimist(process.argv.slice(2))
    // 过滤掉非项目下的路径
    const paths = options.path.split(',').filter(item => {
      const re1 = /^\//
      const re2 = /^\.\.\//
      return item && !re2.test(item) && (!re1.test(item) || (re1.test(item) && item.includes(__dirname)))
    })
    // 去重
    const newPaths = Array.from(new Set(paths))
    if (!newPaths.length) {
      return cb()
    }
    // allowEmpty 选项是为了避免在没有找到匹配的文件时抛出错误
    // Error: File not found with singular glob: xxx (if this was purposeful, use `allowEmpty` option)
    return src(newPaths, { allowEmpty: true })
      .pipe(debug())
      .pipe(csscombPlugin())
      .pipe(dest(file => file.base))
  } catch (e) {
    console.warn(e)
  }
}


修改 NPM 脚本,并创建一个支付宝小程序的样式文件 app.acss 测试一下:

{
  "scripts": {
    "csscomb:mini": "gulp csscombTask --path './**/*.wxss,app.acss'"
  }
}


运行脚本,发现可以一键格式化了,至此基本完成了。


五、GitHub


项目放在 GitHub 上  csscomb-mini 欢迎 Star 。


六、参考


目录
相关文章
|
26天前
|
存储 JavaScript 数据库
ToB项目身份认证AD集成(一):基于目录的用户管理、LDAP和Active Directory简述
本文介绍了基于目录的用户管理及其在企业中的应用,重点解析了LDAP协议和Active Directory服务的概念、关系及差异。通过具体的账号密码认证时序图,展示了利用LDAP协议与AD域进行用户认证的过程。总结了目录服务在现代网络环境中的重要性,并预告了后续的深入文章。
|
26天前
|
人工智能 JavaScript 网络安全
ToB项目身份认证AD集成(三完):利用ldap.js实现与windows AD对接实现用户搜索、认证、密码修改等功能 - 以及针对中文转义问题的补丁方法
本文详细介绍了如何使用 `ldapjs` 库在 Node.js 中实现与 Windows AD 的交互,包括用户搜索、身份验证、密码修改和重置等功能。通过创建 `LdapService` 类,提供了与 AD 服务器通信的完整解决方案,同时解决了中文字段在 LDAP 操作中被转义的问题。
|
28天前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
186 3
|
1月前
|
XML 小程序 JavaScript
小程序入门之项目配置说明和数据绑定
小程序入门之项目配置说明和数据绑定
38 1
|
1月前
|
jenkins Shell 持续交付
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(二)
67 0
|
26天前
|
安全 Java 测试技术
ToB项目身份认证AD集成(二):快速搞定window server 2003部署AD域服务并支持ssl
本文详细介绍了如何搭建本地AD域控测试环境,包括安装AD域服务、测试LDAP接口及配置LDAPS的过程。通过运行自签名证书生成脚本和手动部署证书,实现安全的SSL连接,适用于ToB项目的身份认证集成。文中还提供了相关系列文章链接,便于读者深入了解AD和LDAP的基础知识。
|
1月前
|
缓存 开发框架 移动开发
uni-app:下载使用uni&创建项目&和小程序链接&数据缓存&小程序打包 (一)
uni-app 是一个跨平台的开发框架,它允许开发者使用 Vue.js 来构建应用程序,并能够同时发布到多个平台,如微信小程序、支付宝小程序、H5、App(通过DCloud的打包服务)等。uni-app 的目标是通过统一的代码库,简化多平台开发过程,提高开发效率。 在这一部分中,我们将逐步介绍如何下载和使用uni-app、创建一个新的项目、如何将项目链接到小程序,以及实现数据缓存的基本方法。
|
3月前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
104 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
1月前
|
Java Shell 开发工具
git集成IDEA,托管项目实现版本管理
git集成IDEA,托管项目实现版本管理
31 0
|
1月前
|
jenkins Shell 持续交付
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(一)
Jenkins持续集成GitLab项目 GitLab提交分支后触发Jenkis任务 持续集成 CI/CD 超级详细 超多图(一)
128 0

热门文章

最新文章