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({ 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({ 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文件,里面有我们打包好的文件