Electron plugin architecture, inject plugin code into the application - electron

As the title say, I am trying to develop a plugin architecture for an electron app.
So far I have handle my custom plugin store the download of the plugin source which consist of an single main.js and a style.css.
I am stuck now since I don't know how to "require" the file from my application.
A little more explanation on this main.js file:
I want to require that main.js file to that I can retrieve the exported class to create a new instance in my PluginManager system.
It would be like so:
// plugin-manager.ts
loadPlugin(pluginId: string) {
const pluginClass = await import(path.join('/somewhere-in-the-fs', pluginId));
const plugin = new PluginClass({ app: myApp });
this.enabledPlugins.push(plugin);
}
tldr: I'm stuck at the await import() part because obviously my plugin is not in my running node environment.

Related

How to read config file in electronjs app

It's my first time using Electron JS and nodejs. I've built a small app that reads some records from a database and updates them. Everything is working fine. I have a config file with the database credentials but when I build a portable win app, I cannot figure out how to read the config file that I would like to place next to the exe. I would like to have easy access to the file, so I could run the same app on different databases.
Can anyone tell me if what I want is possible and how? I already tried to get the exe location but I couldn't. I also read a lot of topics here but nothing seems to solve my problem (I might be doing something wrong).
I'm using electron-builder to build my app.
Thanks in advance.
Edit #1
My Config file is
{
"user" :"X",
"password" :"X",
"server":"X",
"database":"X",
"options":
{
"trustedconnection": true,
"enableArithAbort" : true,
"trustServerCertificate": true
}
}
This is what I've and works when I run the project with npm start
const configRootPath = path.resolve(__dirname,'dbConfig.json');
dbConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' }));
However, when I build it, the app is looking for the file in another location different from the one where the executable is.
Use of Electron's app.getPath(name) function will get you the path(s) you are after, irrespective of which OS (Operating System) you are using.
Unless your application writes your dbConfig.json file, it may be difficult for your user to understand exactly where they should place their database config file as each OS will run and store your application data in a different directory. You would need to be explicit to the user as to where to place their config file(s). Alternatively, your application could create the config file(s) on the user's behalf (automatically or through a html form) and save it to a location 'known' to the application.
A common place where application specific config files are stored is in the user's application data directory. With the application name automatically amended to the directory, it can be found as shown below.
const electronApp = require('electron').app;
let appUserDataPath = electronApp.getPath('userData');
console.log(appUserDataPath );
In your use case, the below would apply.
const electronApp = require('electron').app;
const nodeFs = require('fs');
const nodePath = require('path');
const configRootPath = nodePath.join(electronApp.getPath('userData'), 'dbConfig.json');
dbConfig = JSON.parse(nodeFs.readFileSync(configRootPath, 'utf-8'));
console.log(configRootPath);
console.log(dbConfig);
You can try electron-store to store config.
Electron doesn't have a built-in way to persist user preferences and other data. This module handles that for you, so you can focus on building your app. The data is saved in a JSON file named config.json in app.getPath('userData').

NestJs Swagger how to add custom favicon

