使用Gulp优化构建流程

449 阅读3分钟

故事背景

最近我将客户端项目(electron开发)从JavaScript全部迁移到了Typescript,由此产生了以下几个问题:

  1. Typescript如何编译成JavaScript

electron无法直接使用ts文件作为开发环境的启动入口,也不能使用ts文件作为打包入口;所以必须将Ts编译成Js

  1. JavaScript语法兼容

将Ts文件编译成Js文件之后,需将其中的高级语法编译成兼容性强的低级语法,这个过程需使用Babel

  1. electron启动入口寻找

需要指定electron启动开发环境或者打包的入口路径

改进前的解决方案

使用嵌套的scripts命令以及rimraf实现↓↓↓

以启动开发环境为例:

  1. 需先使用tsc --outDir runtime_tmp将Typescript编译成JavaScript; 由Ts编译得到的Js代码放到 runtime_tmp这个临时目录下面;

  2. 然后使用npx babel ./runtime_tmp --out-dir ./runtime 这一步将runtime_tmp目录下的高级Js语法转化成低级Js语法并放到runtime目录下

  3. 最后再删除中间文件./runtime_tmp

  4. 到这里完成源代码的构建,最后还要使用electron ./runtime启动开发环境。

    scripts命令如下所示:

    "prev": "tsc --outDir runtime_tmp && npx babel ./runtime_tmp --out-dir ./runtime && rimraf ./runtime_tmp",
    "start": "yarn prev && cross-env NODE_ENV=development electron ./runtime",

这里用到了cross-env和rimraf 两个库文件。使用rimraf是为了保证在不同的os下都能够成功的删除临时目录,直接使用shell命令可能会报错。

问题在于:上述的scripts脚本非常难阅读,增加不少的心智负担。于是我使用gulp构建自动化的工作流程,如下所示:

改进后的解决方案:

使用gulp构建工具的流来设置打包路线,从而使构建过程更加清晰

安装依赖并创建gulpfile.js


touch gulpfile.js

yarn add -D gulp gulp-typescript gulp-babel gulp-exec @types/gulp @types/gulp-typescript @types/gulp-babel @types/gulp-exec

gulpfile.js中的内容为:


// gulpfile.js

const gulp = require('gulp');

const ts = require('gulp-typescript');

const babel = require('gulp-babel');

const {

    series

} = require('gulp');

const exec = require('gulp-exec');

 

// 将ts编译成js

function compileTypeScript() {

    const tsProject = ts.createProject('tsconfig.json');

    return tsProject.src()

        .pipe(tsProject()) // ts => js

        .pipe(babel()) // js => js

        .pipe(gulp.dest('runtime'));

}

 

// 开发

function dev() {

    const tsProject = ts.createProject('tsconfig.json');

    return tsProject.src()

        .pipe(tsProject())

        .pipe(babel())

        .pipe(gulp.dest('runtime'))

        .pipe(exec('cross-env NODE_ENV=development electron ./runtime')); // 执行shell脚本

}

 

// 打包

function build() {

    const tsProject = ts.createProject('tsconfig.json');

    return tsProject.src()

        .pipe(tsProject())

        .pipe(babel())

        .pipe(gulp.dest('runtime'))

        .pipe(exec('electron-builder'));

}

 

gulp.task('compile', series(compileTypeScript));

gulp.task('dev', series(dev));

gulp.task('build', series(build));

 

// 默认导出是编译,也就是ts=>js的结果

exports.default = series(

    compileTypeScript,

);

package.json中的脚本相应改成:


     "compile": "npx gulp",

     "start": "npx gulp dev",

     "dist": "npx gulp build",

要点

在使用.pipe(tsProject()).pipe(babel())的时候没有传入命令行参数,所以必要的参数需要在tsconfig.jsonbabel.config.js中提前配置好(主要是配置每一步输出文件目录和下一步的入口目录)

electron入口问题

  1. 在dev函数中,通过.pipe(exec('cross-env NODE_ENV=development electron ./runtime'));制定了yarn start也就是npx gulp dev运行时的入口目录为**./runtime**,这样就解决了启动开发环境时候electron找到入口的问题。

  2. 解决electron打包时的入口问题,需要在package.json中配置build字段:

"build": {

"appId": "***",

"productName": "***",

"directories": {

  "output": "***"

},

"files": [

  {

    "from": "runtime/",

    "to": "src/"

  },

  "*/**",

  "**/*",

  "!src/"

],

"extraResources": [

  {

    "from": "***",

    "to": "***"

  }

],

"asar": true,

"win": {

  "icon": "***",

  "target": "dir",

  "requestedExecutionLevel": "requireAdministrator"

},

"linux": {

  "target": "dir"

}

},

其中的关键点在于配置build.files.fromruntime, 也就是babel的输出目录。

结论

使用gulp之后的构建流程变得非常简洁,并且容易阅读,可维护性大大增强。