• 使用gulp构建微信小程序工作流


    前言

    刚入门微信小程序的时候,一切都基于微信web开发者工具,没有使用其他框架,也没有工程化的概念。当时做的项目都比较简单,单单用微信web开发者工具倒也得心应手。学了些东西后,就按捺不住地想跳出原生工具的条条框框,把近些日子学的东西都拿出来熬一熬。

    已有的一个小程序项目使用了github上一个使用webpack、babel、sass开发的小程序脚手架(wxapp-boilerplate),我需要在不变动原有项目代码的基础上,使用gulp来重构项目的工作流。

    使用体验:使用vscode配合各种插件在src目录下开发,使用微信web开发者工具预览调试,通过cmd打开服务,可以用gulp命令快速创建page、component模板。还是很nice的。

    介绍

    根据开发中的刚需和痛点,最终做了以下工作,有实现不到位的,欢迎大家提出建议。

    sass编译成wxss,同时处理了@import直接导入导致单文件过大的问题
    修改gulpfile.js的aliasWords可为项目js配置alias
    支持在src中的wxs使用es6+
    使用微信web开发者工具的Npm构建
    gulp命令快速创建page、component模板

    项目地址:https://github.com/bluehat999/weapp-gulp

    文章地址:https://www.cnblogs.com/mthz/p/weapp-gulp.html

    要点

    实现过程中遇到的问题,也是一些要点:

    1.项目中的WXS文件使用了ES6语法,而WXS原生不支持ES6

    wxs不支持ES6 语法,其标准基本是参考ES5 标准.
    解决方案是使用babel将wxs像js那样从ES6转为ES5,在使用babel的时候,有个模块始终无法加载到,查出问题应该是babel的依赖间版本不一致的问题,就在github上查了gulp-babel的仓库,参照readme.md的示例重新安装模块和使用,就成功解决。

    安装:

      npm install --save-dev gulp-babel @babel/core @babel/preset-env
    

    使用:

      const f_wxs = done => {
          return gulp.src(WXS, { since: gulp.lastRun(f_wxs) })
              .pipe(plumber({ errorHandler: onError }))
              .pipe(babel({
      			presets: ['@babel/preset-env']
              }))
              .pipe(rename({extname:'.wxs'}))
              .pipe(gulp.dest(DIST))
      }
      gulp.task('wxs', f_wxs)
    
    2.sass编译成wxss,解决@import导致文件体积过大的问题

    css不支持import语法,sass在处理@import时会直接把对应文件添加过来,从而导致wxss文件体积过大。

    而wxss支持import语法,同时限制了单包代码不超过2M,所以需要采用方法避免sass编译时直接导入样式,而是沿用@import。简单来说,就是让sass编译时不处理import语句。

    可以改sass的源码,让它跳过import,也可以在交给sass编译前将文件中的import语句注释掉,编译结束后再取消注释。

    但是不处理import语句也会带来一个问题:文件中使用了引入文件中的变量和mixin时,会由于没有引入而找不到变量和mixin。我们需要再给不处理import语句加一个判断条件。

    一般项目都会将全局的(需要被引用的)变量和mixin放在单独的文件里,而且会适当分成多个,以免单个文件过大。将这些文件放在指定的目录里,将目录路径作为判断条件来过滤掉需要import的变量和mixin的sass文件。

    const SRC = './src/**/'
    const SASS = [`${SRC}*.{scss,wxss,scss}`]
    const DIRECTIMPORT = [`styles`, `font`]
    
    const f_sass = done => {
        return gulp.src([...SASS,...DIRECTIMPORT.map(item => `!${SRC}${item}/**/*`)], 
                        { since: gulp.lastRun(f_sass) ,allowEmpty:true})
            .pipe(plumber({ errorHandler: onError }))
            .pipe(tap((file) => {
                const filePath = path.dirname(file.path);
                file.contents = new Buffer(
                    String(file.contents)
                    .replace(/@imports+['|"](.+)['|"];/g, ($1, $2) => {
                        const imPath = path.resolve(filePath + '/' + $2)    
                        return DIRECTIMPORT.some( item => { return imPath.indexOf(item) > -1} ) ? $1 : `/** ${$1} **/`
                })
                )
            }))
            .pipe(sass())
            .pipe(replace(/(/**s{0,})(@.+)(s{0,}**/)/g, ($1, $2, $3) => $3.replace(/.scss/g, '.wxss')))
            .pipe(rename({ extname: '.wxss' }))
            .pipe(gulp.dest(DIST))
    }
    gulp.task('sass', f_sass)
    
    3.微信小程序使用npm

    小程序基础库2.2.1以上的版本开始支持npm安装第三方包。官方文档

    仔细读了文档,和它的示例代码,不过还是被坑了一会。

    node_modules必须放在小程序根目录或其子目录下,npm的package.json也是,否则在微信web开发者工具对dist进行npm构建时会提示找不到npm。

    它的npm构建会在代码同级目录生成source map文件,方便做逆向调试。

    不过npm的命令是需要在dist目录的上一级使用的,如果直接放在dist里,上一级就用不了,本来理想的方案是放在dist、修改npm寻找node_modules文件的地点,或者放在上一级、修改开发者工具构建时寻找node_modules文件的地点。

    但是我实在没查到如何修改,也许看源码可以,所以采用了比较麻烦的方案。就是node_modules放在上一级,写一个gulp task将它整体复制到dist。node_modules毕竟挺大的,复制一份要用去10几秒,开销挺大,不过也只有node_modules更新了需要同步一下,总的来说也还好。

    4.使用gulp-tap获取处理的文件名时并计算一个相对路径

    原有项目使用了webpack来管理文件依赖,改用gulp的话,原有的一些依赖路径就是错误的,(比如引用config和utils目录下的文件时),如果直接修改代码,会和项目原有的编程习惯冲突,所以决定直接在gulp构建时来把错误的路径改为正确的相对路径。

    5.微信小程序中使用lodash报错
    Uncaught TypeError: Cannot read property 'prototype' of undefined
    

    找到一篇解释的很好的文章

    按照文章中给出的方案,在开发者工具中构建Npm后,可使用gulp lodash自动修改相应文件来修复这个问题。

    6.微信小程序不支持async / await 语法

    因为小程序支持ES6转ES5,我就没有在gulp中使用babel,没考虑到小程序对ES6以上的特性不支持。

    小程序报了上诉错误,我首先查了一下regeneratorRuntime is not defined的错误,大致得知是异步的错误,找到报错的代码,发现使用了async await,猜测是微信小程序不支持,需要引入相应的包,然后google到了比较好的答案。

    facebook代码仓库下载到了相应源码(只需要runtime.js就可以了),放入utils中,在使用了async的地方引入。不过我又遇到了下面的问题:

    源码中报错部位在catch中,文件中既没有引入也没有定义这个Function,在网上也找不到答案,考虑在catch中,应该是处理报错之类的,注释掉也影响不大,我就把它注释掉了。

    更多改进

    改进一定会有的,如果觉得还行或者不行,劳烦关注一下我的博客和github。

    项目地址:https://github.com/bluehat999/weapp-gulp

    文章地址:https://www.cnblogs.com/mthz/p/weapp-gulp.html

  • 相关阅读:
    AdminLTE 3.0发布了
    .NET Core ORM 类库Petapoco中对分页Page添加Order By对查询的影响
    【译】ASP.NET Core在 .NET Core 3.1 Preview 1中的更新
    物品编码中心所说的包装指示符
    Entity Framework Core生成的存储过程在MySQL中需要进行处理及PMC中的常用命令
    Asp.Net Core Mvc Razor之RazorPage
    基于Asp.Net Core MVC和AdminLTE的响应式管理后台之侧边栏处理
    Qt的下载地址
    由于MicrosoftVisualStudio14.0DesignerShadowCache导致的一个异常问题
    Spring系列.事务管理原理简析
  • 原文地址:https://www.cnblogs.com/mthz/p/weapp-gulp.html
Copyright © 2020-2023  润新知