本文讲述如何使用 electron + react + material-ui + webpack 来快速搭建一个桌面应用。

app

目录结构如下

├── electron-react-webpack/             # Your project's name

    ├── app/

        ├── build/                      # Webpack 2 will create and update this folder
            ├── bundle.js               # Bundled JS
            ├── ...                     # Your images will be copied here

        ├── src/

            ├── assets/                 # Images
                ├── electron.png
                ├── react.png
                ├── webpack.png

            ├── components/             # React Components
                ├── Link.js
                ├── Logo.js

            ├── App.js                  # React main component
            ├── entry.js                # App entry. Your global JS can go here

        ├── index.html                  # Single Page Application HTML, it only uses build's files

    ├── main.js                         # Electron app
    ├── package.json
    ├── webpack.config.js               # Webpack setup

package.json 文件

{
  "name": "app-name",
  "version": "0.2.0",
  "description": "",
  "main": "main.js",
  "babel": {
    "presets": [
      "es2015",
      "react",
      "stage-0"
    ]
  },
  "scripts": {
    "dev": "webpack",
    "start": "electron ."
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/yourname/repo.git"
  },
  "author": "xzdbd",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/yourname/repo/issues"
  },
  "homepage": "https://github.com/yourname/repo#readme",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-polyfill": "^6.26.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "css-loader": "^0.28.8",
    "electron": "^1.7.10",
    "electron-reload": "^1.2.2",
    "file-loader": "^1.1.6",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.10.1"
  },
  "dependencies": {
    "material-ui": "^1.0.0-beta.27",
    "material-ui-icons": "^1.0.0-beta.17",
    "react": "^16.2.0",
    "react-dom": "^16.2.0"
  }
}

webpack 配置文件 webpack.config.js

module.exports = {
  
      watch: true,
  
      target: 'electron',
  
      entry: ['babel-polyfill', './app/src/entry.js'],
  
      output: {
          path: __dirname + '/app/build',
          publicPath: 'build/',
          filename: 'bundle.js'
      },
  
      module: {
          rules: [
              {
                  test: /\.jsx?$/,
                  exclude: /node_modules/,
                  loader: 'babel-loader'
              },
              {
                  test: /\.(png|jpg|gif|svg)$/,
                  loader: 'file-loader',
                  query: {
                      name: '[name].[ext]?[hash]'
                  }
              }
          ]
      },
  
  };

Electron 的 app 文件 main.js

// Basic init
const electron = require('electron')
const {app, BrowserWindow} = electron

// Let electron reloads by itself when webpack watches changes in ./app/
require('electron-reload')(__dirname)

// To avoid being garbage collected
let mainWindow

app.on('ready', () => {

    let mainWindow = new BrowserWindow({width: 450, height: 600})

    mainWindow.loadURL(`file://${__dirname}/app/index.html`)

})

定义主界面的 html 文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="build/bundle.js"></script>
  </body>
</html>

定义 react 的入口 app/src/entry.js

import React from 'react'
import {render} from 'react-dom'
import App from './app'

render(
    <App/>,
    document.getElementById('app')
)

定义一个 react component app/src/app.js

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import IconButton from 'material-ui/IconButton';
import MenuIcon from 'material-ui-icons/Menu';

const styles = {
  root: {
    width: '100%',
  },
  flex: {
    flex: 1,
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20,
  },
};

function App(props) {
  const { classes } = props;
  return (
    <div className={classes.root}>
      <AppBar position="static">
        <Toolbar>
          <IconButton className={classes.menuButton} color="contrast" aria-label="Menu">
            <MenuIcon />
          </IconButton>
          <Typography type="title" color="inherit" className={classes.flex}>
            Electron App
          </Typography>
          <Button color="contrast">Login</Button>
        </Toolbar>
      </AppBar>
    </div>
  );
}

App.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(App);

运行 webpack 打包,支持热更新

npm run dev

运行 electron app

npm start