Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core electron + core backend ESM #7293

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions core/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
"version": "4.10.0-dev.30",
"description": "iTwin.js backend components",
"main": "lib/cjs/core-backend.js",
"module": "lib/esm/core-backend.js",
"typings": "lib/cjs/core-backend",
"license": "MIT",
"engines": {
"node": "^18.0.0 || ^20.0.0"
},
"scripts": {
"build": "npm run -s build:cjs && npm run -s copy:assets && npm run -s copy:test-assets",
"build": "npm run -s build:cjs && npm run -s build:esm && npm run -s copy:assets && npm run -s copy:test-assets",
"build:cjs": "tsc 1>&2 --outDir lib/cjs",
"build:esm": "tsc 1>&2 --module ES2020 --outDir lib/esm",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yourec ompiling core-electron to module esnext, but here es2020?

"clean": "rimraf lib .rush/temp/package-deps*.json ../../tools/internal/ios/core-test-runner/build ../../tools/internal/lib",
"docs": "betools docs --includes=../../generated-docs/extract --json=../../generated-docs/core/core-backend/file.json --tsIndexFile=./core-backend.ts --onlyJson --excludeGlob=**/*.d.ts",
"copy:assets": "cpx \"./src/assets/**/*\" ./lib/cjs/assets",
"copy:assets": "cpx \"./src/assets/**/*\" ./lib/cjs/assets && cpx \"./src/assets/**/*\" ./lib/esm/assets",
"copy:config": "internal-tools copy-config",
"copy:test-assets": "cpx \"./src/test/assets/**/*\" ./lib/cjs/test/assets",
"copy:test-assets": "cpx \"./src/test/assets/**/*\" ./lib/cjs/test/assets && cpx \"./src/test/assets/**/*\" ./lib/esm/test/assets",
"cover": "nyc npm -s test",
"extract-api": "betools extract-api --entry=core-backend",
"lint": "eslint -f visualstudio \"./src/**/*.ts\" 1>&2",
Expand Down
5 changes: 2 additions & 3 deletions core/backend/src/test/schema/FunctionalDomain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { assert, expect } from "chai";
import { join } from "path";
import { restore as sinonRestore, spy as sinonSpy } from "sinon";
import { restore as sinonRestore, SinonSpy, spy as sinonSpy } from "sinon";
import { Guid, Id64 } from "@itwin/core-bentley";
import { CodeScopeSpec, CodeSpec, ElementProps, IModel } from "@itwin/core-common";
import { ClassRegistry } from "../../ClassRegistry";
Expand All @@ -18,7 +18,6 @@ import {
import { ElementOwnsChildElements, ElementOwnsUniqueAspect, SubjectOwnsPartitionElements } from "../../NavigationRelationship";
import { IModelTestUtils } from "../IModelTestUtils";
import { KnownTestLocations } from "../KnownTestLocations";
import Sinon = require("sinon");

let iModelDb: StandaloneDb;
const insertedLabel = "inserted label";
Expand Down Expand Up @@ -276,7 +275,7 @@ describe("Functional Domain", () => {

const testChannelKey1 = "channel 1 for tests";
const testChannelKey2 = "channel 2 for tests";
function testChannel<T>(channelKey: ChannelKey, fn: () => T, spies: Sinon.SinonSpy[]) {
function testChannel<T>(channelKey: ChannelKey, fn: () => T, spies: SinonSpy[]) {
iModelDb.channels.removeAllowedChannel(channelKey);
expect(fn).throws("not allowed");
iModelDb.channels.addAllowedChannel(channelKey);
Expand Down
16 changes: 8 additions & 8 deletions core/backend/src/test/standalone/ChangeConflictHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import * as chai from "chai";
import { assert, expect } from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { restore, SinonSpy, SinonStub, spy, stub } from "sinon";
import { HubWrappers, KnownTestLocations } from "../";
import { HubMock } from "../../HubMock";
import {
Expand All @@ -25,7 +26,6 @@ import {
import { IModelTestUtils, TestUserType } from "../IModelTestUtils";
import { ChangesetConflictArgs } from "../../internal/ChangesetConflictArgs";
chai.use(chaiAsPromised);
import sinon = require("sinon");

async function assertThrowsAsync<T>(test: () => Promise<T>, msg?: string) {
try {
Expand Down Expand Up @@ -139,7 +139,7 @@ describe("Changeset conflict handler", () => {
});

afterEach(async () => {
sinon.restore();
restore();

if (b1.isOpen) {
b1.abandonChanges();
Expand All @@ -157,8 +157,8 @@ describe("Changeset conflict handler", () => {
}
});

async function spyChangesetConflictHandler(b: BriefcaseDb, cb: () => Promise<void>, test: (s: sinon.SinonSpy<ChangesetConflictArgs[], DbConflictResolution>) => void) {
const s1 = sinon.spy(b, "onChangesetConflict" as any) as sinon.SinonSpy<ChangesetConflictArgs[], DbConflictResolution>;
async function spyChangesetConflictHandler(b: BriefcaseDb, cb: () => Promise<void>, test: (s: SinonSpy<ChangesetConflictArgs[], DbConflictResolution>) => void) {
const s1 = spy(b, "onChangesetConflict" as any) as sinon.SinonSpy<ChangesetConflictArgs[], DbConflictResolution>;
try {
await cb();
} finally {
Expand All @@ -167,17 +167,17 @@ describe("Changeset conflict handler", () => {
}
}

async function stubChangesetConflictHandler(b: BriefcaseDb, cb: () => Promise<void>, test: (s: sinon.SinonStub<ChangesetConflictArgs[], DbConflictResolution>) => void) {
const s1 = sinon.stub(b as any, "onChangesetConflict" as any);
async function stubChangesetConflictHandler(b: BriefcaseDb, cb: () => Promise<void>, test: (s: SinonStub<ChangesetConflictArgs[], DbConflictResolution>) => void) {
const s1 = stub(b as any, "onChangesetConflict" as any);
try {
test(s1 as sinon.SinonStub<ChangesetConflictArgs[], DbConflictResolution>);
test(s1 as SinonStub<ChangesetConflictArgs[], DbConflictResolution>);
await cb();
} finally {
s1.restore();
}
}
async function fakeChangesetConflictHandler(b: BriefcaseDb, cb: () => Promise<void>, interceptMethod: (arg: ChangesetConflictArgs) => DbConflictResolution | undefined) {
const s1 = sinon.stub<ChangesetConflictArgs[], DbConflictResolution>(b as any, "onChangesetConflict" as any);
const s1 = stub<ChangesetConflictArgs[], DbConflictResolution>(b as any, "onChangesetConflict" as any);
s1.callsFake(interceptMethod);
try {
await cb();
Expand Down
8 changes: 4 additions & 4 deletions core/backend/src/test/standalone/MergeConflict.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import * as chai from "chai";
import { assert, expect } from "chai";
import * as chaiAsPromised from "chai-as-promised";
import { stub } from "sinon";
import { HubWrappers, KnownTestLocations } from "../";
import { HubMock } from "../../HubMock";
import {
Expand All @@ -22,7 +23,6 @@ import {
} from "../../core-backend";
import { IModelTestUtils, TestUserType } from "../IModelTestUtils";
chai.use(chaiAsPromised);
import sinon = require("sinon");
export async function createNewModelAndCategory(rwIModel: BriefcaseDb, parent?: Id64String) {
// Create a new physical model.
const [, modelId] = await IModelTestUtils.createAndInsertPhysicalPartitionAndModelAsync(rwIModel, IModelTestUtils.getUniqueModelCode(rwIModel, "newPhysicalModel"), true, parent);
Expand Down Expand Up @@ -143,7 +143,7 @@ describe("Merge conflict & locking", () => {
} as ElementAspectProps);
b2.saveChanges();

const onChangesetConflictStub = sinon.stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
const onChangesetConflictStub = stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
await assertThrowsAsync(
async () => b2.pushChanges({ accessToken: accessToken1, description: `modify aspect ${aspectId1} with no lock` }),
"UPDATE/DELETE before value do not match with one in db or CASCADE action was triggered.");
Expand Down Expand Up @@ -216,7 +216,7 @@ describe("Merge conflict & locking", () => {
await b1.pushChanges({ accessToken: accessToken1, description: `deleted element ${el1}` });
b2.saveChanges();

const onChangesetConflictStub = sinon.stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
const onChangesetConflictStub = stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
await assertThrowsAsync(
async () => b2.pushChanges({ accessToken: accessToken2, description: `add aspect to element ${el1}` }),
"UPDATE/DELETE before value do not match with one in db or CASCADE action was triggered.");
Expand Down Expand Up @@ -328,7 +328,7 @@ describe("Merge conflict & locking", () => {

await b1.pushChanges({ accessToken: accessToken1, description: `deleted element ${el1}` });

const onChangesetConflictStub = sinon.stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
const onChangesetConflictStub = stub(BriefcaseDb.prototype, "onChangesetConflict" as any);
/* we should be able to apply all changesets */
await b3.pullChanges();
expect(onChangesetConflictStub.callCount).greaterThanOrEqual(1, "native conflict handler must call BriefcaseDb.onChangesetConflict()");
Expand Down
17 changes: 15 additions & 2 deletions core/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,22 @@
"engines": {
"node": "^18.0.0 || ^20.0.0"
},
"exports": {
"./ElectronBackend": {
"types": "./lib/esm/ElectronBackend.d.ts",
"import": "./lib/esm/ElectronBackend.js",
"require": "./lib/cjs/ElectronBackend.js"
},
"./ElectronFrontend": {
"types": "./lib/esm/ElectronFrontend.d.ts",
"import": "./lib/esm/ElectronFrontend.js",
"require": "./lib/cjs/ElectronFrontend.js"
}
},
"scripts": {
"build": "npm run -s build:cjs && npm run -s webpack:test",
"build": "npm run -s build:cjs && npm run -s build:esm && npm run -s webpack:test",
"build:cjs": "tsc 1>&2 --outDir lib/cjs",
"build:esm": "tsc 1>&2 --module esnext --outDir lib/esm",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why deliver both CJS and ESM ? Wouldn't it be less painful to just switch to ESM on 5.0 ?

Copy link
Contributor Author

@hl662 hl662 Oct 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I was initially thinking this would go into one of the 4.X versions, but I'm now more certain this should be in 5.x - as I go through with modifying DTA, I'm noticing pain points with delivering dual cjs/esm, both in these packages and our electron-authorization pkg. When running an ESM module, and using named imports (like "@itwin/electron-authorization/Main"), electron complains at run time that it doesn't like electron-auth being CJS. And seems like the only way to solve that is to set 'type': "module" in the respective package.json.

"clean": "rimraf lib .rush/temp/package-deps*.json",
"docs": "betools docs --includes=../../generated-docs/extract --json=../../generated-docs/core/core-electron/file.json --tsIndexFile=./__DOC_ONLY__.ts --onlyJson",
"extract-api": "betools extract-api --entry=__DOC_ONLY__",
Expand Down Expand Up @@ -39,7 +52,7 @@
"@itwin/core-bentley": "workspace:^4.10.0-dev.30",
"@itwin/core-common": "workspace:^4.10.0-dev.30",
"@itwin/core-frontend": "workspace:^4.10.0-dev.30",
"electron": ">=23.0.0 <34.0.0"
"electron": ">=28.0.0 <34.0.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if we leave the min ver as is?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Electron "properly" supports ESM from version 28. If we're delivering both CJS and ESM, we could leave version 23 as minimum, I think.

},
"devDependencies": {
"@itwin/build-tools": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions test-apps/display-test-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "display-test-app",
"description": "Internal app for testing features of display system",
"license": "UNLICENSED",
"type": "module",
"author": {
"name": "Bentley Systems, Inc.",
"url": "http://www.bentley.com"
Expand Down
8 changes: 4 additions & 4 deletions test-apps/display-test-app/src/backend/Backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import * as fs from "fs";
import * as path from "path";
import { Logger, LogLevel, ProcessDetector } from "@itwin/core-bentley";
import { ElectronMainAuthorization } from "@itwin/electron-authorization/Main";
import { ElectronHost, ElectronHostOptions } from "@itwin/core-electron/lib/cjs/ElectronBackend";
import { ElectronHost, ElectronHostOptions } from "@itwin/core-electron/ElectronBackend";
import { BackendIModelsAccess } from "@itwin/imodels-access-backend";
import { IModelsClient } from "@itwin/imodels-client-authoring";
import { IModelDb, IModelHost, IModelHostOptions, LocalhostIpcHost, produceTextAnnotationGeometry } from "@itwin/core-backend";
import {
IModelReadRpcInterface, IModelRpcProps, IModelTileRpcInterface, RpcInterfaceDefinition, RpcManager, SnapshotIModelRpcInterface, TextAnnotation, TextAnnotationProps, TextBlockGeometryProps,
} from "@itwin/core-common";
import { MobileHost, MobileHostOpts } from "@itwin/core-mobile/lib/cjs/MobileBackend";
import { DtaConfiguration, getConfig } from "../common/DtaConfiguration";
import { DtaRpcInterface } from "../common/DtaRpcInterface";
import { MobileHost, MobileHostOpts } from "@itwin/core-mobile/lib/cjs/MobileBackend.js";
import { DtaConfiguration, getConfig } from "../common/DtaConfiguration.js";
import { DtaRpcInterface } from "../common/DtaRpcInterface.js";
import { EditCommandAdmin } from "@itwin/editor-backend";
import * as editorBuiltInCommands from "@itwin/editor-backend";

Expand Down
10 changes: 5 additions & 5 deletions test-apps/display-test-app/src/backend/DtaElectronMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as path from "path";
import { assert } from "@itwin/core-bentley";
import { ElectronHost } from "@itwin/core-electron/lib/cjs/ElectronBackend";
import { CreateSectionDrawingViewArgs, CreateSectionDrawingViewResult, dtaChannel, DtaIpcInterface } from "../common/DtaIpcInterface";
import { getRpcInterfaces, initializeDtaBackend, loadBackendConfig } from "./Backend";
import { ElectronHost } from "@itwin/core-electron/ElectronBackend";
import { CreateSectionDrawingViewArgs, CreateSectionDrawingViewResult, dtaChannel, DtaIpcInterface } from "../common/DtaIpcInterface.js";
import { getRpcInterfaces, initializeDtaBackend, loadBackendConfig } from "./Backend.js";
import { IpcHandler } from "@itwin/core-backend";
import { getConfig } from "../common/DtaConfiguration";
import { createSectionDrawing } from "./SectionDrawingImpl";
import { getConfig } from "../common/DtaConfiguration.js";
import { createSectionDrawing } from "./SectionDrawingImpl.js";

const mainWindowName = "mainWindow";
const getWindowSize = (winSize?: string) => {
Expand Down
4 changes: 2 additions & 2 deletions test-apps/display-test-app/src/backend/MobileMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/

import { MobileHostOpts } from "@itwin/core-mobile/lib/cjs/MobileBackend";
import { getRpcInterfaces, initializeDtaBackend } from "./Backend";
import { MobileHostOpts } from "@itwin/core-mobile/lib/cjs/MobileBackend.js";
import { getRpcInterfaces, initializeDtaBackend } from "./Backend.js";

const dtaMobileMain = (async () => {
const opts: MobileHostOpts = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { TransformProps } from "@itwin/core-geometry";
import { DbResult, DisplayStyle3dProps, GeometricModel2dProps, RelatedElementProps, SectionDrawingProps, SectionType, SpatialViewDefinitionProps } from "@itwin/core-common";
import { Id64, Id64String } from "@itwin/core-bentley";
import { CreateSectionDrawingViewArgs, CreateSectionDrawingViewResult } from "../common/DtaIpcInterface";
import { CreateSectionDrawingViewArgs, CreateSectionDrawingViewResult } from "../common/DtaIpcInterface.js";

/** Find or create a document partition named" DrawingProductionDrawing" to contain all our section drawings. */
async function getDrawingProductionListModel(db: BriefcaseDb): Promise<Id64String> {
Expand Down
2 changes: 1 addition & 1 deletion test-apps/display-test-app/src/backend/WebMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Logger } from "@itwin/core-bentley";
import { BentleyCloudRpcConfiguration, BentleyCloudRpcManager } from "@itwin/core-common";
import { getRpcInterfaces, initializeDtaBackend } from "./Backend";
import { LocalhostIpcHost } from "@itwin/core-backend";
import { DtaRpcInterface } from "../common/DtaRpcInterface";
import { DtaRpcInterface } from "../common/DtaRpcInterface.js";

/* eslint-disable no-console */

Expand Down
2 changes: 1 addition & 1 deletion test-apps/display-test-app/src/common/DtaRpcInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { IModelRpcProps, RpcInterface, RpcManager, TextAnnotationProps, TextBlockGeometryProps } from "@itwin/core-common";
import * as http from "http";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are we using "backendServer" for?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldnt be in the common layer imo

import * as https from "https";
import { DtaConfiguration } from "./DtaConfiguration";
import { DtaConfiguration } from "./DtaConfiguration.js";

/** Display Test App RPC interface. */
export class DtaRpcInterface extends RpcInterface { // eslint-disable-line deprecation/deprecation
Expand Down
2 changes: 1 addition & 1 deletion test-apps/display-test-app/src/frontend/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import "@bentley/icons-generic-webfont/dist/bentley-icons-generic-webfont.css";
import { GuidString, ProcessDetector } from "@itwin/core-bentley";
import { ElectronApp, ElectronAppOpts } from "@itwin/core-electron/lib/cjs/ElectronFrontend";
import { ElectronApp, ElectronAppOpts } from "@itwin/core-electron/ElectronFrontend";
import { BrowserAuthorizationClient } from "@itwin/browser-authorization";
import { FrontendIModelsAccess } from "@itwin/imodels-access-frontend";
import { IModelsClient } from "@itwin/imodels-client-management";
Expand Down
2 changes: 1 addition & 1 deletion test-apps/display-test-app/src/frontend/FileOpen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { ProcessDetector } from "@itwin/core-bentley";
import { ElectronApp } from "@itwin/core-electron/lib/cjs/ElectronFrontend";
import { ElectronApp } from "@itwin/core-electron/ElectronFrontend";
import { OpenDialogOptions } from "electron";

export interface BrowserFileSelector {
Expand Down
6 changes: 4 additions & 2 deletions test-apps/display-test-app/tsconfig.backend.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
"extends": "./node_modules/@itwin/build-tools/tsconfig-base.json",
"compilerOptions": {
"outDir": "./lib",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2020"],
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"resolvePackageJsonExports": true
},
"include": ["./src/backend/*.ts", "./src/common/*.ts"]
Expand Down
6 changes: 3 additions & 3 deletions test-apps/display-test-app/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ export default defineConfig(() => {
resolve: {
alias: {
...packageAliases,
"@itwin/core-electron/lib/cjs/ElectronFrontend":
"@itwin/core-electron/src/ElectronFrontend.ts",
// "@itwin/core-electron/ElectronFrontend":
// "@itwin/core-electron/src/ElectronFrontend.ts",
"@itwin/core-mobile/lib/cjs/MobileFrontend":
"@itwin/core-mobile/src/MobileFrontend.ts",
"../../package.json": "../package.json", // in core-frontend
Expand All @@ -147,7 +147,7 @@ export default defineConfig(() => {
force: true, // forces cache dumps on each rebuild. should be turned off once the issue in vite with monorepos not being correctly optimized is fixed. Issue link: https://github.com/vitejs/vite/issues/14099
// overoptimized dependencies in the same monorepo (vite converts all cjs to esm)
include: [
"@itwin/core-electron/lib/cjs/ElectronFrontend", // import from module error
// "@itwin/core-electron/ElectronFrontend", // import from module error
"@itwin/core-mobile/lib/cjs/MobileFrontend", // import from module error
],
exclude: [
Expand Down