I am trying to add a custom favicon to my NestJs documentation. However, I am a bit lost on how the path file gets resolved and not sure how to achieve this.
I am using nestjs/swagger module version 3.1.0 and trying to pass the path file like so when initializing the Swagger Module.
My main.ts file
SwaggerModule.setup('/v1/docs', app, document, {
customCss: CUSTOM_STYLE,
customSiteTitle: 'My API Documentation',
customfavIcon: './public/favicon.jpg'
});
Searched on the github issues and didn't find anything useful. And as you can see from the code I was able to modify the CSS styles, but I cannot figure out how to make the favicon custom.
Appreciate any help
I have added the custom favicon to my swagger docs using following:
The first thing you make sure is, in your main.ts, the app is initialized with the following:
const app: NestExpressApplication = await NestFactory.create(...)
To serve static content you must initialize your app with NestExpressApplication.
The next thing is to allow the Nest application to look for public content using the following in your main.ts after initialization:
app.useStaticAssets(join(__dirname, '..', 'public'));
Also, create a public directory in your root of the application and paste your favicon.jpg file in it.
Now its time to initialize the Swagger in main.ts
SwaggerModule.setup('/v1/docs', app, document, {
customCss: CUSTOM_STYLE,
customSiteTitle: 'My API Documentation',
customfavIcon: '../favicon.jpg'
});
You must give a relative path to the root of the application like ../favicon.jpg in case our main.ts is in src folder in root of the application.
Alternative solution, just host your favicon and reference it with external url
SwaggerModule.setup('api', app, getSwaggerDocument(app), {
...
customfavIcon:
'https://[your-bucket-url].com/.../anything.png',
});
To iterate on pravindot17's answer, now there's the #nestjs/serve-static package for hosting static files. Which avoid us from type-casting the Nest.js client and relying on our implicit assumption that we're running an Express-backed Nest.js server.
After installing the package, you hook it into your src/app.module.ts. This configuration expects that the root of your project has a /public/ folder where you store your static assets.
import { Module } from '#nestjs/common';
import { ServeStaticModule } from '#nestjs/serve-static';
import { join } from 'path';
#Module({
imports: [
// Host static files in ../public under the /static path.
ServeStaticModule.forRoot({
/**
* Config options are documented:
* https://github.com/nestjs/serve-static/blob/master/lib/interfaces/serve-static-options.interface.ts
*/
rootPath: join(__dirname, '..', '..', 'public'),
serveRoot: '/static',
}),
// ...
})
export class AppModule {}
Now my own preference is using an absolute path rather than relative, as it makes it independent from the path we picked to host our API documentation under.
SwaggerModule.setup('/v1/docs', app, document, {
customfavIcon: '/static/favicon.jpg'
});
One last note is that this configuration hosts static files from /static/*, this is done to prevent that API calls to non-existing endpoints show an error message to the end-user that the static file cannot be found.
Otherwise, all 404's on non-existing endpoints will look something like:
{"statusCode":404,"message":"ENOENT: no such file or directory, stat '/Users/me/my-project/public/index.html'"}

Generate seperate build file for a particular component in angular 7

I am going to develop a very large application using Angular 7 Framework.
I have created a blank angular workspace using
ng new angular-app --create-application=false
And in this workspace I have two angular applications created using the following commands:
ng generate application app-one
ng generate application app-two
Inside each of the two applications, I am going to have multiple components each working independently of each other.
I am looking for a way to create a separate javascript build file for each of the component so as to reduce the build size.
And use each of the separately build js files to use each component as a web component.
Please read what I have already tried to get a better idea.
I have tried the following steps:
Create a repository with prefix custom for custom angular elements:
ng new app-name --prefix custom
Add the angular elements package:
ng add #angular/elements
Create custom element component with encapsulation as native/emulated/none as required:
ng g component my-component --inline-style --inline-template -v Native
Define the custom element in app.modulte.ts
import { Injector} from '#angular/core';
import { createCustomElement } from '#angular/elements';
...
export class AppModule {
constructor(private injector : Injector){
const el = createCustomElement(MyComponent, {injector : this.injector});
customElements.define('my-component',el);
}
ngDoBootstrap(){ }
}
Install ngx-build-plus package for building a single bundle (e. g. for Angular Elements):
npm i ngx-build-plus
Update application's builder section within the angular.json file so that it points to ngx-build-plus:
"builder": "ngx-build-plus:build",
Add script in package.json to run builder:
"build:ngx": "ng build --prod --output-hashing none --single-bundle true"
If required, Combine scripts.js and main.js in the created dist folder by creating a js file "concat_ngx.js":
const fs = require('fs-extra');
const concat = require('concat');
(async function build() {
const files = [
'./dist/<your_project>/scripts.js',
'./dist/<your_project>/main.js',
]
await fs.ensureDir('elements_ngx')
await concat(files, 'elements_ngx/combined-script.js');
})()
Run file to get single js file:
node concat_ngx.js
Use js file in any Angular/Other project to use the custom component created.
But the problem here is I have to change the component bootstrap every time in app-module.ts
I needed an automated way to change the bootstrapping in app-module.ts at runtime.
But the problem here is I have to change the component bootstrap every time in app-module.ts
I needed an automated way to change the bootstrapping in app-module.ts at runtime.
In Angular 7, Add Default or Automatic bootstrapping :-
It is the default way an angular application bootstraps and main.ts holds the starting point of an application.
platformBrowserDynamic().bootstrapModule(AppModule);
For more information see here: -https://medium.com/learnwithrahul/ways-of-bootstrapping-angular-applications-d379f594f604
ng serve -o app-one
or
ng serve -o app-two
For more information see here https://medium.com/#klauskpm/change-the-default-angular-project-27da8fca8721

Aurelia: using es6 import for electron + typescript

I have an aurelia application running in electron. My source files are typescript and I have ambient typings for electron and node.
Because I know I'm compiling for use on electron, I am transpiling my typescript to es6 and with System module loading; this means I can turn system.js's transpiler off. I'm using system.js and jspm because that is approach Aurelia has been pushing.
So in my ts files: I would like to be able to do:
import {remote} from 'electron';
Unfortunately, system.js does not know anything about the module electron and fails during runtime. TypeScript on the other hand is perfectly happy because I've set up the typings for electron and node; I get full intellisense in VSCode too.
note: if you attempt to do var electron = require('electron'); in the header, system.js interferes with it and it fails to load. You can place that 'require('electron')' within a class or function and it will work, but I don't find this ideal.
Question: How can I get system.js to correctly return the 'electron' module that is only available when you run the app in electron itself?
A solution --hopefully there is a better way-- I've come up with is to shim the electron module for system.js and link it directly to the contents of require('electron'):
electron.js
System.register([], function (exports_1, context_1) {
"use strict";
var __moduleName = context_1 && context_1.id;
var electron;
return {
setters: [],
execute: function () {
electron = require('electron');
exports_1("default", electron);
Object.keys(electron).forEach(function (key) {
exports_1(key, electron[key]);
});
}
}
});
this effectively wraps the internal electron module and allows system.js to know about it. It works; but hopefully there is a more elegant/built-in way that others know of.
You don't need any mappings or changes to the typescypt as import {remote} from 'electron' will attempt to resolve electron.js as a last resort.

How build Vaadin project with gradle?

I have gradle project (backend) and I want to add Vaadin-based frontend. But I haven't find any gradle-plugins for Vaadin.
While, as was already mentioned above, Vaadin app is a simple web application and does not require any additional plugins but "java" and "war" (and maybe "jetty" to run the app), currently there seems to be the first vaadin-specific gradle plugin available:
https://github.com/johndevs/gradle-vaadin-plugin
It will help you with Vaadin-specific task like building widgetsets, creating components skeletons, etc.
I think there is no a Vaadin plugin for Gradle but I have used Gradle in one of my Vaadin add-on projects: SplitButton. It's a project with sub-projects, widgetset compilation and it writes necessary jar manifest entries neebed by Vaadin Directory.
EDIT
Actually there is Gradle Vaadin plugin now - it allows you to easily build Vaadin projects with Gradle. It helps with the most tedious tasks when building a Vaadin project like building the widgetset and running development mode. It also helps you to quickly get started by providing tasks for project, component and theme creation:
https://github.com/johndevs/gradle-vaadin-plugin
You don't need a Vaadin plugin. A Vaadin application is simply a web application.The war plugin will suffice. If you want support for automatically creating the folder layout that Vaadin wants however, you might look into using the vaadin eclipse plugin found here:
http://vaadin.com/eclipse
If you are looking for deployment support, you can simply use the jetty plugin that comes with gradle or the tomcat plugin found here
https://github.com/bmuschko/gradle-tomcat-plugin
If you need to create custom widgets and compile them into a widgetset that's a GWT compile
https://vaadin.com/book/vaadin6/-/page/gwt.development.html#gwt.development.compiler
Note: The Vaadin7 Book no longer has the section on developing Gwt widgets.
There is a gradle plugin for GWT that could help with that. However, I've not needed a custom widget yet, so I haven't actually tried it.
https://github.com/markuskobler/gwt-gradle-plugin
This post:
Using Gradle with Vaadin
looks very comprehensive as far as Gradle+Vaadin setup goes. I'm also including a link to another Vaadin-based 'build.gradle' file I found on my travels, using Google's very useful 'filetype' search (see also the associated gradle.properties file).
JFYI that Google file search is:
filetype:<extension> <your search phrases>
Gradle can also be used to configure Eclipse and IntelliJ's project files by using a fragment such as the following (Eclipse natures can be 'found' by using the above Google file search for "project" extension and "natures" search, etc.):
//Template plugin - Great for project-layout setup - See http://tellurianring.com/wiki/gradle/templates
apply from: 'http://launchpad.net/gradle-templates/trunk/latest/+download/apply.groovy'
apply plugin: 'eclipse'
apply plugin: 'idea'
// if you want to distribute the gradle with your code
task('wrapper', type: Wrapper).configure {
gradleVersion = '1.0-milestone-8a'
}
def versionCompatibility = 1.6
//configurations.providedDependencies.extendsFrom configurations.gwt
eclipse {
project {
comment = ""
buildCommand "org.eclipse.jdt.core.javabuilder"
buildCommand "org.eclipse.wst.jsdt.core.javascriptValidator"
buildCommand "org.eclipse.wst.common.project.facet.core.builder"
buildCommand "org.eclipse.wst.validation.validationbuilder"
buildCommand "com.vaadin.integration.eclipse.widgetsetBuilder"
//buildCommand "org.eclipse.m2e.core.maven2Builder"
//buildCommand "org.maven.ide.eclipse.maven2Builder"
//buildCommand "com.google.gdt.eclipse.core.webAppProjectValidator"
//buildCommand "com.google.gwt.eclipse.core.gwtProjectValidator"
//buildCommand "com.google.gdt.eclipse.designer.GWTBuilder"
//Don't forget commas - no trailing
natures "org.eclipse.jdt.core.javanature",
"com.vaadin.integration.eclipse.widgetsetNature",
"org.eclipse.wst.jsdt.core.jsNature",
"org.eclipse.wst.common.project.facet.core.nature",
"org.eclipse.wst.common.modulecore.ModuleCoreNature",
"org.eclipse.jem.workbench.JavaEMFNature"
//"org.eclipse.m2e.core.maven2Nature",
//"org.maven.ide.eclipse.maven2Nature",
//"com.google.gwt.eclipse.core.gwtNature"
//"com.google.gdt.eclipse.designer.GWTNature",
//"ch.epfl.lamp.sdt.core.scalanature",
//"com.springsource.sts.grails.core.nature",
//"org.eclipse.jdt.groovy.core.groovyNature"
}
classpath {
containers "com.google.gwt.eclipse.core.GWT_CONTAINER"
//"com.springsource.sts.gradle.classpathcontainer"
//minusConfigurations=[configurations.gwt]
}
}
idea {
project {
jdkName = versionCompatibility
ipr {
withXml { provider ->
def node = provider.asNode()
// Set Gradle home
def gradleSettings = node.appendNode('component', [name: 'GradleSettings'])
gradleSettings.appendNode('option', [name: 'SDK_HOME', value: gradle.gradleHomeDir])
}
}
}
}
Cheers
Rich

Resources