美文网首页
基于gulp的移动端解决方案

基于gulp的移动端解决方案

作者: Erin_梦 | 来源:发表于2018-07-09 14:06 被阅读171次

    近期在梳理有关gulp工作流的过程中,写了一套简单的移动端静态页面解决方案
    该方案具体解决了以下几个问题:
    1、更改html、css、js等任意文件,实现浏览器重载,同步调试
    2、实现sass实时编译与注入
    3、实现移动端自适应与代码自动优化
    4、支持css、js选择性合并压缩
    5、支持ES6转换
    6、解决前端静态资源版本更新与缓存

    查看demo详见:github地址

    安装

    安装gulp插件

    npm install --save-dev gulp
    npm install --save-dev brower-sync
    npm install --save-dev node-sass
    npm install --save-dev gulp-sass
    npm install --save-dev gulp-postcss
    npm install --save-dev postcss-adaptive
    npm install --save-dev autoprefixer
    npm install --save-dev gulp-uglify
    npm install --save-dev gulp-concat
    npm install --save-dev gulp-clean-css
    npm install --save-dev gulp-babel
    npm install --save-dev babel-core
    npm install --save-dev babel-preset-es2015
    npm install --save-dev del
    npm install --save-dev gulp-rev
    npm install --save-dev gulp-rev-collector
    npm install --save-dev gulp-html-replace
    npm install --save-dev merge-stream
    npm install --save-dev gulp-sync
    

    实现方法

    任务一:浏览器实时调试重载

    gulp.task('browser-sync', function () {
        browserSync.init({
            files: ['**'],
            server: {
                baseDir: './',
                index: 'index.html'
            },
            port: 8080
        })
    })
    

    启动8080端口进行调试,files指定变动重载文件目录,这边我默认所有文件变动重载

    任务二:sass实时编译注入(含优化)

    gulp.task('sass', function () {
        var plugins = [
            adaptive({ remUnit: 75 }),
            autoprefixer({ browsers: ['last 1 version'] })
        ];
        return gulp.src('./scss/*.scss')
            .pipe(sass({
                sourcemaps: true
            }).on('error', sass.logError))
            .pipe(postcss(plugins))
            .pipe(gulp.dest('./css'));
    });
    

    这一步的目的是把sass文件转化成css文件。其中用到了两个辅助插件,一个是adaptive对应的postcss-adaptive,是配合淘宝团队开发的移动端适配flexible.min.js一起使用的。另一个是autoprefixer对应的autoprefixer,以实现自动补充浏览器前缀的功能,个人觉得挺实用的。

    gulp.task('sass:watch', function () {
        gulp.watch('./scss/*.scss', ['sass']);
    });
    

    通过gulp watch实时监听sass文件的变化,改动同步注入到对应的css文件

    任务一和任务二实现了文件在编译过程中的调试功能,打开命令行工具,运行gulp会执行下述代码
    gulp.task('default', gulpsync.sync(['sass', 'sass:watch', 'browser-sync']));

    任务三:文件打包
    当文件编译完毕之后进入到打包阶段。我们先梳理一下打包的几个流程:
    1.打包前先清除目标文件夹里的js和css(因为我们做了版本迭代,不重名的文件在多次打包后不会覆盖,所以需要把前一版本的文件删除)
    2.把需要打包的css,js,images,html等文件经过特殊处理后放到目标文件夹
    3.替换html中引入的文件版本号

    步骤一:清除目标文件夹内容

    gulp.task('clean:package', function () {
        del([
            './build/css/*',
            '!./build/css/*.json',
            './build/js/*',
            '!./build/js/*.json',
        ]);
    });
    

    编译后的目标文件夹我指定的是build,其中用到了del来指定删除和保留的文件。json文件是css和js生成的版本号对应的文件,这里未做删除。

    步骤二:打包文件

    gulp.task('pack', function () {
        // 打包css
        var packcss = gulp.src('./css/*.css')
            .pipe(concat('main.css'))
            .pipe(cssmin({
                advanced: false,//类型:Boolean 默认:true [是否开启高级优化(合并选择器等)]
                compatibility: 'ie7',//保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式]
                keepBreaks: true,//类型:Boolean 默认:false [是否保留换行]
                keepSpecialComments: '*'
                //保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀
            }))
            .pipe(rev())
            .pipe(gulp.dest('./build/css'))
            .pipe(rev.manifest())
            .pipe(gulp.dest('./build/css'));
    
        // 打包js
        var packjs = gulp.src(['./js/*.js', '!./js/*.min.js'])
            .pipe(babel({
                presets: ['es2015']
            }))
            .pipe(uglify())
            .pipe(rev())    //加名字MD5
            .pipe(gulp.dest('./build/js')) //保存
            .pipe(rev.manifest())
            .pipe(gulp.dest("./build/js"));
    
        // 打包minjs
        var packminjs = gulp.src('./js/*.min.js')
            .pipe(gulp.dest('./build/js'));
        // 打包html
        var packhtml = gulp.src(['*.html'])
            .pipe(gulp.dest('./build'));
        // 打包images
        var packimage = gulp.src('./images/**/*')
            .pipe(gulp.dest('./build/images'));
    
        return merge(packcss, packimage, packhtml, packjs, packminjs);
    });
    

    由于打包的文件的种类和方式比较多,因此我用了merge方法对应的merge-stream来合并任务,这样看上去会比较清晰。
    css文件的打包方式是把所有的css文件合并压缩成一个大文件并生成带有版本号的json文件,其中合并用了gulp-concat,压缩用到了gulp-clean-css,生成版本号用到了gulp-rev,具体用法可参考npm文档。
    js文件支持es6的语法,在打包过程中需先进行es6的转换,用到gulp-babel,再对每个文件分别进行压缩,这里用到了gulp-uglify,同样gulp-rev为其生成版本号文件。这里我没有按照css的打包流程来对所有js文件进行合并压缩,保留了使用的js插件库文件,翻译压缩对象仅仅为自己写的js文件,个人觉得这样更方便维护和更新。
    剩余的html,image和min.js文件则原封不动的拷贝到打包目标文件夹,等待进行后续操作。其中我并没有把image文件进行压缩,因为每次build执行压缩操作比较耗时,建议image文件统一在tinypng这个网页上一次性压缩。

    在执行完pack任务之后,在指定的目录会分别生成两个rev-manifest.json文件,分别携带了css和js文件的版本号,打开文件

    {
      "main.js": "main-e184645161.js"
    }
    

    但这并不是我们想要的效果,我们想要生成的文件名如下

    {
      "main.js": "main.js?v=e184645161"
    }
    

    因此我们需要修改几个文件来达到效果:

    打开node_modules\gulp-rev\index.js
    第135行 manifest[originalFile] = revisionedFile;
    更新为: manifest[originalFile] = originalFile + '?v=' + file.revHash;
    
    打开node_modules\rev-path\index.js
    9行 return modifyFilename(pth, (filename, ext) => `${filename}-${hash}${ext}`);
    更新为: return modifyFilename(pth, (filename, ext) => `${filename}${ext}`);
    
    打开node_modules\gulp-rev-collector\index.js
    40行的  var cleanReplacement =  path.basename(json[key]).replace(new RegExp( opts.revSuffix ), '' );
    更新为: var cleanReplacement =  path.basename(json[key]).split('?')[0];
    搜索prefixDelim,把 regexp: new RegExp( prefixDelim + pattern, 'g' ),
    更新为:  regexp: new RegExp( '([\/\\\\\'"])' + pattern+'(\\?v=\\w{10})?', 'g' ),
    

    修改完毕之后运行gulp就能达到我们想要的效果了

    步骤三:替换html中引用文件的版本号

    gulp.task('rev:js', function () {
        return gulp.src(['./build/js/*.json', './build/*.html'])
            .pipe(revCollector({
                replaceReved: true,
            }))
            .pipe(gulp.dest('./build'));
    })
    

    gulp-rev-collector这个插件的作用就是根据json文件,找出html中一一对应的js文件,并修改版本号。

    gulp.task('replace:css', function () {
        var text = fs.readFileSync('./build/css/rev-manifest.json', 'utf8'),
            obj = JSON.parse(text),
            str = '';
        for (i in obj) {
            str = obj[i];
        }
        gulp.src('./build/*.html')
            .pipe(htmlreplace({
                'css': './css/' + str,
            }, { keepBlockTags: true }))
            .pipe(gulp.dest('./build'));
    })
    

    在处理css版本替换的时候就面临了一个问题,因为css的所有文件都会被合并生成一个大文件,所以生成的json文件里只有一个合并后文件的版本号,因此gulp-rev-collector就无法一一对应替换,所以这边我用到的方法是,先获取到json文件里css文件的版本号,再找到所有html里需要替换的css文件(一个html文件里可能引用了多个css文件,有些需要替换,有些引用的外链无需替换)统一替换成一个合并后的css文件。这里用到了一个替换插件gulp-html-replace来实现对应操作,只需将需要编译的css文件用注释包起来就可以替换成想要的文件
    编译前:

     <!-- build:css -->
        <link rel="stylesheet" href="./css/normalize.css">
        <link rel="stylesheet" href="./css/main.css">
    <!-- endbuild -->
    

    编译后:

        <!-- build:css -->
        <link rel="stylesheet" href="./css/main.css?v=305ba0386a">
        <!-- endbuild -->
    

    任务三实现了编译结束后的打包工作,打开命令行工具,运行gulp build就会执行
    gulp.task('build', gulpsync.sync(['clean:package', 'pack', 'rev:js', 'replace:css']))

    以上就实现了用gulp实时编译和按需打包的功能啦~想试试的童鞋点击这里来构建自己的gulp工作流吧!

    相关文章

      网友评论

          本文标题:基于gulp的移动端解决方案

          本文链接:https://www.haomeiwen.com/subject/owneuftx.html