zoukankan      html  css  js  c++  java
  • 前端修仙之路-四、如何利用gulp创建web前端开发框架(终)

    通过前面三篇内容我们已经学习如何利用gulp插件和gulp脚手架来搭建一个完整的web前端框架,这篇就主要讲解将框架中的一些代码和文件独立,让框架项目结构更加清晰,也便于在日常开发中使用。

    主要从下面四个步骤出发:

    1.利用npm来运行框架。

    2.代码整合

    3.文件整合

    4.如何配置和使用gitignore文件

    首先我们先把第一步实现一下:用npm来执行脚本命令。

    看一下npm的强大功能之一,npm允许在package.json文件里面,使用scripts定义脚本命令。就像我们创建的package.json文件中,可以看到下面这一段:

    scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },

    面代码是package.json文件的一个片段,里面的scripts字段是一个对象。它的每一个属性,对应一段脚本。比如,test命令对应的脚本是输出一串报错终止脚本。

    我们在控制台中运行一下,输入:

    npm run test

     从上面截图可以看到,虽然报了个错,但是说明还是执行了那个test名称的脚本。

    那么为什么要学习用npm来执行命令呢?当然有作用,因为我们接下来将用npm来运行gulpfile.js这个文件,不用gulp脚手架了。

    那么我们改一下脚本运行命令test的执行:

    "scripts": {
        "test": "gulp dev --env development"
      },

    改成gulp执行开发环境的命令,然后在控制台中用npm再执行一下上面的命令,

    可以看到项目已经在跑起来了。

    通过上面的方法,我们省去了安装gulp脚手架的麻烦。那么将打包生产环境的脚本命令也添加到package.json文件中。

    "scripts": {
        "dev": "gulp dev --env development",
        "build": "gulp dev --env production"
      },

    可以通过在控制台运行“npm run dev” 和 “npm run build”就可以将项目运行起来和将项目打包。

    上面已经把第一步完成了,下面接着讲第二、三步:代码和文件的整合。

    我们需要在框架根目录下创建一main个文件夹,然后把框架根目录下的gulpfile.js、utils.js、config.js移入到main文件夹中并需要修改一下gulpfile.js中的代码:

    const gulp = require('gulp');
    const stylus = require('gulp-stylus');
    const uglify = require('gulp-uglify');
    const cleanCss = require('gulp-clean-css');
    const postcss = require('gulp-postcss');
    const postcssrc = require('postcss-load-config');
    const connect = require('gulp-connect');
    const plumber = require('gulp-plumber'); // 避免出错task终止
    const minimist = require('minimist'); // 用于命令行传参数
    const gulpif = require('gulp-if'); // 用于命令行传参
    const cleanCSS = require('gulp-clean-css'); // 缩小css文件
    const changed = require('gulp-newer'); // 增量更新
    const babel = require('gulp-babel');
    const tinypng_nokey = require('gulp-tinypng-nokey'); //压缩图片--免key
    const opn = require('opn'); // 开启浏览器
    const del = require('del'); // 删除dist文件夹
    
    const { getPort } = require('./utils');
    const Config = require('./config');
    // 命令行传参数
    const knownOptions = {
        string: 'env',
        default: { env: process.env.NODE_ENV || 'production' }
    };
    const options = minimist(process.argv.slice(2), knownOptions);
    // 检查端口冲突
    const checkPort = async () => {
        Config.connect.port = await getPort();
    };
    // 开启文件服务器
    const openServer = async () => await connect.server(Config.connect);
    // 自动打开浏览器
    const openBrowser = async () => {
        console.log('打开浏览器');
        const { host, port } = Config.connect;
        const url = `http://${host}:${port}/view`;
        opn(url);
    };
    // HTML文件
    const htmls = () => {
        return gulp
            .src('src/view/**/*.html')
            .pipe(changed('src/view/**/*.html'))
            .pipe(plumber())
            .pipe(gulp.dest('dist/view/'))
            .pipe(connect.reload());
    };
    // CSS文件
    const styles = () => {
        return gulp
            .src('src/css/**/*.styl')
            .pipe(changed('src/css/**/*.styl'))
            .pipe(plumber())
            .pipe(stylus())
            .pipe(gulpif(options.env === 'production', cleanCSS()))
            .pipe(gulp.dest('dist/css/'))
            .pipe(connect.reload());
    };
    // 图片文件
    const images = () => {
        return gulp
            .src('src/images/**/*')
            .pipe(changed('src/images/**/*'))
            .pipe(plumber())
            .pipe(gulp.dest('dist/images/'))
            .pipe(connect.reload());
    };
    // 图片压缩
    const imgTiny = () => {
        return gulp
            .src('src/images/**/*')
            .pipe(changed('src/images/**/*'))
            .pipe(tinypng_nokey())
            .pipe(gulp.dest('dist/images/'))
            .pipe(connect.reload());
    }
    // JS文件
    const scripts = () => {
        return gulp
            .src('src/js/**/*.js')
            .pipe(changed('src/js/**/*.js'))
            .pipe(plumber())
            .pipe(babel()) //ES6转换
            .pipe(gulpif(options.env === 'production', uglify()))
            .pipe(gulp.dest('dist/js/'))
            .pipe(connect.reload());
    };
    
    //检测文件是否有更新
    const watchFiles = () => {
        gulp.watch('src/view/**/*.html', htmls); //检测到html文件更新,更新版本号
        gulp.watch('src/css/**/*.styl', styles);
        gulp.watch('src/images/*', images);
        gulp.watch('src/js/**/*.js', scripts);
    };
    // 删除dist目录
    const clean = () => {
        return del(['dist']);
    };
    // 开发环境-不压缩JS、css和图片
    const devbuild = gulp.series(
        checkPort,
        gulp.parallel(openServer, htmls, styles, images, scripts),
        openBrowser,
        watchFiles
    );
    // 生产环境-不运行服务、不开启浏览器、代码压缩和图片压缩
    const prodbuild = gulp.series(
        clean,
        gulp.parallel(htmls, styles, imgTiny, scripts),
    );
    const build = options.env === 'production' ? prodbuild : devbuild; //判断是开发环境还是生产环境
    options.env === 'production' ? null : watchFiles();
    module.exports = build;
    View Code

    上面在gulpfile.js文件中做了导出模块,我们在根目录下再创建个gulpfile.js文件(这个文件名用其他的不行,必须要用gulpfile,gulp命令必须需要找到gulpfile这个文件名才能正常运行,其他不行,诶,没办法了),写入下面代码:

    const gulp = require('gulp');
    const build = require('./main/gulpfile.js');
    gulp.task('dev', build);

     如果大家有点强迫症的话,我们只能修改main文件夹下的gulpfile.js文件名,就把它改成main.js,相应的再改一下根目录下gulpfile.js中的导入路径:

    const gulp = require('gulp');
    const build = require('./main/main.js');
    gulp.task('dev', build);

    接下来,在配置config.js文件中,封装项目资源的路径:

    const { host } = require('./utils');
    
    const folder = {
        src: 'src/', // 源文件目录
        dist: 'dist/' // 文件处理目录
    };
    
    const distFiles = folder.dist + '**'; // 目标路径下的所有文件
    
    const Config = {
        connect: {
            root: 'dist',
            livereload: true,
            port: 1234,
            host
        },
        src: folder.src,
        dist: folder.dist,
        distFiles: distFiles,
        html: {
            src: folder.src + 'view/**/*.html',
            dist: folder.dist + 'view/'
        },
        css: {
            src: folder.src + 'css/**/*.styl',
            avoid: '!' + folder.src + 'css/stylus/*',
            dist: folder.dist + 'css/'
        },
        js: {
            src: folder.src + 'js/**/*.js',
            dist: folder.dist + 'js/'
        },
        images: {
            src: folder.src + 'images/**/*',
            dist: folder.dist + 'images/'
        },
        libs: {
            src: folder.src + 'common/**/*',
            dist: folder.dist + 'common/'
        }
    };
    
    module.exports = Config;

    再来修改main.js代码中的静态资源路径为实参:

    const gulp = require('gulp');
    const stylus = require('gulp-stylus');
    const uglify = require('gulp-uglify');
    const cleanCss = require('gulp-clean-css');
    const postcss = require('gulp-postcss');
    const postcssrc = require('postcss-load-config');
    const connect = require('gulp-connect');
    const plumber = require('gulp-plumber'); // 避免出错task终止
    const minimist = require('minimist'); // 用于命令行传参数
    const gulpif = require('gulp-if'); // 用于命令行传参
    const cleanCSS = require('gulp-clean-css'); // 缩小css文件
    const changed = require('gulp-newer'); // 增量更新
    const babel = require('gulp-babel');
    const tinypng_nokey = require('gulp-tinypng-nokey'); //压缩图片--免key
    const opn = require('opn'); // 开启浏览器
    const del = require('del'); // 删除dist文件夹
    
    const { getPort } = require('./utils');
    const Config = require('./config');
    // 命令行传参数
    const knownOptions = {
        string: 'env',
        default: { env: process.env.NODE_ENV || 'production' }
    };
    const options = minimist(process.argv.slice(2), knownOptions);
    // 检查端口冲突
    const checkPort = async () => {
        Config.connect.port = await getPort();
    };
    // 开启文件服务器
    const openServer = async () => await connect.server(Config.connect);
    // 自动打开浏览器
    const openBrowser = async () => {
        console.log('打开浏览器');
        const { host, port } = Config.connect;
        const url = `http://${host}:${port}/view`;
        opn(url);
    };
    // HTML文件
    const htmls = () => {
        return gulp
            .src(Config.html.src)
            .pipe(changed(Config.html.src))
            .pipe(plumber())
            .pipe(gulp.dest(Config.html.dist))
            .pipe(connect.reload());
    };
    // CSS文件
    const styles = async () => {
        const config = await postcss();
        return gulp
            .src([Config.css.src, Config.css.avoid])
            .pipe(changed(Config.css.src))
            .pipe(plumber())
            .pipe(stylus())
            .pipe(postcss(config.plugins, config.options))
            .pipe(gulpif(options.env === 'production', cleanCSS()))
            .pipe(gulp.dest(Config.css.dist))
            .pipe(connect.reload());
    };
    // 图片文件
    const images = () => {
        return gulp
            .src(Config.images.src)
            .pipe(changed(Config.images.src))
            .pipe(plumber())
            .pipe(gulp.dest(Config.images.dist))
            .pipe(connect.reload());
    };
    // 图片压缩
    const imgTiny = () => {
        return gulp
            .src(Config.images.src)
            .pipe(tinypng_nokey())
            .pipe(gulp.dest(Config.images.dist))
            .pipe(connect.reload());
    }
    // JS文件
    const scripts = () => {
        return gulp
            .src(Config.js.src)
            .pipe(changed(Config.js.src))
            .pipe(plumber())
            .pipe(babel()) //ES6转换
            .pipe(gulpif(options.env === 'production', uglify()))
            .pipe(gulp.dest(Config.js.dist))
            .pipe(connect.reload());
    };
    
    //检测文件是否有更新
    const watchFiles = () => {
        gulp.watch(Config.html.src, htmls); //检测到html文件更新,更新版本号
        gulp.watch(Config.css.src, styles);
        gulp.watch(Config.images.src, images);
        gulp.watch(Config.js.src, scripts);
    };
    // 删除dist目录
    const clean = () => {
        return del(['dist']);
    };
    // 开发环境-不压缩JS、css和图片
    const devbuild = gulp.series(
        checkPort,
        gulp.parallel(openServer, htmls, styles, images, scripts),
        openBrowser,
        watchFiles
    );
    // 生产环境-不运行服务、不开启浏览器、代码压缩和图片压缩
    const prodbuild = gulp.series(
        clean,
        gulp.parallel(htmls, styles, imgTiny, scripts),
    );
    const build = options.env === 'production' ? prodbuild : devbuild; //判断是开发环境还是生产环境
    options.env === 'production' ? null : watchFiles();
    module.exports = build;
    View Code

    现在我们接着讲第四步:如何配置和使用gitignore文件。

    我们需要了解一下gitignore文件是个啥东西呢?首先要强调一点,这个文件的完整文件名就是".gitignore",注意最前面有个“.”一般来说每个Git项目中都需要一个“.gitignore”文件,这个文件的作用就是告诉Git哪些文件不需要添加到版本管理中。日常开发项目的时候,为了自己方便和同事方便,也一般会把项目提交都Git上,这样的话,这个gitignore文件可就是个好东西了,首先就我们现在创建的框架来说,先看一下现在的整体目录吧:

    上图中里面圈出的目录就是现在的框架整体目录,如果我们需要将这个整体提交到git上,node_modules和dist这两个文件夹及其里面的内容是不用提交的。node_modules可以根据packa.json来安装,dist可以运行“npm run dev”或者“npm  run build”来创建。

    所以完全是可以忽略掉这两个的。

    那应该怎么做呢?我们同样在项目根路径下创建一个“.gitignore”文件,然后写入:

    node_modules/
    dist/

    “/”代表该文件夹下的所有。这样在每次push的时候,会自动忽略掉这两个文件夹里面的文件的。

    写在最后:好久没有试过写这么长的教程了,记得写这么长的时候还是第一次写博客的时候,当时是去年还是去去年了,当时是做毕业设计的时候,当时还是Java出身的小白,现在已经转身走上了web前端的修仙之路了,有时候命运还是挺会捉弄人的哈。不想感慨太多,这个长篇教程可能有很多地方写的不是很好,但敬请大家见谅就好了。其实这个框架不是我做的,是我公司的前辈们做的,现在只不过是引用并写下心得教程啦~当然我在入职这个公司之前也还是有过gulp构建框架的基础,不过那个时候是用gulp和bower搭建过一套不是很完整的框架,入职这个公司之后,看到这个框架,才知道什么叫做大佬吧,虽然这里的功能不是很多,但够用和实用确实是够了的。当然,这个框架现在也算是开源了吧,哈哈~大家有需要的什么功能,比如:手机端自适应插件、版本hash值添加这些功能也是可以自行添加的,gulp上有很多实用的插件。这个就看个人需求了,后面的话,如果有空的话,也是会经常写开发中的日志,遇到的什么难题呀、有比较好用的UI之类的,跟大家分享一下嘛!

    人生没有彩排,每天都是现场直播!加油!

  • 相关阅读:
    如何使用log4net记录日志
    js鼠标左右键,键盘值
    MagicAjax的内部原理初探(一)
    关于VS2005内置web服务器和IIS的区别问题(讨论,收集)
    在Linux中使用C#
    方便你的测试(TestDriven.NET)
    转载:数据库sharding(scale up to scale out)
    单元测试--爱你不容易
    你期待已久的ASP.NET Atlas(一)[翻]
    Ajax底层代码简析(可直接用的框架)
  • 原文地址:https://www.cnblogs.com/liao123/p/13625886.html
Copyright © 2011-2022 走看看