From 516b58c09f63c66153b2466d9b011e511cf1c78f Mon Sep 17 00:00:00 2001 From: Mtpc <11539268+mtpc@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:02:05 +0200 Subject: [PATCH] add support for includePlugins in capacitor config --- src/cli-scripts/common.ts | 136 +++++++++++++++++-- src/electron-platform-template/tsconfig.json | 1 + 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/cli-scripts/common.ts b/src/cli-scripts/common.ts index 9ddb73f5..38074acb 100644 --- a/src/cli-scripts/common.ts +++ b/src/cli-scripts/common.ts @@ -1,11 +1,13 @@ import type { CapacitorConfig } from '@capacitor/cli'; +import type typescript from 'typescript'; import chalk from 'chalk'; import { exec } from 'child_process'; import { createHash } from 'crypto'; -import { readFileSync, existsSync, writeFileSync } from 'fs'; +import { existsSync, writeFileSync } from 'fs'; import type { Ora } from 'ora'; import ora from 'ora'; import { dirname, join, parse, resolve } from 'path'; +import { pathExists, readFileSync } from '@ionic/utils-fs'; const enum PluginType { Core, @@ -43,12 +45,19 @@ export interface Plugin { }; } +export const CONFIG_FILE_NAME_TS = 'capacitor.config.ts'; +export const CONFIG_FILE_NAME_JS = 'capacitor.config.js'; +export const CONFIG_FILE_NAME_JSON = 'capacitor.config.json'; + type DeepReadonly = { readonly [P in keyof T]: DeepReadonly }; -export type ExternalConfig = DeepReadonly; -interface Config { - readonly app: AppConfig; -} +export type ExternalConfig = DeepReadonly & + { + electron?: { + includePlugins?: string[] + } + }; + interface AppConfig { readonly rootDir: string; readonly appId: string; @@ -74,11 +83,122 @@ interface PackageJson { readonly devDependencies?: { readonly [key: string]: string | undefined }; } +type ExtConfigPairs = Pick< + AppConfig, + 'extConfigType' | 'extConfigName' | 'extConfigFilePath' | 'extConfig' +>; + +interface NodeModuleWithCompile extends NodeJS.Module { + _compile?(code: string, filename: string): any; +} + +export const requireTS = (ts: typeof typescript, p: string): unknown => { + const id = resolve(p); + + delete require.cache[id]; + + require.extensions['.ts'] = ( + module: NodeModuleWithCompile, + fileName: string, + ) => { + let sourceText = readFileSync(fileName, 'utf8'); + + if (fileName.endsWith('.ts')) { + const tsResults = ts.transpileModule(sourceText, { + fileName, + compilerOptions: { + module: ts.ModuleKind.CommonJS, + moduleResolution: ts.ModuleResolutionKind.NodeJs, + esModuleInterop: true, + strict: true, + target: ts.ScriptTarget.ES2017, + }, + reportDiagnostics: true, + }); + sourceText = tsResults.outputText; + } else { + // quick hack to turn a modern es module + // into and old school commonjs module + sourceText = sourceText.replace(/export\s+\w+\s+(\w+)/gm, 'exports.$1'); + } + + module._compile?.(sourceText, fileName); + }; + + const m = require(id); // eslint-disable-line @typescript-eslint/no-var-requires + + delete require.extensions['.ts']; + + return m; +} + +async function loadExtConfigTS( + rootDir: string, + extConfigName: string, + extConfigFilePath: string, +): Promise { + const tsPath = resolveNode(rootDir, 'typescript'); + if (!tsPath) { + throw new Error( + 'Could not find installation of TypeScript.\n' + + `To use ${ + extConfigName + } files, you must install TypeScript in your project, e.g. w/ npm install -D typescript`, + ); + } + + const ts = require(tsPath); // eslint-disable-line @typescript-eslint/no-var-requires + const extConfigObject = requireTS(ts, extConfigFilePath) as any; + const extConfig = extConfigObject.default ?? extConfigObject; + + return { + extConfigType: 'ts', + extConfigName, + extConfigFilePath: extConfigFilePath, + extConfig, + }; +} + +async function loadExtConfigJS( + rootDir: string, + extConfigName: string, + extConfigFilePath: string, +): Promise { + return { + extConfigType: 'js', + extConfigName, + extConfigFilePath: extConfigFilePath, + extConfig: require(extConfigFilePath), + } +} + +async function loadExtConfig(rootDir: string): Promise { + const extConfigFilePathTS = resolve(rootDir, CONFIG_FILE_NAME_TS); + + if (await pathExists(extConfigFilePathTS)) { + return loadExtConfigTS(rootDir, CONFIG_FILE_NAME_TS, extConfigFilePathTS); + } + + const extConfigFilePathJS = resolve(rootDir, CONFIG_FILE_NAME_JS); + + if (await pathExists(extConfigFilePathJS)) { + return loadExtConfigJS(rootDir, CONFIG_FILE_NAME_JS, extConfigFilePathJS); + } + + const extConfigFilePath = resolve(rootDir, CONFIG_FILE_NAME_JSON); + + return { + extConfigType: 'json', + extConfigName: CONFIG_FILE_NAME_JSON, + extConfigFilePath: extConfigFilePath, + extConfig: await readJSON(extConfigFilePath), + }; +} + export async function getPlugins(packageJsonPath: string): Promise<(Plugin | null)[]> { const packageJson: PackageJson = (await readJSON(packageJsonPath)) as PackageJson; - //console.log(packageJson); - const possiblePlugins = getDependencies(packageJson); - //console.log(possiblePlugins); + const conf = (await loadExtConfig(process.env.CAPACITOR_ROOT_DIR)).extConfig.electron?.includePlugins + const possiblePlugins = conf ?? getDependencies(packageJson); const resolvedPlugins = await Promise.all(possiblePlugins.map(async (p) => resolvePlugin(p))); return resolvedPlugins.filter((p) => !!p); diff --git a/src/electron-platform-template/tsconfig.json b/src/electron-platform-template/tsconfig.json index ef90ab39..3497adcc 100644 --- a/src/electron-platform-template/tsconfig.json +++ b/src/electron-platform-template/tsconfig.json @@ -4,6 +4,7 @@ "compilerOptions": { "outDir": "./build", "importHelpers": true, + "skipLibCheck": true, "target": "ES2017", "module": "CommonJS", "moduleResolution": "node",