Ionic3 與Electron製做桌面應用

Ionic3 與Electron製做桌面應用html

原文:https://medium.com/@LohaniDamodar/lets-make-desktop-application-with-ionic-3-and-electron-44316f82901dnode

 

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

相關文章
相關標籤/搜索