zoukankan      html  css  js  c++  java
  • Ionic3 与Electron制作桌面应用

    Ionic3 与Electron制作桌面应用

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

    ionic:https://ionicframework.com

    electron:https://electron.atom.io

    ionic是一个混合开发框架,electron是一个开发跨平台桌面应用的框架。

    此教程包括三个步骤:

    1. 创建ionic项目,开启服务

    2. 在项目中添加electron依赖

    3. 添加webpack配置和electron主体脚本以electron的方式运行项目

    在教程第二部分,首先会创建一个简单的angular2服务来访问electron的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({
    
             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

  • 相关阅读:
    属性注入(依赖注入)
    Spring之ioc
    Spring初始案例
    ::before和::after伪元素、:visited和:link、transform: scaleX(2);的使用
    给博客博文加上日期分类(set、map)
    Jquery父子选取心得
    先从css3开始拾起
    尝试博客文章一号
    Response.setContentType()
    pom配置详解
  • 原文地址:https://www.cnblogs.com/adoontheway/p/7827962.html
Copyright © 2011-2022 走看看