微信小程序之代码构建初探:如何继续使用html与css开发小程序

8,105 阅读5分钟

微信小程序必然会给互联网带来一场非比寻常的变革。

随处可见关于小程序的文章也让我们感受到它正在刮起一阵风暴,所以呢,抽空研究研究它,还是非常有必要的,加上最近小程序公测,通过注册未认证的小程序,我们可以得到一个appid,下载最新的开发工具,就可以开始尝试编写一些demo。

在开发小程序的时候,由于我们比较常用的编辑器对于 .wxml, .wxss 后缀的文件并没有多少支持,目前我所知道的,除了 vs code 有一个叫做 vs wxml 的插件之外,几乎没有其他插件了,因此,没有代码补全,没有 emmet 支持,没有代码高亮,这极大的影响了开发效率,我也知道有很多来尝试小程序开发的同学为此非常困扰。

好在,办法总是有的。

大家都知道大多数编辑器对于 html 与 css 的支持非常全面,特别是 emmet 插件,对于 html 和 css 来说,已经变得必不可少了。而微信的 wxml 与 wxss 其实与 html 与 css 差别并不大。因此,我们只需要在开发时,将代码写在 html 与 css 中,在保存时,通过构建工具,将文件的后缀名改成 .wxml 与 .wxss 即可。 这样一来,我们就不用在内置工具中开发,到处找对于小程序支持良好的IDE,也不用等各位大佬出新的插件了,就用我们各自最喜欢最熟悉的编辑器就可以。下面我以我最熟悉的gulp为例,与大家分享一下具体如何实现。

准备

我们知道小程序的页面都在 pages 文件夹下,首先创建一个 demo 文件夹,这里将会放置我们的新页面,并在 demo 文件夹里创建一个 dev 文件夹,用于存放 html 与 css 文件,大概的目录结构如下

// + 表示文件夹   - 表示文件
+ pages
  + demo
    + dev
      + html
        - demo.html
        - demo2.html
      + styles
        - demo.scss
        - _reset.scss
        - _libs.scss
      + scripts
        - demo.js

因为在平时开发中,常常将scss编译为css使用,因此这里我们也用scss来进行开发

编译之后,得到的结构大约如下

+ pages
  + demo
    + dev
    - demo.wxml
    - demo.wxss
    - demo.js
    - gulpfile.js

我们的目的,就是将 dev 中的 html,js,scss,通过 gulp,编译成为小程序能够支持的 wxml,js 与 wxss,在清楚了目的之后,我们就来添加 gulp 任务就行了。

首先在 gulpfile.js 中定义一个路径对象,以方便后续的使用

// 设置相关路径
var paths = {
    wxml: 'html',
    wxss: 'styles',
    js: 'scripts',
    img: 'images'
};

具体要使用那些gulp插件,大家在使用的时候根据提示安装即可,因为是根据之前的老文件修改,比较懒没有去区分具体使用了那些插件,见谅。

HTML

对于 html 的处理比较简单,只有2个操作,修改后缀名与在你希望的位置生成新的 wxml 文件

gulp.task('wxml', function() {
    var src = [paths.wxml + '/**/*.html'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(foreach(function(stream, file) {
            return stream.pipe(rename(file.relative.replace(/\.html/gi, '.wxml')));
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "transform wxml success!"
        }));
});

JS

js 就更简单了,由于开发工具自己内置了编译方式,我们只需要按照 commonJs 的方式处理自己的代码就行,不需要进行额外的处理,但是为了统一,也将开发代码放在 dev 文件中,编译时在你想要的位置重新生成即可

gulp.task('wxjs', function() {
    var src = [paths.js + '/**/*.js'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "transform wxjs success!"
        }))
});

SCSS

对于 scss 的处理工作稍微要多一点,我们的主要目的是要继续使用 scss 的语法与特性,并最终编译成 .wxss 文件

