mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
extensions-api -- loading extension modules -- part 1
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
1e08b01423
commit
b2414542b8
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,5 @@ static/build/**
|
|||||||
binaries/client/
|
binaries/client/
|
||||||
binaries/server/
|
binaries/server/
|
||||||
src/extensions/**/*.js
|
src/extensions/**/*.js
|
||||||
|
src/extensions/**/*.d.ts
|
||||||
locales/**/**.js
|
locales/**/**.js
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
"compile:main": "webpack --config webpack.main.ts",
|
"compile:main": "webpack --config webpack.main.ts",
|
||||||
"compile:renderer": "webpack --config webpack.renderer.ts",
|
"compile:renderer": "webpack --config webpack.renderer.ts",
|
||||||
"compile:i18n": "lingui compile",
|
"compile:i18n": "lingui compile",
|
||||||
|
"compile-extensions": "tsc --project src/extensions --watch",
|
||||||
"build:linux": "yarn compile && electron-builder --linux --dir -c.productName=Lens",
|
"build:linux": "yarn compile && electron-builder --linux --dir -c.productName=Lens",
|
||||||
"build:mac": "yarn compile && electron-builder --mac --dir -c.productName=Lens",
|
"build:mac": "yarn compile && electron-builder --mac --dir -c.productName=Lens",
|
||||||
"build:win": "yarn compile && electron-builder --win --dir -c.productName=Lens",
|
"build:win": "yarn compile && electron-builder --win --dir -c.productName=Lens",
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
import { LensExtension } from "@lens"; // fixme: provide runtime import
|
// import { LensExtension } from "@lens"; // fixme: provide runtime import
|
||||||
|
|
||||||
export default class ExampleExtension extends LensExtension {
|
export default class ExampleExtension /*extends LensExtension*/ {
|
||||||
async init(): Promise<any> {
|
async init(): Promise<any> {
|
||||||
console.log('Example extension: init')
|
console.log('Example extension: init')
|
||||||
return super.init();
|
// return super.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const someData = {
|
||||||
|
title: "it works"
|
||||||
|
}
|
||||||
@ -4,7 +4,6 @@ import { action, comparer, observable, toJS } from "mobx";
|
|||||||
import { BaseStore } from "../common/base-store";
|
import { BaseStore } from "../common/base-store";
|
||||||
import { ExtensionId, ExtensionManifest, ExtensionVersion, LensExtension } from "./extension";
|
import { ExtensionId, ExtensionManifest, ExtensionVersion, LensExtension } from "./extension";
|
||||||
import { isDevelopment } from "../common/vars";
|
import { isDevelopment } from "../common/vars";
|
||||||
import logger from "../main/logger";
|
|
||||||
|
|
||||||
export interface ExtensionStoreModel {
|
export interface ExtensionStoreModel {
|
||||||
version: ExtensionVersion;
|
version: ExtensionVersion;
|
||||||
@ -24,7 +23,10 @@ export interface ExtensionModel {
|
|||||||
export interface InstalledExtension<T extends ExtensionModel = any> {
|
export interface InstalledExtension<T extends ExtensionModel = any> {
|
||||||
manifestPath: string;
|
manifestPath: string;
|
||||||
manifest: ExtensionManifest;
|
manifest: ExtensionManifest;
|
||||||
LensExtension: new (model: T, manifest?: ExtensionManifest) => LensExtension;
|
extensionModule: {
|
||||||
|
[name: string]: any;
|
||||||
|
default: new (model: T, manifest?: ExtensionManifest) => LensExtension
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
|
export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
|
||||||
@ -56,15 +58,16 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
|
|||||||
let mainJs: string;
|
let mainJs: string;
|
||||||
try {
|
try {
|
||||||
manifestJson = __non_webpack_require__(manifestPath); // eslint-disable-line
|
manifestJson = __non_webpack_require__(manifestPath); // eslint-disable-line
|
||||||
mainJs = path.resolve(path.dirname(manifestPath), manifestJson.main); // todo: compile *.ts on the fly?
|
mainJs = path.resolve(path.dirname(manifestPath), manifestJson.main);
|
||||||
const LensExtension = __non_webpack_require__(mainJs).default; // eslint-disable-line
|
mainJs = mainJs.replace(/\.ts$/i, ".js"); // todo: compile *.ts on the fly?
|
||||||
|
const extensionModule = __non_webpack_require__(mainJs); // eslint-disable-line
|
||||||
return {
|
return {
|
||||||
manifestPath: manifestPath,
|
manifestPath: manifestPath,
|
||||||
manifest: manifestJson,
|
manifest: manifestJson,
|
||||||
LensExtension: LensExtension,
|
extensionModule: extensionModule,
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`[EXTENSION-STORE]: can't load extension at ${manifestPath}: ${err}`, { manifestJson, mainJs });
|
console.error(`[EXTENSION-STORE]: can't load extension at ${manifestPath}: ${err}`, { manifestJson, mainJs });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +88,7 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
|
|||||||
});
|
});
|
||||||
let extensions = await Promise.all(manifestsLoading);
|
let extensions = await Promise.all(manifestsLoading);
|
||||||
extensions = extensions.filter(v => !!v); // filter out files and invalid folders (without manifest.json)
|
extensions = extensions.filter(v => !!v); // filter out files and invalid folders (without manifest.json)
|
||||||
logger.info(`[EXTENSION-STORE]: ${extensions.length} extensions loaded`, { folderPath, extensions });
|
console.info(`[EXTENSION-STORE]: ${extensions.length} extensions loaded`, { folderPath, extensions });
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,16 +119,17 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
|
|||||||
currentExtensions.forEach(model => {
|
currentExtensions.forEach(model => {
|
||||||
const manifest = this.installed.get(model.manifestPath);
|
const manifest = this.installed.get(model.manifestPath);
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
logger.error(`[EXTENSION-STORE]: can't load extension manifest at ${model.manifestPath}`, { model })
|
console.error(`[EXTENSION-STORE]: can't load extension manifest at ${model.manifestPath}`, { model })
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const extension = this.getById(model.id)
|
const extension = this.getById(model.id)
|
||||||
if (!extension) {
|
if (!extension) {
|
||||||
try {
|
try {
|
||||||
const { LensExtension, manifest: manifestJson } = manifest;
|
const { manifest: manifestJson, extensionModule } = manifest;
|
||||||
|
const LensExtension = extensionModule.default;
|
||||||
this.extensions.set(model.id, new LensExtension(model, manifestJson));
|
this.extensions.set(model.id, new LensExtension(model, manifestJson));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`[EXTENSION-STORE]: init extension failed: ${err}`, { model, manifest })
|
console.error(`[EXTENSION-STORE]: init extension failed: ${err}`, { model, manifest })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
extension.importModel(model);
|
extension.importModel(model);
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
|
import type { ExtensionModel } from "./extension-store";
|
||||||
import { readJsonSync } from "fs-extra";
|
import { readJsonSync } from "fs-extra";
|
||||||
import { action, observable, when } from "mobx";
|
import { action, observable, when } from "mobx";
|
||||||
import { ExtensionModel } from "./extension-store";
|
|
||||||
import extensionManifest from "./example-extension/package.json"
|
import extensionManifest from "./example-extension/package.json"
|
||||||
import logger from "../main/logger";
|
import logger from "../main/logger";
|
||||||
|
|
||||||
// TODO: extensions api
|
// TODO: extensions api
|
||||||
// * Lazy load/unload extension (js/ts?) (from sources: local folder, npm_modules/@lens/some_plugin, etc.)
|
// - figure out how to expose/inject lens apis to extension:
|
||||||
// * figure out how to expose lens external apis to extension:
|
// -- replace import "@lens" to real path to "build/Lens.js" or maybe "build/Lens-extensions.api.js"
|
||||||
// - opt1: import {someApi} from "@lens" => replaced to import from "$PATH/build/Lens.js" on the fly ?
|
// -- load extension via NodeJS.require() / webContents.executeJavaScript()
|
||||||
// - opt2: dynamic require() / contents.executeJavaScript / etc. ?
|
|
||||||
|
|
||||||
export type ExtensionId = string;
|
export type ExtensionId = string;
|
||||||
export type ExtensionVersion = string | number;
|
export type ExtensionVersion = string | number;
|
||||||
|
|||||||
20
src/extensions/tsconfig.json
Normal file
20
src/extensions/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "react",
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "CommonJS",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"allowJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"declaration": true
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"./example-extension/example-extension.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user