sass之gulp自动化构建,在原生小程序中使用sass语法
由于我的英文不好,所以在写css的时候,通常会因为class类名而烦恼,当页面变得复杂的时候,会被页面杂乱无章、毫无规范的css影响开发体验,这是我选择sass来编写原生小程序样式最主要的原因(主要是less忘光了,sass还记得一点)。
gulp扫盲:gulp.js - 基于流(stream)的自动化构建工具。
下面开始做一些环境准备:
全局安装gulp:
npm i gulp -g
在项目目录中安装项目的gulp:
npm i -y
npm i gulp
gulp会分全局和项目内(或者叫本地)两个,全局安装是安装gulp的命令,项目中进行安装是提供gulp对象、在gulpfile.js中引入gulp。安装两次gulp是node的机制问题,本地require不到全局的包。
在项目中安装sass编译相关的插件依赖:
npm i node-sass gulp-rename gulp-sass gulp-changed
如果node-sass安装失败的时候,请把npm的镜像更改为淘宝的镜像,因为npm默认会使用国外的镜像进行依赖安装,由于某些不可描述的因素,改成淘宝镜像可以避免安装时不必要的报错。
如果你是通过nvm安装node的,先找到nvm目录,然后找到nvm目录下面的setting.txt文件,加入这两行:
node_mirror: https://npm.taobao.org/mirrors/node/
npm_mirror: https://npm.taobao.org/mirrors/npm/
不了解nvm的可以翻一下前两篇文章,有介绍相关操作步骤。
在你小程序项目的根目录下(app.js同级)新建一个gulpfile.js文件,这个命名不可更改,是gulp构建时自动执行的任务文件,下面先附上完整的gulpfile.js内容,可以直接用于开发,无需任何修改(前提是依赖已经安装完毕,包括chalk这个包):
const gulp = require('gulp');
const sass = require('gulp-sass');
const rename = require('gulp-rename');
const changed = require('gulp-changed');
//这个只是为了输出的时候带上一些明显的颜色,非必要
const chalk = require('chalk');
const log = console.log;
//自动编译
gulp.task('auto', gulp.series(function() {
return miniSass(); // 注意,这里有个return,为何?下面解释
}));
//手动编译
gulp.task('sass', function(){
let date1 = new Date().getTime();
miniSass(date1);
});
// 执行自动编译
gulp.task('watch', function(){
gulp.watch('./pages/**/*.scss',gulp.series('auto'));// gulp 4.x写法
});
// 编译
function miniSass(date1){
return gulp.src('./pages/**/*.scss')//需要编译的文件
.pipe(sass({
outputStyle: 'expanded'//展开输出方式 expanded
}))
.pipe(rename((path)=> {
path.extname = '.wxss'
}))
.pipe(changed('./pages'))//只编译改动的文件
.pipe(gulp.dest('./pages'))//编译
.pipe(rename((path)=> {
//下面这段只是为了唉控制台输出一些东西,非必要
let date2 = new Date().getTime();
if(date1){
log(chalk.yellow('[' +new Date().getHours() + ':' + new Date().getMinutes() + ':' + new Date().getSeconds()+ ']')+ ' 编译完成文件:' + 'pages\\' + path.dirname + '\\' + path.basename + '.scss' + ','+chalk.green('耗时:'+(date2 - date1)/1000 + 's'))
}else{
log(chalk.yellow('编译完成文件:' + 'pages\\' + path.dirname + '\\' + path.basename + '.scss'))
}
}))
}
使用的时候,只需要在wxml所在的目录创建一个同名的scss文件即可,这个可以与wxss共存,比如你有一个项目已经进入开发了的,想中途引入sass,行不行呢?那是裤裆里着火 -- 当然啦。按照上面的做法,已经做好的页面不会受到scss的影响,因为上面的代码只是监听scss文件的变动,当你目录中不存在scss文件,wxss就自然不会受到影响。
编译命令有两个,一个是手动编译:gulp sass;一个是自动编译:gulp watch。手动编译的话控制台的输出会干净很多,自动编译会打印很多无用的东西(但可以即时编译,无需再手动执行编译命令),可以根据实际来取舍。
如何定义一些全局的scss变量?一般是在app.js同级目录下新建一个scss文件,以“_”开头(比如:_base.scss),把一些全局的样式放在这个文件中,在需要使用的地方,通过import引入即可,例如:
// _base.scss
$fs:20rpx;
//index.scss
@import './base.scss';
.title{
font-size:$fs;
}
细心的gay会发现,命名的时候有下划线,为什么导入的时候不需要呢?
这是gulp插件做了一层定义,当你以下划线开头的,会不进行编译,但导入的时候不需要写下划线。
当你在scss文件中写了不存在的(未定义的)样式变量的时候,控制台会提醒你的,如上图。图中的son.wxss是gulp构建生成的。
到这里,在原生小程序中使用sass基本已经没有什么障碍了,在提交代码到小程序后台的时候,scss文件是不会被提交的,所以不用担心引入sass后会被scss文件占用了包的空间大小。最后,在这里解释一下,上面那个gulpfile.js文件中,自动编译任务里面为何要写个return,而手动编译却不用:
因为gulp使用了node的异步完成(Async Completion),需要一个任务完成信号(Signal task completion)去通知gulp,然后gulp去决定是继续后续任务(task),还是结束。当你不写return的时候,去执行watch监听,只会进行第一次编译,后面的所有改动将不再进行编译,因为你没有使用任何模式或者方式去通知gulp任务已经完成了,所以gulp不会再执行。
解决办法很简单:因为我们创建的gulp任务使用的是node的streams模式,返回此任务(task)的stream即是一种通知,所以我们只需要 return 就解决了。
注意:当你在项目使用scss文件的时候,会自动编译出一个同名的wxss文件,千万不要尝试在编译出来的wxss进行样式的编写,否则当你改动scss文件的时候,会清除未在scss文件中存在的所有样式。