React+electron项目搭建 打包

React+electron项目搭建 打包

一.搭建react+electron项目

1.创建一个react项目

create-react-app my-app

cd my-app

npm start

看下页面是否打开,是否运行正确。

注意:如果页面没有src文件夹,

第一种:卸载全局安装包:

npm uninstall -g create-react-app

yarn global remove create-react-app

然后 npm start,浏览器会打开页面。

如果第一种不行,用第二种

第二种:忽视掉本地的create-react-app已存在的版本进行项目的创建

npx --ignore-existing create-react-app my-app

2. 引入electron

npm install electron --save-dev

 

3. 配置

1):在package.json配置入口文件,具体如下:

“main”:”main.js”

 

 

 

 

修改启动命令:

 

 

2)main.js文件编写

const { app, BrowserWindow } = require('electron')
const path = require('path')
const pkg = require('./package.json');

let mainWindow

function createWindow() {
  mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    preload: path.join(__dirname, 'preload.js')
    }
 })

  // 加载应用----react 打包
  //mainWindow.loadURL(url.format({
  //pathname: path.join(__dirname, './build/index.html'),
  //protocol: 'file:',
  //slashes: true
  //}))
  // 加载应用----适用于 react 项目和开发阶段npm run electron
   mainWindow.loadURL('http://localhost:3000/');
  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

app.on('activate', function () {
  if (mainWindow === null) createWindow()
})

 

 

启动:

npm start   npm run dev/electron  两个命令都执行时,浏览器打开页面,会打开桌面应用。

 

二.搭建react路由

npm install --save react-router-dom

 

src/Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import ReactMap from './router/routerMap';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <div>
    <ReactMap />
  </div>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

src/router/routerMap.js
import React from 'react'
import { HashRouter as Router, Route } from 'react-router-dom'
import Login from '../pages/Login/Login'

class ReactMap extends React.Component {
  updateHandle() {
    console.log("每次router变化后触发")
  }
  render() {
    return (
      <Router history={this.props.history}>
        <Route exact path="" component={Login} />
      </Router>
    )
  }
}
export default ReactMap;

 

三.搭建redux

npm install --save react-redux

npm install --save redux

npm install --save redux-thunk

 

src/Index.js

import React from 'react';
import ReactDOM from 'react-dom';
import ReactMap from './router/routerMap';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import { createStore, applyMiddleware, compose } from 'redux'
import rootRedux from './redux'
import thunk from 'redux-thunk'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose
const enhancer = composeEnhancers(applyMiddleware(thunk));
const store = createStore(
  rootRedux,
  enhancer
// applyMiddleware(thunk),
// window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

ReactDOM.render(
  <div>
    <Provider store={store}>
    <ReactMap />
    </Provider>
  </div>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

 

src/redux/index.js

import { combineReducers } from 'redux'
import set from './set'
export default combineReducers({
  data: set
})

 

src/redux/set.js

 

const set = (state = [], action) => {
  switch (action.type) {
    case 'GET_LIST':
      return {
        ...state,
        list: action.list
      }
    case 'SET_USERNAME':
      return {
        ...state,
        userName: action.list
      }
    default: return state
  }
}

export default set

 

 

src/actions/index.js

export const getList = () => {
   return {
    type: 'GET_LIST',
    list: '1111'
  }
}

export const setUserName = (list) => {
  return {
    type: 'SET_USERNAME',
    list: list
  }
}

 

四.不抽离 webpack配置的方案antd(npm run build 后找不到图片路径,暂未解决)

cnpm install --save react-app-rewired customize-cra

cnpm install --save babel-plugin-import

 

1.配置less,less-loader

cnpm install --save less less-loader

 

2. 根目录新建config-overrides.js文件

const { override, fixBabelImports, addWebpackAlias, addLessLoader } = require('customize-cra')
const path = require('path')
function resolve(dir) {
  return path.join(__dirname, dir)
}

// addLessLoader 添加less的引用
// fixBabelImports 按需加载antd组件
// addWebpackAlias 路径别名配置
/* 路径别名配置 */
module.exports = override(
  addWebpackAlias({
    '@': resolve('src'),
    components: resolve('./src/components'),
    assets: resolve('./src/assets'),
    static: resolve('./src/static'),
    img: resolve('./src/static/img'),
    js: resolve('./src/static/js'),
    css: resolve('./src/static/css'),
  }),
  /* antd组件按需加载 */
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: true,
  }),
  addLessLoader({
    javascriptEnabled: true,
    modifyVars: { '@primary-color': '#1DA57A' },
  }),

);

 

