Electron 開發的 gulp 配置

源自 Atom-shell 的 Electron 目前是一個很火的項目。已經有不少開發者基於 Electron 開發出了各類各樣的桌面程序。在我看來,對於廣大前端開發者來講,最爲耳熟能詳的應該是 Atom 和 VS Code。在 Electron 的官網上可以看到更多有意思的項目。css

以前提到過,個人計劃之一就是玩一下 Electron,打造一個桌面工具。上個星期通過幾回摸索和調研肯定了這個項目的可行性以後,開始着手打造。近幾天慢慢的構建出基礎的項目前端結構。html

對於前端的技術選型已經沒有以前那麼糾結了,思考事後決定了:React。緣由很簡單,以前的一個小項目用的是 Vuejs 的一套體系,此次想換換口味。雖然以前我一直很不喜歡 React 那種模板和邏輯混合在一塊兒的方式,可是很喜歡 Redux 的處理方式,因此忍不住試試看,究竟是用 React 爽仍是 Vue 爽。前端

瞭解過 Electron 的應該都知道它的 main process 和 renderer process。main process 使用 BroswerWindow 實例建立 web page,每一個 BroswerWindow 實例在它本身的 renderer process 中運行 web page,每當 BroswerWindow 實例被銷燬時,其對應的 renderer process 也會被終止。main process 管理全部的 web page 及其對應的 renderer process 。vue

我以爲能夠這麼簡單地理解的:若是將 renderer process 負責管理渲染的 web 頁面所作的事情和瀏覽器相似,那麼 main process 則是包裹着這個「瀏覽器」的外殼,將「瀏覽器」中的代碼與系統底層聯繫在一塊兒。node

在實踐過程當中,我發現 main process 的文件不能使用 import(應該說是沒法使用 ES6 語法),可使用 babel 將使用 ES6 語法的代碼編譯成可執行的版本代碼。而 renderer process 的代碼則經過 webpack 打包 React 代碼。react

gulp-babel 編譯 main process 代碼

經過 gulp 和 babel 能夠很輕鬆地完成webpack

var path = require('path');
var gulp = require('gulp');
var babel = require("gulp-babel");

var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');

// main process 的編譯
gulp.task('babel:electron-main', function () {
  return gulp.src([APP_PATH + '/main.js', APP_PATH + '/main/**/*.js'], { base: APP_PATH })
    .pipe(babel())
    .pipe(gulp.dest('dist'));
});

gulp 與 babel 的配合使用的更多細節能夠參考 babelgulp-babelgit

React 的 webpack 配置在這裏我就不重複了,處處都能找到。github

process 的重啓和刷新

我發如今目前市面上Electron 的相關基礎教程中,簡單的介紹都是如此:web

// 安裝 
npm install -g electron-prebuilt
// 啓動
electron .

//更好一點的是按照官方給出的 quick start
npm start

可是這樣有一個很直接的問題:每次修改 main process 相關代碼以後須要重啓,修改了 renderer process 相關代碼以後須要手動刷新,這很影響開發體驗。

renderer process 的 hot load 很好處理,和前端開發相似,react 和 vue 都有相似的工具,直接將前端開發中使用的配置挪過來就好。而 main process 的自動化則須要另尋辦法,固然,也不難。使用 electron-connect 能夠很好的幫助咱們解決這個問題,在 gulp 中設置好task 以後而後在 renderer process 和 main process 中的插入一段代碼便可。

  • gulpfile.js

    var gulp = require('gulp');
    var gutil = require('gulp-util');
    var electron = require('electron-connect').server.create();
    
    gulp.task('watch:electron', function () {
      electron.start();
      gulp.watch(['./app/src/main.js', './app/src/main/**/*.js'], electron.restart);
      gulp.watch(['./app/dist/**/*.{html,js,css}'], electron.reload);
    });
  • RendererProcess

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Hello World!</title>
    </head>
    <body>
    
    <!-- All of the Node.js APIs are available in this renderer process. -->
    <!--We are using node <script>document.write(process.versions.node)</script>,-->
    Chromium <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
    and Node <script>document.write(process.version)</script>.
    <div id="example"></div>
    </body>
    <script>
          //建立 client
        require('electron-connect').client.create();
    </script>
    </html>
  • MainProcess

    'use strict';
    
    var app = require('app');
    var BrowserWindow = require('browser-window');
    var client = require('electron-connect').client;
    
    app.on('ready', function () {
      var mainWindow = new BrowserWindow({
        width: 400,
        height: 300
      });
      mainWindow.loadUrl('file://' + __dirname + '/index.html');
    
      // Connect to server process
      client.create(mainWindow);
    });

細心的同窗可能會發現,在 watch 的 task 中,同時對 main process 和 renderer process 的代碼監聽,對應的操做是 restart 和 reload。reload 會刷新當前的頁面,在這裏 React 的 hot load 均可以不須要了。印象中好像 hot load 是不會整個刷新頁面的,回頭能夠試試。

至此,只須要在終端中執行

gulp watch:electron

就能達到開發過程當中 electron 自動 restart 和 reload 的目的了。若是想看詳細文檔能夠前往 這裏

上述只是簡單的例子,更多時候須要根據項目的規劃作調整,一下是個人 gulpfile.js

var path = require('path');
var gulp = require('gulp');
var babel = require("gulp-babel");
var gutil = require('gulp-util');
var webpack = require('webpack');
var webpackConfig = require('./webpack.config.js');
var electron = require('electron-connect').server.create();

var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');

// 開發
var webpackConfigDev = Object.create(webpackConfig);
webpackConfigDev.devtool = 'eval-source-map';
webpackConfigDev.debug = true;

var devCompiler = webpack(webpackConfigDev);

// renderer process 的 webpack 編譯
gulp.task('webpack:build-dev', function () {
  devCompiler.run(function (err, status) {
    if (err) {
      throw new gutil.PluginError('webpack:build-dev', err);
    }
    gutil.log('[webpack:build-dev]', status.toString({
      colors: true
    }));
  });
});

// main process 的編譯
gulp.task('babel:electron-main', function () {
  return gulp.src([APP_PATH + '/main.js', APP_PATH + '/main/**/*.js', APP_PATH + '/constant/*.js'], { base: APP_PATH })
    .pipe(babel())
    .pipe(gulp.dest('dist'));
});


gulp.task('watch', ['babel:electron-main', 'webpack:build-dev'], function () {

  electron.start();

  gulp.watch(['./app/main.js', './app/main/**/*.js'], ['babel:electron-main']);
  gulp.watch([APP_PATH + '/constant/*.js', './app/src/**/*.{html,js,css}'], ['webpack:build-dev']);

  gulp.watch(['./dist/main.js', './dist/main/**/*.js'], electron.restart);
  gulp.watch(['./dist/renderer/*.{html,js,css}', './dist/renderer/**/*.{html,js,css}'], electron.reload);

});

gulp.task('dev', ['watch']);
相關文章
相關標籤/搜索