gulp.task('wxss', function() {
    var src = [paths.wxss + '/**/*!(_).scss'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(foreach(function(stream, file) {
            return stream
                .pipe(path.extname(file.relative) == '.less' ? less() : sass().on('error', sass.logError));
        }))
        .pipe(csscomb())
        .pipe(minifycss({
            aggressiveMerging: false,
            advanced: false,
            compatibility: 'ie7',
            keepBreaks: true
        }))
        .pipe(cssbeautify({
            autosemicolon: true
        }))
        .pipe(foreach(function(stream, file) {
            return stream.pipe(rename(file.relative.replace(/\.css/gi, '.wxss')));
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "browser reload for css"
        }));
});

ok,这样就大功告成了,熟悉 gulp 的同学可以动手尝试一下了,熟悉其他构建工具的同学也可以根据我提供的思路实现同样的效果。想来也是不难的。当然,这只是代码构建的一些小的尝试,当面临具体项目时,还需要更多更严谨的考虑才行。

完整代码

'use strict';

var rf = require("fs");
var path = require("path");
var through = require("through2");
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var gutil = require('gulp-util');
var less = require('gulp-less');
var minifycss = require('gulp-minify-css');
var autoprefixer = require('gulp-autoprefixer');
var csscomb = require('gulp-csscomb');
var cssbeautify = require('gulp-cssbeautify');
var rename = require('gulp-rename');
var changed = require('gulp-changed');
var header = require('gulp-header');
var footer = require('gulp-footer');
var livereload = require('gulp-livereload');
var watch = require('gulp-watch');
var imgcache = require('gulp-imgcache');
var notify = require("gulp-notify");
var foreach = require("gulp-foreach");
var sass = require("gulp-sass");
var sort = require('gulp-sort');
var replace = require('gulp-replace');

// 图像处理
var imagemin = require('gulp-imagemin');
var pngquant = require('imagemin-pngquant');
var spritesmith = require('gulp.spritesmith');

//错误捕获
var plumber = require('gulp-plumber');

// 设置相关路径
var paths = {
    wxml: 'html',
    wxss: 'styles',
    js: 'scripts',
    img: 'images'
};

gulp.task('wxml', function() {
    var src = [paths.wxml + '/**/*.html'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(foreach(function(stream, file) {
            return stream.pipe(rename(file.relative.replace(/\.html/gi, '.wxml')));
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "transform wxml success!"
        }));
});

gulp.task('wxjs', function() {
    var src = [paths.js + '/**/*.js'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "transform wxjs success!"
        }))
});

gulp.task('wxss', function() {
    var src = [paths.wxss + '/**/*!(_).scss'];
    return gulp.src(src)
        .pipe(plumber({
            errorHandler: handleError
        }))
        .pipe(foreach(function(stream, file) {
            return stream
                .pipe(path.extname(file.relative) == '.less' ? less() : sass().on('error', sass.logError));
        }))
        .pipe(csscomb())
        .pipe(minifycss({
            aggressiveMerging: false,
            advanced: false,
            compatibility: 'ie7',
            keepBreaks: true
        }))
        .pipe(cssbeautify({
            autosemicolon: true
        }))
        .pipe(foreach(function(stream, file) {
            return stream.pipe(rename(file.relative.replace(/\.css/gi, '.wxss')));
        }))
        .pipe(gulp.dest('../'))
        .pipe(notify({
            onLast: true,
            message: "browser reload for css"
        }));
});

gulp.task('watch', function() { //监听文件改变触发相应任务
    gulp.watch([paths.wxml + '/**/*.html'], ['wxml']);
    gulp.watch([paths.js + '/**/*.js'], ['wxjs']);
    gulp.watch([paths.wxss + '/**/*.scss'], ['wxss']);
});

gulp.task('default', ['watch']);

function handleError(err) {
    gutil.beep();
    gutil.log(err.toString());
    notify.onError("Error: <%= error.message %>")(err);
    this.emit('end');
}

代码会有冗余的部分没有仔细删除,忽略即可。使用时需要根据提示安装必要的插件

关于微信小程序,如果基础不错的同学,可以去积极尝试一下的,感觉官方文档写的很清晰,模块化经验比较丰富的应该会很容易上手。对于基础比较薄弱的同学保持关注也是非常必要的,抓紧时间掌握基础才是关键。

因为小程序大家都处于学习阶段,所以大家都在探索嘛,希望大家多多发文章,相互交流学习,一起进步^_^。最近我也会持续更新自己在学习中的收获与一些实践demo,欢迎关注我的公众号,一起交流。