3.  修改package.json文件,目录结构

 

 

 

4.  使用:页面引用less

import '@/static/css/index.less'

 

五.抽离 webpack配置的方案

npm run eject 

 

运行后会出现config文件夹,在里面配置less 和路径别名配置

1.配置less,less-loader

cnpm install --save less less-loader

webpack.config.js里面进行less的配置

 

 

 

 

 

2.配置路径别名

webpack.config.js里面进行路径别名的配置

 

 

六.打包

1.打包的准备工作:

package.json,里面加上”homepage”:”.”

 

 

public里面加上main.js  package.json preload.js

package.json

{
    "name":"crh_chat",
    "version":"1.0-test",
    "main":"main.js",
    "author": {
        "name":"YOURNAME"
    },
    "license": "MIT"
}

 

main.js

如果需要引用一些模块就加入preload: path.join(__dirname, 'preload.js'),不用可以注释掉这段

const electron = require('electron');
const path = require('path');
// 控制应用生命周期的模块
const { app } = electron;
// 创建本地浏览器窗口的模块
const { BrowserWindow } = electron;

// 指向窗口对象的一个全局引用,如果没有这个引用,那么当该javascript对象被垃圾回收的
// 时候该窗口将会自动关闭
let win;

function createWindow() {
  // 创建一个新的浏览器窗口
  win = new BrowserWindow({
  width: 1920, 
  height: 1080, 
  autoHideMenuBar: true,
  webPreferences: {
      preload: path.join(__dirname, 'preload.js')
  }
  });

  // 并且装载应用的index.html页面
  win.loadURL(`file://${__dirname}/index.html`);

  // 打开开发工具页面
  //win.webContents.openDevTools();
  // 当窗口关闭时调用的方法
  win.on('closed', () => {
    // 解除窗口对象的引用,通常而言如果应用支持多个窗口的话,你会在一个数组里
    // 存放窗口对象,在窗口关闭的时候应当删除相应的元素。
    win = null;
  });
}


// 当Electron完成初始化并且已经创建了浏览器窗口,则该方法将会被调用。
// 有些API只能在该事件发生后才能被使用。
app.on('ready', createWindow);
/* var mainWindow = new BrowserWindow({
  webPreferences: {
    nodeIntegration: false
  }
}); */

// 当所有的窗口被关闭后退出应用
app.on('window-all-closed', () => {
  // 对于OS X系统,应用和相应的菜单栏会一直激活直到用户通过Cmd + Q显式退出
  if (process.platform !== 'darwin') {
    app.quit();
  }
});


app.on('activate', () => {
  // 对于OS X系统,当dock图标被点击后会重新创建一个app窗口,并且不会有其他
  // 窗口打开
  if (win === null) {
    createWindow();
  }

});

 

 

preload.js 这里引入了electron,需要用的时候,window.electron

global.electron = require('electron')

window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector)
    if (element) element.innerText = text
  } 

  
  for (const type of ['chrome', 'node', 'electron']) {
    replaceText(`${type}-version`, process.versions[type])
  }
})

 

有两个地方需要preload.js 外面那个是开发时要用的,public里面是打包后需要用到的。

 

 

 

 

2.npm run build

成功后会出现build文件夹,双击index.html在浏览器打开,可以正常运行

 

 

 

 

3.npm run package

pacakge.json里面的scripts配置

 

"package": "electron-packager ./build package0514 --win --out package/ --arch=x64 --app-version=1.1.0 --electron-version=8.0.0"

 

然后 npm run package

成功后页面会生成一个package文件,里面有我们打包好的文件

 

 

posted @ 2020-06-15 13:57  米娅m  阅读(3324)  评论(0编辑  收藏  举报