Ionic3 與Electron製做桌面應用html
ionic:https://ionicframework.comwebpack
electron:https://electron.atom.iogit
ionic是一個混合開發框架,electron是一個開發跨平臺桌面應用的框架。github
此教程包括三個步驟:web
1. 建立ionic項目,開啓服務npm
2. 在項目中添加electron依賴json
3. 添加webpack配置和electron主體腳本以electron的方式運行項目windows
在教程第二部分,首先會建立一個簡單的angular2服務來訪問electron的api;而後給不一樣平臺編譯分包。api
最終源代碼地址:https://github.com/lohanitech/ion-electron
準備工做和預備知識:
1 安裝和了解ionic
2 安裝和了解electron
1. 建立Ionic項目,開啓服務
運行以下命令
ionic start ion-electron
進入ion-electron文件夾運行:
ionic serve
能夠在本地瀏覽器中輸入 http://localhost:8100 預覽效果
2. 在項目中安裝electron依賴
在項目中運行以下命令:
npm install electron electron-builder foreman --save-dev
electron是咱們要整合進來的一個桌面開發
electron-builder用於編譯electron的腳本
foreman用於模擬多進程的node包。
安裝完成後,package.json以下:
"name": "ion-electron", "author": { "name": "Damodar Lohani", "email": "example@example.com", "url": "https://lohanitech.com/members/damodar-lohani" }, "description": "ionic framework based electron project", "main": "electron/electron.js", "config": { "ionic_bundler": "webpack", "ionic_webpack": "./config/webpack.config.js" }, "build": { "appId": "com.lohanitech.ionic-electron-test", "electronVersion": "1.7.5", "asar":false, "files": [ "www/**/*", "electron/*" ] }
3. 添加webpack配置和electron主體腳本以electron的方式運行項目
在項目中新建一個文件夾名爲config,並在其中加入一個文件名爲webpack.config.js,將以下代碼複製進去。
首先是ionic相關的配置,(目前位於 node_modules/@ionic/app-scripts/config/webpack.config.js),在源文件中加入:
externals: [ (function () { var IGNORES = ["fs","child_process","electron","path","assert","cluster","crypto","dns","domain","events","http","https","net","os","process","punycode","querystring","readline","repl","stream","string_decoder","tls","tty","dgram","url","util","v8","vm","zlib"]; return function (context, request, callback) { if (IGNORES.indexOf(request) >= 0) { return callback(null, "require('" + request + "')"); } return callback(); }; })() ],
最新的webpack配置變爲以下(最新的配置文件咱們須要在dev配置和production配置中添加):
/* * The webpack config exports an object that has a valid webpack configuration * For each environment name. By default, there are two Ionic environments: * "dev" and "prod". As such, the webpack.config.js exports a dictionary object * with "keys" for "dev" and "prod", where the value is a valid webpack configuration * For details on configuring webpack, see their documentation here * https://webpack.js.org/configuration/ */ var path = require('path'); var webpack = require('webpack'); var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY); var ModuleConcatPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin'); var PurifyPlugin = require('@angular-devkit/build-optimizer').PurifyPlugin; var optimizedProdLoaders = [ { test: /\.json$/, loader: 'json-loader' }, { test: /\.js$/, loader: [ { loader: process.env.IONIC_CACHE_LOADER }, { loader: '@angular-devkit/build-optimizer/webpack-loader', options: { sourceMap: true } }, ] }, { test: /\.ts$/, loader: [ { loader: process.env.IONIC_CACHE_LOADER }, { loader: '@angular-devkit/build-optimizer/webpack-loader', options: { sourceMap: true } }, { loader: process.env.IONIC_WEBPACK_LOADER } ] } ]; function getProdLoaders() { if (process.env.IONIC_OPTIMIZE_JS === 'true') { return optimizedProdLoaders; } return devConfig.module.loaders; } var devConfig = { entry: process.env.IONIC_APP_ENTRY_POINT, output: { path: '{{BUILD}}', publicPath: 'build/', filename: '[name].js', devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(), }, externals: [ (function () { var IGNORES = ["fs","child_process","electron","path","assert","cluster","crypto","dns","domain","events","http","https","net","os","process","punycode","querystring","readline","repl","stream","string_decoder","tls","tty","dgram","url","util","v8","vm","zlib"]; return function (context, request, callback) { if (IGNORES.indexOf(request) >= 0) { return callback(null, "require('" + request + "')"); } return callback(); }; })() ], devtool: process.env.IONIC_SOURCE_MAP_TYPE, resolve: { extensions: ['.ts', '.js', '.json'], modules: [path.resolve('node_modules')] }, module: { loaders: [ { test: /\.json$/, loader: 'json-loader' }, { test: /\.ts$/, loader: process.env.IONIC_WEBPACK_LOADER } ] }, plugins: [ ionicWebpackFactory.getIonicEnvironmentPlugin(), ionicWebpackFactory.getCommonChunksPlugin() ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. node: { fs: 'empty', net: 'empty', tls: 'empty' } }; var prodConfig = { entry: process.env.IONIC_APP_ENTRY_POINT, output: { path: '{{BUILD}}', publicPath: 'build/', filename: '[name].js', devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(), }, externals: [ (function () { var IGNORES = ["fs","child_process","electron","path","assert","cluster","crypto","dns","domain","events","http","https","net","os","process","punycode","querystring","readline","repl","stream","string_decoder","tls","tty","dgram","url","util","v8","vm","zlib"]; return function (context, request, callback) { if (IGNORES.indexOf(request) >= 0) { return callback(null, "require('" + request + "')"); } return callback(); }; })() ], devtool: process.env.IONIC_SOURCE_MAP_TYPE, resolve: { extensions: ['.ts', '.js', '.json'], modules: [path.resolve('node_modules')] }, module: { loaders: getProdLoaders() }, plugins: [ ionicWebpackFactory.getIonicEnvironmentPlugin(), ionicWebpackFactory.getCommonChunksPlugin(), new ModuleConcatPlugin(), new PurifyPlugin() ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. node: { fs: 'empty', net: 'empty', tls: 'empty' } }; module.exports = { dev: devConfig, prod: prodConfig }
這是ionic的webpack配置,只需稍做改動就能夠與electron一塊兒使用了。
添加election主腳本
在項目內建立一個文件夾名爲electron,在其中新建一個electron.js。這個是建立和加載electron窗口的主腳本。打開electron.js,貼入如下代碼:
'use strict'; const electron = require('electron'); // Module to control application life. const { app } = electron; // Module to create native browser window. const { BrowserWindow } = electron; let win; function createWindow() { // Create the browser window. win = new BrowserWindow({ width: 1024, height: 600 }); var url = 'file://' + __dirname + '/../www/index.html'; var Args = process.argv.slice(2); Args.forEach(function (val) { if (val === "test") { url = 'http://localhost:8100' } }); // and load the index.html of the app. win.loadURL(url); // Open the DevTools. win.webContents.openDevTools(); // Emitted when the window is closed. win.on('closed', () => { // 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. win = 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', () => { // On OS X 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', () => { // On OS X 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 (win === null) { createWindow(); } });
在package.json中加入啓動腳本
在package.json的scripts中貼入如下代碼:
"scripts": { "dev": "nf start", "start":"ionic-app-scripts serve", "electron dist": "electron .", "ebuild":"npm run build && node_modules/.bin/build", "clean": "ionic-app-scripts clean", "build": "ionic-app-scripts build", "ionic:build": "ionic-app-scripts build", "ionic:serve": "ionic-app-scripts serve" }
因爲如今加入了foreman,咱們須要給他添加配置。在項目根目錄下新建文件Procfile,貼入代碼:
ionic: npm start
electron: node electron-wait-ionic.js
在根目錄下新建electron-wait-ionic.js,更新以下:
const net = require('net'); const port = 8100; process.env.E_URL = `http://localhost:${port}`; const client = new net.Socket(); let startedElectron = false; const tryConnection = () => client.connect({port: port}, () => { client.end(); if(!startedElectron) { console.log('starting electron'); startedElectron = true; const exec = require('child_process').exec; exec('electron .'); } } ); tryConnection(); client.on('error', (error) => { setTimeout(tryConnection, 1000); });
這個腳本的做用是嘗試鏈接端口8100,由於8100端口在electron接入的時候會激活。若是鏈接失敗會接着鏈接。
此時,運行npm run dev會以開發模式運行項目。
因爲electron在徹底編譯以前會運行服務,因此第一次可能會看到空白頁面,發生這種狀況的話能夠根據console輸出信息,在編譯完成後按ctrl+r從新加載electron窗口便可。
正常工做的效果圖以下:
完成此教程能夠查看第二部分來學習如何在Ionic項目中訪問electron的api。