icebreaker99
icebreaker99
  • 发布:2021-09-01 13:21
  • 更新:2021-09-01 13:21
  • 阅读:1762

增强原生小程序开发,构建 tailwind + postcss + scss 最小化工具链

分类:uni-app

前言

书接上回 tailwindcss 小程序定制化之旅

我们知道 uni-apptarojs 在最终打包成小程序运行的时候,都是使用的 webpack,所以在这 2 个框架中,我们可以使用 *-loader 轻而易举的赋予它们这方面的能力。

但是,假如我们使用的是原生开发呢?

原生开发的选项

使用微信开发工具的小伙伴们,肯定注意到,在 项目详情 -> 本地设置 中,

有上传代码时 样式自动补全,自动压缩样式, 自动压缩混淆 等等选项。

它们的本质,不过是几个插件罢了:

样式自动补全 -> autoprefixer

自动压缩样式 -> cssnano

自动压缩混淆 -> uglify-js/terser

所以我们完全可以自定义,以获得更强更自由的能力。

最小化的自定义样式工具链

1. Scss与Postcss支持

我们知道 在 webpacksass-loader, postcss-loader ,babel-loader 这类,只是编译核心们和 webpack 做粘合的胶水代码。

在不使用 webpack gulp rollup ... 这类的打包工具的情况下,我们当然可以去自定义一个最小化的样式编译工具。

首先,直接安装 dart-sass,和 postcss

yarn add -D sass postcss

安装后,可以看到 , sass 渲染函数签名

// sass函数签名  
export function render(options: Options, callback: (exception: SassException, result: Result) => void): void;  
export function renderSync(options: Options): Result;

然后我们又知道 webpackloader 选择了 compose 方式的执行方式。

函数式编程中, compose 从右到左执行, pipe 从左到右执行

于是我们知道了执行顺序,那么就可以确定 *.scss 文件,先交给 sass 处理,再交由 postcss 处理, 然后就直接打成 xxpage.wxss 这类 局部页面样式 , 又或者打成 app.wxss 作为全局样式。

那么写代码实现就是探囊取物了:

// 不考虑 preset merge的情况下  
const sass = require('sass')  
const postcss = require('postcss')  
const { plugins } = require('./postcss.config.js')  
function handleScss (path) {  
  sass.render({  
    file: path,  
    // fiber: Fiber  
  }, (err, result) => {  
    if (err) {  
      console.error(err)  
    }  
    const destPath = path.replace(/\.scss$/, '.wxss')  
    postcss(plugins).process(result.css, {  
      from: path,  
      to: destPath  
    }).then(result => {  
      fs.writeFile(destPath, result.css, () => true)  
      if (result.map) {  
        fs.writeFile(destPath + '.map', result.map.toString(), () => true)  
      }  
    })  
  })  
}

上面这段代码就是 scss -> postcss -> wxss 的转化链路

而且还可以在里面,随意的装 postcss plugin , 比如 autoprefixer , cssnano , tailwindcss 之前笔者写的 tailwindcss-miniprogram-preset 也可以无缝的嵌入这套机制中去,给原生小程序使用。

2. 文件监控

我们开发的时候,会经常去创建,修改,删除文件,这么获取到这些 timing 对文件进行重新编译呢?

fs.watchfs.watchFile 固然可以,不过更推荐的还是 chokidar

yarn add -D chokidar

chokidarREADME.md 中详细介绍了它的优势,这里不再叙述。

const watcher = chokidar.watch(`${someGlob}`, {  
  ignored: /(^|[\/\\])\../,   
  persistent: true  
})  
// EventEmitter 的写法,把监控安排的明明白白  
watcher  
  .on('add', (path,stats) => {  
    // 添加文件  
  })  
  .on('change', (path,stats) => {  
    // 修改文件  
  })  
  .on('unlink', (path,stats) => {  
    // 删除文件  
  })  
  .on('error', error => {  
    // 发生错误  
  })  
  .on('ready', () => {  
    // watch ready after add files  
  })  

通过 watcher 的持续性监控,我们可以很容易得出结论,我们需要在 *.scss 文件变动的时候,重新编译,
add,change 的时间点, 在 unlink 的时间点,也要同时 unlink 对应的 *.wxss 文件。

假如 purgecss 开启,则需要在 wxml 文件发生变更时,通知重新编译 app.scss 和文件对应的 page.scss,一般开发时不开启此工具。

3. IDE智能提示设置

前面这一套机制,搭建完成后

app.scss 里加一行 @tailwind utilities; 就可以顺利使用 tailwindcss

但是我们需要我们的编辑器根据 tailwindcss 配置,自动生成 class 的智能提示怎么做呢?

这里我们以 vscode 为例:

  1. 安装 WXML - Language Services 插件(一搜wxml下载量最多的就是了)

  2. 安装 Tailwind CSS IntelliSense 插件

接着找到 Tailwind CSS IntelliSense扩展设置

include languages,手动标记 wxml 的类型为 html

如图所示

智能提示就出来了:

智能提示

是不是非常方便,同时也能大大提升开发效率。

代码工程化方案

其实这篇文章,拆开了 webpack 的部分黑盒, 探讨了场景定制化的代码加工生产线,以期来帮助开发者提升效率。

typescript + @babel/core + rollup 这种处理js的组合也见过。

只要能提升开发者生产效率,提升开发体验,提升可维护性的工具还是值得一做的。

附录

源代码

1 关注 分享
1***@qq.com

要回复文章请先登录注册