摘要:是一個使用和等技術創建原生程序的框架,它負責比較難搞的部分,你只需把精力放在你的應用的核心上即可。談談技術選型使用去做底層的繪制,大項目首選狀態管理的最佳實踐肯定不是,目前首選,或者。
目前Electron在github上面的star量已經快要跟React-native一樣多了
這里吐槽下,webpack感覺每周都在偷偷更新,很糟心啊,還有Angular更新到了8,Vue馬上又要出正式新版本了,5G今年就要商用,華為的系統也要出來了,RN還沒有更新到正式的1版本,還有號稱讓前端開發者失業的技術flutter也在瘋狂更新,前端真的是學不完的
回到正題,不能否認,現在的大前端,真的太牛了,PC端可以跨三種平臺開發,移動端可以一次編寫,生成各種小程序以及React-native應用,然后跑在ios和安卓以及網頁中 , 這里不得不說-------京東的Taro框架 這些人 已經把Node.js和webpack用上了天對webpack不熟悉的,看我之前的文章 ,今天不把重點放在webpack
歡迎關注我的專欄 《前端進階》 都是百星高贊文章
手寫React優化版腳手架
前端性能優化不完全手冊
手寫vue腳手架
本文源碼git倉庫地址
先說說Electron官網介紹: 使用 JavaScript, HTML 和 CSS 構建跨平臺的桌面應用 ,如果你可以建一個網站,你就可以建一個桌面應用程序。 Electron 是一個使用 JavaScript, HTML 和 CSS 等 Web 技術創建原生程序的框架,它負責比較難搞的部分,你只需把精力放在你的應用的核心上即可。什么意思呢?
Electron = Node.js + 谷歌瀏覽器 + 平常的JS代碼生成的應用,最終打包成安裝包,就是一個完整的應用
Electron分兩個進程,主進程負責比較難搞的那部分,渲染進程(平常的JS代碼)部分,負責UI界面展示
兩個進程之間可以通過remote模塊,以及IPCRender和IPCMain之間通信,前者類似于掛載在全局的屬性上進行通信(很像最早的命名空間模塊化方案),后者是基于發布訂閱機制,自定義事件的監聽和觸發實現兩個進程的通信。
Electron相當于給React生成的單頁面應用套了一層殼,如果涉及到文件操作這類的復雜功能,那么就要依靠Electron的主進程,因為主進程可以直接調用Node.js的API,還可以使用C++插件,這里Node.js的牛逼程度就凸顯出來了,既可以寫后臺的CRUD,又可以做中間件,現在又可以寫前端。
談談技術選型使用React去做底層的UI繪制,大項目首選React+TS
狀態管理的最佳實踐肯定不是Redux,目前首選dva,或者redux-saga。
構建工具選擇webpack,如果不會webpack真的很吃虧,會嚴重限制你的前端發展,所以建議好好學習Node.js和webpack
選擇了普通的Restful架構,而不是GraphQL,可能我對GraphQL理解不深,沒有領悟到精髓
在通信協議這塊,選擇了websoket和普通的http通信方式
因為是demo,很多地方并沒有細化,后期會針對electron出一個網易云音樂的開源項目,這是一定要做到的
先開始正式的環境搭建config文件放置webpack配置文件
server文件夾放置Node.js的后端服務器代碼
src下放置源碼
main.js是Electron的入口文件
json文件是腳本入口文件,也是包管理的文件~
開發模式項目啟動思路:先啟動webpack將代碼打包到內存中,實現熱更新
再啟動Electron讀取對應的url地址的文件內容,也實現熱更新
設置webpack入口app: ["babel-polyfill", "./src/index.js", "./index.html"], vendor: ["react"] }忽略Electron中的代碼,不用webpack打包(因為Electron中有后臺模塊代碼,打包就會報錯)
externals: [ (function () { var IGNORES = [ "electron" ]; return function (context, request, callback) { if (IGNORES.indexOf(request) >= 0) { return callback(null, "require("" + request + "")"); } return callback(); }; })() ]加入代碼分割
optimization: { runtimeChunk: true, splitChunks: { chunks: "all" } },設置熱更新等
plugins: [ new HtmlWebpackPlugin({ template: "./index.html" }), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), ], mode: "development", devServer: { contentBase: "../build", open: true, port: 5000, hot: true },
#### 加入babel
{ loader: "babel-loader", options: { //jsx語法 presets: ["@babel/preset-react", //tree shaking 按需加載babel-polifill presets從后到前執行 ["@babel/preset-env", { "modules": false, "useBuiltIns": "false", "corejs": 2, }], ], plugins: [ //支持import 懶加載 plugin從前到后 "@babel/plugin-syntax-dynamic-import", //andt-mobile按需加載 true是less,如果不用less style的值可以寫"css" ["import", { libraryName: "antd-mobile", style: true }], //識別class組件 ["@babel/plugin-proposal-class-properties", { "loose": true }], // ], cacheDirectory: true }, }看看主進程的配置文件main.js
// Modules to control application life and create native browser window const { app, BrowserWindow, ipcMain, Tray, Menu } = require("electron") const path = require("path") // 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 app.disableHardwareAcceleration() // ipcMain.on("sync-message", (event, arg) => { // console.log("sync - message") // // event.returnValue("message", "tanjinjie hello") // }) function createWindow() { // Create the browser window. tray = new Tray(path.join(__dirname, "./src/assets/bg.jpg")); tray.setToolTip("wechart"); tray.on("click", () => { mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show() }); const contextMenu = Menu.buildFromTemplate([ { label: "退出", click: () => mainWindow.quit() }, ]); tray.setContextMenu(contextMenu); mainWindow = new BrowserWindow({ width: 805, height: 500, webPreferences: { nodeIntegration: true }, // titleBarStyle: "hidden" frame: false }) //自定義放大縮小托盤功能 ipcMain.on("changeWindow", (event, arg) => { if (arg === "min") { console.log("min") mainWindow.minimize() } else if (arg === "max") { console.log("max") if (mainWindow.isMaximized()) { mainWindow.unmaximize() } else { mainWindow.maximize() } } else if (arg === "hide") { console.log("hide") mainWindow.hide() } }) // and load the index.html of the app. // mainWindow.loadFile("index.html") mainWindow.loadURL("http://localhost:5000"); BrowserWindow.addDevToolsExtension( path.join(__dirname, "./src/extensions/react-dev-tool"), ); // 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 BrowserWindow.removeDevToolsExtension( path.join(__dirname, "./src/extensions/react-dev-tool"), ); }) } // 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() }) // In this file you can include the rest of your app"s specific main process // code. You can also put them in separate files and require them here.今天只講開發模式下的配置,因為實在太多,得分兩篇文章寫了~ 剩下的配置去git倉庫看 在開發模式下啟動項目:
使用 "dev": "webpack-dev-server --config ./config/webpack.dev.js", 將代碼打包到內存中
使用 "start": "electron ." 開啟electron,讀取對應的內存地址中的資源,實現熱更新
項目起來后,在入口處index.js文件中,注入dvaimport React from "react" import App from "./App" import dva from "dva" import Homes from "./model/Homes" import main from "./model/main" const app = dva() app.router(({ history, app: store }) => (這里不得不說redux,redux-sage,dva的區別 直接看圖 首先是Redux)); app.model(Homes) app.model(main) app.start("#root")
React 只負責頁面渲染, 而不負責頁面邏輯, 頁面邏輯可以從中多帶帶抽取出來, 變成 store,狀態及頁面邏輯從
頁面邏輯就是 reducer,
上面說了, 可以使用 Middleware 攔截 action, 這樣一來異步的網絡操作也就很方便了, 做成一個 Middleware 就行了, 這里使用 redux-saga 這個類庫, 舉個栗子:
點擊創建 Todo 的按鈕, 發起一個 type == addTodo 的 action
saga 攔截這個 action, 發起 http 請求, 如果請求成功, 則繼續向 reducer 發一個 type == addTodoSucc 的 action, 提示創建成功, 反之則發送 type == addTodoFail 的 action 即可
最后是: Dva有了前面的三步鋪墊, Dva 的出現也就水到渠成了, 正如 Dva 官網所言, Dva 是基于 React + Redux + Saga 的最佳實踐沉淀, 做了 3 件很重要的事情, 大大提升了編碼體驗:
把 store 及 saga 統一為一個 model 的概念, 寫在一個 js 文件里面
增加了一個 Subscriptions, 用于收集其他來源的 action, eg: 鍵盤操作
model 寫法很簡約, 類似于 DSL 或者 RoR, coding 快得飛起??
約定優于配置, 總是好的
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/114724.html
摘要:是一個使用和等技術創建原生程序的框架,它負責比較難搞的部分,你只需把精力放在你的應用的核心上即可。談談技術選型使用去做底層的繪制,大項目首選狀態管理的最佳實踐肯定不是,目前首選,或者。 showImg(https://segmentfault.com/img/bVbtqlI?w=1308&h=565); 目前Electron在github上面的star量已經快要跟React-nativ...
摘要:調用通過注冊表調用到實例,透過的,調用到中的,最后通過,調用,根據參數相應模塊執行。京東的,多端解決方案是一套遵循語法規范的多端開發解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對于一項技術,我們不能停留在五分鐘狀態,特別喜歡一句話,用什么方式繪制UI界面一點不重要,重要的是底層的思維,解決問題和優化...
摘要:調用通過注冊表調用到實例,透過的,調用到中的,最后通過,調用,根據參數相應模塊執行。京東的,多端解決方案是一套遵循語法規范的多端開發解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對于一項技術,我們不能停留在五分鐘狀態,特別喜歡一句話,用什么方式繪制UI界面一點不重要,重要的是底層的思維,解決問題和優化...
摘要:調用通過注冊表調用到實例,透過的,調用到中的,最后通過,調用,根據參數相應模塊執行。京東的,多端解決方案是一套遵循語法規范的多端開發解決方案。 showImg(https://segmentfault.com/img/bVbuMkw?w=1304&h=808); 對于一項技術,我們不能停留在五分鐘狀態,特別喜歡一句話,用什么方式繪制UI界面一點不重要,重要的是底層的思維,解決問題和優化...
閱讀 3156·2021-11-22 09:34
閱讀 2795·2021-09-22 15:28
閱讀 816·2021-09-10 10:51
閱讀 1852·2019-08-30 14:22
閱讀 2273·2019-08-30 14:17
閱讀 2734·2019-08-30 11:01
閱讀 2295·2019-08-29 17:19
閱讀 3653·2019-08-29 13:17