Electron + Antd + Mobx 環境搭建

最近要重構一版桌面管理軟件。業務需求與WEB版基本一致,但需要用到斷點續傳等本地功能。最經濟的辦法當然是移植到Electron環境中。
之前的應用框架主要用到了以下React套餐:

  • React
  • React-Router 路由
  • Mobx 數據管理
  • AntDesign 界面組件

經過一天時間的摸索大致找到了門路,構建完成後寫了一個腳手架,歡迎下載。

下面回顧一下本次環境搭建的過程。

安裝AntDesign的腳手架

關於Antd在CRA框架下的使用,官網有一份很詳細的操作說明(包括babel-import等的設置),初學者可以跟着一步一步學習。如果你趕時間,也可以直接用它的腳手架。

$ git clone https://github.com/ant-design/create-react-app-antd.git my-project
$ cd my-project
$ npm install && npm start

跑起來以後,會自動彈出一個頁面 localhost:3000,網頁上顯示的就是最基礎的包括了antd的demo示例。

安裝Electron及配置

關於electron的介紹,可以看官網文檔,本文不涉及。
完成antd腳手架安裝後,在工程目錄下安裝electron。

$ npm install electron --save-dev

安裝完成以後,在根目錄下需要做一些設置,包括:
electron啓動腳本

  1. npm啓動及編譯命令
  2. render端使用electron模塊的設置
  3. electron啓動腳本

在根目錄下新建main.js,寫入以下內容。(其實與官方例子是一樣的)

// Modules to control application life and create native browser window
const {app, BrowserWindow} = require('electron')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadFile('build/index.html')

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

npm啓動及編譯命令

在工程根目錄的package.json中加入以下內容:

{
  ...
  "main": "main.js",
  "homepage": ".",
  "scripts": {
    "electron-dev": "electron . --env dev",
    "electron-build": "npm run build && electron . --env build",
    "start": "react-app-rewired start",
    ...
  }
}

我們希望在執行npm run electron-dev時,能打開electron應用並展示antd的網頁內容,那麼需要修改main.js:

  ...
  // and load the index.html of the app.
  // mainWindow.loadFile('index.html')   // 這個是原內容,修改爲以下內容
  if (argv && argv[1] === 'dev') {       // 如果npm run electron-dev,加載本地網頁
    mainWindow.loadURL('http://localhost:3000/')
  }
  else if (argv && argv[1] === 'build') {
    mainWindow.loadURL(url.format({
      pathname: path.join(__dirname, './build/index.html'),
      protocol: 'file:',
      slashes: true
    }))
  }
...

配置到這裏後,打開兩個終端,分別cd到項目根目錄下。

$ npm start   // 終端1
$ npm run electron-dev   // 終端2

electron界面應該就會展示出來,界面中顯示的就是antd的demo內容。
圖片描述

render端使用electron模塊

經過以上設置,界面內容已經可以正常展示並可以實時刷新,但還缺少了一個重要功能:electron模塊,用以支持本地化操作。
配置的基本思路是,在electron啓動過程中在window對象中設置webPreferences的preload屬性[文檔],將electron模塊註冊爲global對象供renderer側使用。

...
  // Create the browser window.
  // mainWindow = new BrowserWindow({ width: 800, height: 600 })
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    autoHideMenuBar: true,
    fullscreenable: false,
    webPreferences: {
      javascript: true,
      plugins: true,
      nodeIntegration: false, // 不集成 Nodejs
      webSecurity: false,
      preload: path.join(__dirname, './public/renderer.js') // public目錄下的renderer.js
    }
  })
...
// 新建renderer.js,public目錄下
const process = require('process');

process.once('loaded', () => {
  global.electron = require('electron')
});

設置成功後,在renderer側即可引入electron的remote模塊。

使用mobx

安裝mobx及mobx-react

$ npm install mobx mobx-react --save

安裝成功後,在App.js中使用:

...
import { observer } from 'mobx-react';
...

@observer
class App extends React.Component {
  ...
}

執行開發命令後,會發現出現了一個編譯錯誤。
圖片描述
原因就在於CRA團隊並不傾向於支持所有未正式發佈的javascript語言特性,目前要使用裝飾圈,均需要使用babel等進行轉譯。這個問題目前有兩個方法:使用eject方式或react-app-rewire-mobx模塊。
使用eject方式將會暴露出所有的webpack配置,開發者如果熟悉可以進行自定義的配置。當然,這樣做的話create-react-app的意義就大打折扣了。
使用react-app-rewire-mobx則相對方便了許多,只需安裝該模塊,並在config-overrides.js中加入,即可正常使用。

注意

按照上面的方式配置以後,仍然會報錯。

./src/index.js Error: The 'decorators' plugin requires a
'decoratorsBeforeExport' option, whose value must be a boolean. If you
are migrating from Babylon/Babel 6 or want to use the old decorators
proposal, you should use the 'decorators-legacy' plugin instead of
'decorators'.

原因在於,新版的babel7.0的描述換了一種方式。應該將上面的配置改爲:

module.exports = function override(config, env) {
  ...
  config = injectBabelPlugin(["@babel/plugin-proposal-decorators", { legacy: true }], config);
  return config;
}

其實在react-app-rewire-mobx中也僅僅就是就是導入這個修飾符,只不過是舊版的寫法。但就因爲沒有跟隨babel7.0更新,所以導致了這個

// react-app-rewire-mobx/index.js
const {injectBabelPlugin} = require('react-app-rewired');

function rewireMobX(config, env) {
  return injectBabelPlugin('transform-decorators-legacy', config);
}

module.exports = rewireMobX;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章