LoginSignup
1
1

More than 1 year has passed since last update.

Angular 12 で Electron によるデスクトップアプリ化

Posted at

すでに Angular プロジェクトが作成されているものとする

参考サイト

環境

Angular バージョン

ng version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 12.2.10
Node: 14.15.1
Package Manager: npm 8.1.0
OS: darwin x64

Angular: 12.2.10
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, localize, material, platform-browser
... platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1200.5
@angular-devkit/build-angular   12.2.10
@angular-devkit/core            12.0.5
@angular-devkit/schematics      12.2.10
@angular/fire                   6.1.5
@schematics/angular             12.2.10
rxjs                            6.6.7
typescript                      4.3.5

モジュールの追加

@types/node を新しいバージョンに上げておく

    "@types/node": "^14.15.5",

Angular12 で electron を実装するのに必要なモジュールを追加する

package.json
"dependencies" or "devDependencies": {
...
    "ngx-electron": "^2.2.0",
    "ts-loader": "^9.2.5",
    "concurrently": "^6.2.1",
    "electron": "^13.2.0",
    "electron-log": "4.4.1",
    "electron-packager": "^15.3.0",
    "webpack-cli": "^4.8.0",
    "webpack-node-externals": "^3.0.0"
}

webpack.**.config.js の追加

image.png

webpack.electron.config.js
const path = require('path');
const { ProgressPlugin } = require('webpack');

const src = path.join(process.cwd(), 'src', 'electron');

module.exports = {
  resolve: {
    extensions: [
      '.ts',
      '.js'
    ]
  },
  entry: {
    main: path.join(src, 'main.ts')
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          configFile: path.join(src, 'tsconfig.json')
        }
      }
    ]
  },
  plugins: [
    new ProgressPlugin()
  ],
  // indicates that transpilation code is to be run in the main process
  target: 'electron-main'
};
webpack.electron.dev.config.js
const path = require('path');
const baseConfig = require('./webpack.electron.config');

module.exports = {
  ...baseConfig,
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.join(process.cwd(), 'dist'),
    // avoid conflicts with the `main.js` file generated from the Angular CLI
    filename: 'shell.js'
  }
};
webpack.electron.prod.config.js
const path = require('path');
const nodeExternals = require('webpack-node-externals');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const baseConfig = require('./webpack.electron.config');

module.exports = {
  ...baseConfig,
  mode: 'production',
  output: {
    path: path.join(process.cwd(), 'dist'),
    filename: 'main.js'
  },
  plugins: [
    // the electron-packager requires a valid `package.json` file along with the Electron code
    new CopyWebpackPlugin({
      patterns: [
        {
          context: path.join(process.cwd(), 'src', 'electron'),
          from: 'package.json'
        }
      ]
    })
  ],
  // Indicate that we do not want to bundle modules from 3rd party libraries automatically, as part of ES6 imports.
  // Instead we must define them in the `dependencies` property of the `package.json` file and will be installed
  // using the `package` npm script
  externals: [nodeExternals()]
};

npm run の スクリプトを追加

package.json
  "scripts": {
...
    "build:dev": "concurrently \"ng build --delete-output-path=false --watch\" \"webpack --config webpack.electron.dev.config.js --watch\"",
    "start:dev": "electron dist/shell.js",
    "build:prod": "ng build --optimization --outputHashing=all --sourceMap=false --namedChunks=false --extract-licenses --vendorChunk=false --build-optimizer && webpack --config webpack.electron.prod.config.js",
    "start:prod": "electron dist/main.js"
  }

テストする時は
For the desktop version run:

npm run build:dev
npm run start:dev

electron 起動用の main.ts を用意する

image.png

src/electron/main.ts
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
import * as fs from 'fs';
import log from 'electron-log';

log.info(`${app.name} ${app.getVersion()}`);

function createWindow () {
  const mainWindow = new BrowserWindow({
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  });
  mainWindow.maximize();
  mainWindow.webContents.openDevTools();
  mainWindow.loadFile('index.html');
}

app.whenReady().then(() => {
  createWindow();
});

// Angular -> Electron
ipcMain.on('selectPirate', async (event: Electron.IpcMainEvent, name: string) => {
    await dialog.showMessageBox({ message: 'You selected: ' + name });
    event.returnValue = true;
});
src/electron/package.json
{
    "name": "angular-electron-sample",
    "description": "Angular Electron Sample",
    "version": "0.0.0",
    "author": {
      "name": "Aristeidis Bampakos"
    },
    "main": "main.js",
    "dependencies": {
      "electron-log": "4.3.1"
    }
}
src/electron/tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "importHelpers": false
  },
  "include": [
    "**/*.ts"
  ]
}

テスト

ビルドしてみる

build:dev

Jan-30-2022 09-45-18.gif

最後フリーズした状態になるけど気にせず ctrl+c で強制終了する

起動してみる

start:dev

Electron用の動作 を Angule アプリに追加する

app.module に追加

src/app/app.module.ts
import { ElectronService, NgxElectronModule } from "ngx-electron";

...

@NgModule({
  imports: [

    NgxElectronModule
  ],
  providers: [

    ElectronService
  ]

electron を使うコンポーネントに追加

**.component.ts
import { ElectronService } from 'ngx-electron';

  constructor(
    public electronService: ElectronService
   ) {}

  // electron を使う関数
  public use_electron(): void{
    if(this.electronService.isElectronApp) {
      this.electronService.ipcRenderer.sendSync('selectPirate', 'hogehoge');
    }
  }

おわりに

Angular 12 では なかなか情報がみつからなかったので書きました

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1