diff --git a/.editorconfig b/.editorconfig index 59d9a3a..f166060 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,7 @@ trim_trailing_whitespace = true [*.ts] quote_type = single +ij_typescript_use_double_quotes = false [*.md] max_line_length = off diff --git a/.gitignore b/.gitignore index 7a4a863..cc7b141 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files. # Compiled output +/dist /tmp /out-tsc /bazel-out diff --git a/README.md b/README.md index 2997e26..e93691d 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,59 @@ -# Integrating Syncfusion Angular Components with Angular and Electron Applications +# ElectronApp -This document helps you to create a simple Angular application with `Electron Framework` and `Syncfusion Angular UI components`. +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.13. -## Prerequisites +## Development server -Before getting started with the Angular project, make sure you have the following installed on your machine, +To start a local development server, run: -* [System requirements for Syncfusion Angular UI components](https://ej2.syncfusion.com/angular/documentation/system-requirement) -* Electron CLI version - `^22.x.x` or later +```bash +ng serve +``` -If you do not have the `Electron CLI` installed, refer to the [`Electron package`](https://www.npmjs.com/package/electron-cli) for instructions on how to install it. +Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. -## Getting started with Syncfusion Angular component +## Code scaffolding -Follow the [documentation](https://ej2.syncfusion.com/angular/documentation/getting-started/angular-cli) to create an Angular application that includes Syncfusion Angular components. +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: -## Create main.js file +```bash +ng generate component component-name +``` -Create a `main.js` file in the root folder of the project and update the below code, This file will serve as an entry-point for Electron and it is responsible for creating windows and handling all the system events that might occur in the app. +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: -```typescript -const { app, BrowserWindow } = require('electron'); -let win; +```bash +ng generate --help +``` -function createWindow() { - win = new BrowserWindow({ width: 800, height: 600 }); +## Building - // Load the Angular app in the browser window - win.loadFile('./dist/sample15/index.html'); +To build the project run: - win.on('closed', () => { - win = null; - }); -} +```bash +ng build +``` -app.on('ready', createWindow); +This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); - } -}); +## Running unit tests -app.on('activate', () => { - if (win === null) { - createWindow(); - } -}); +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: +```bash +ng test ``` -## Update index.html - -In the `/src/index.html` file, change `` to ``, so that the Electron can able to find the Angular files. - -## Update package.json +## Running end-to-end tests -Go to your root directory and find the package.json file. Open its content and add the following, +For end-to-end (e2e) testing, run: -```typescript -"main":"main.js", -"scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e", - "electron-build": "ng build --configuration=production", - "electron": "electron ." -}, +```bash +ng e2e ``` -## Running the application +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. -Finally, run the following command line to start the application. The Syncfusion Essential JS 2 menu component will be rendered in the Electron framework. +## Additional Resources - ```bash -npm run electron-build - -npm run electron -``` \ No newline at end of file +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/angular.json b/angular.json index ee2c821..bbc6921 100644 --- a/angular.json +++ b/angular.json @@ -3,7 +3,7 @@ "version": 1, "newProjectRoot": "projects", "projects": { - "sample15": { + "electron-app": { "projectType": "application", "schematics": {}, "root": "", @@ -11,22 +11,23 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser", + "builder": "@angular-devkit/build-angular:application", "options": { - "outputPath": "dist/sample15", + "outputPath": "dist/electron-app", "index": "src/index.html", - "main": "src/main.ts", + "browser": "src/main.ts", "polyfills": [ "zone.js" ], "tsConfig": "tsconfig.app.json", "assets": [ - "src/favicon.ico", - "src/assets" + { + "glob": "**/*", + "input": "public" + } ], "styles": [ - "src/styles.css", - "./node_modules/@syncfusion/ej2-material-theme/styles/material.css" + "src/styles.css" ], "scripts": [] }, @@ -35,24 +36,21 @@ "budgets": [ { "type": "initial", - "maximumWarning": "500kb", - "maximumError": "5mb" + "maximumWarning": "500kB", + "maximumError": "1MB" }, { "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" + "maximumWarning": "4kB", + "maximumError": "8kB" } ], "outputHashing": "all" }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, - "sourceMap": true, - "namedChunks": true + "sourceMap": true } }, "defaultConfiguration": "production" @@ -61,19 +59,16 @@ "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "sample15:build:production" + "buildTarget": "electron-app:build:production" }, "development": { - "browserTarget": "sample15:build:development" + "buildTarget": "electron-app:build:development" } }, "defaultConfiguration": "development" }, "extract-i18n": { - "builder": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "sample15:build" - } + "builder": "@angular-devkit/build-angular:extract-i18n" }, "test": { "builder": "@angular-devkit/build-angular:karma", @@ -84,17 +79,21 @@ ], "tsConfig": "tsconfig.spec.json", "assets": [ - "src/favicon.ico", - "src/assets" + { + "glob": "**/*", + "input": "public" + } ], "styles": [ - "src/styles.css", - "./node_modules/@syncfusion/ej2-material-theme/styles/material.css" + "src/styles.css" ], "scripts": [] } } } } + }, + "cli": { + "analytics": "7530d412-980f-46ae-b82a-dd405f10468b" } -} \ No newline at end of file +} diff --git a/main.js b/main.js index 9aac8a5..a28cf97 100644 --- a/main.js +++ b/main.js @@ -1,11 +1,12 @@ const { app, BrowserWindow } = require('electron'); +const path = require('path'); + let win; function createWindow() { win = new BrowserWindow({ width: 800, height: 600 }); - - // Load the Angular app in the browser window - win.loadFile('./dist/sample15/index.html'); + win.loadFile(path.join(__dirname, 'dist/electron-app/browser/index.html')); // Adjust 'my-app' to your project name + win.webContents.openDevTools(); win.on('closed', () => { win = null; @@ -24,4 +25,4 @@ app.on('activate', () => { if (win === null) { createWindow(); } -}); +}); \ No newline at end of file diff --git a/package.json b/package.json index 43fc710..54719a4 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,40 @@ { - "name": "sample15", + "name": "electron-app", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "watch": "ng build --watch --configuration development", - "test": "ng test", - "electron-build": "ng build --configuration=production", - "electron": "electron ." + "test": "ng test" }, - "main": "main.js", "private": true, "dependencies": { - "@angular/animations": "^15.1.0", - "@angular/common": "^15.1.0", - "@angular/compiler": "^15.1.0", - "@angular/core": "^15.1.0", - "@angular/forms": "^15.1.0", - "@angular/platform-browser": "^15.1.0", - "@angular/platform-browser-dynamic": "^15.1.0", - "@angular/router": "^15.1.0", + "@angular/common": "^19.2.0", + "@angular/compiler": "^19.2.0", + "@angular/core": "^19.2.0", + "@angular/forms": "^19.2.0", + "@angular/platform-browser": "^19.2.0", + "@angular/platform-browser-dynamic": "^19.2.0", + "@angular/router": "^19.2.0", "@syncfusion/ej2-angular-grids": "*", - "@syncfusion/ej2-material-theme": "*", - "electron": "^22.2.0", + "@syncfusion/ej2-angular-navigations": "*", "rxjs": "~7.8.0", "tslib": "^2.3.0", - "zone.js": "~0.12.0" + "zone.js": "~0.15.0" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.1.4", - "@angular/cli": "~15.1.4", - "@angular/compiler-cli": "^15.1.0", - "@types/jasmine": "~4.3.0", - "jasmine-core": "~4.5.0", + "@angular-devkit/build-angular": "^19.2.13", + "@angular/cli": "^19.2.13", + "@angular/compiler-cli": "^19.2.0", + "@types/jasmine": "~5.1.0", + "electron": "^36.5.0", + "jasmine-core": "~5.6.0", "karma": "~6.4.0", - "karma-chrome-launcher": "~3.1.0", + "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.0.0", - "typescript": "~4.9.4" + "karma-jasmine-html-reporter": "~2.1.0", + "typescript": "~5.7.2" } } diff --git a/src/app/app.component.html b/src/app/app.component.html index c0a2724..36093e1 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,8 +1,336 @@ - - - - - - - - \ No newline at end of file + + + + + + + + + + + +
+
+
+ +

Hello, {{ title }}

+

Congratulations! Your app is running. 🎉

+
+ +
+
+ @for (item of [ + { title: 'Explore the Docs', link: 'https://angular.dev' }, + { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' }, + { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' }, + { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' }, + { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' }, + ]; track item.title) { + + {{ item.title }} + + + + + } +
+ +
+
+
+ + + + + + + + + + + diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 97232b0..d9bb9eb 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -4,9 +4,7 @@ import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], + imports: [AppComponent], }).compileComponents(); }); @@ -16,16 +14,16 @@ describe('AppComponent', () => { expect(app).toBeTruthy(); }); - it(`should have as title 'sample15'`, () => { + it(`should have the 'electron-app' title`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; - expect(app.title).toEqual('sample15'); + expect(app.title).toEqual('electron-app'); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('.content span')?.textContent).toContain('sample15 app is running!'); + expect(compiled.querySelector('h1')?.textContent).toContain('Hello, electron-app'); }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7550342..ad40e97 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,26 +1,67 @@ import { Component } from '@angular/core'; +import { GridModule } from '@syncfusion/ej2-angular-grids'; +import { CommonModule } from '@angular/common'; @Component({ selector: 'app-root', - templateUrl: './app.component.html', + standalone: true, + imports: [GridModule, CommonModule], + template: ` +

Syncfusion Angular 19 Grid with Electron (Standalone)

+ + + + + + + + + `, styleUrls: ['./app.component.css'] }) export class AppComponent { public data: Object[] = [ { - OrderID: 10248, CustomerID: 'VINET', EmployeeID: 5, OrderDate: new Date(8364186e5), - ShipName: 'Vins et alcools Chevalier', ShipCity: 'Reims', ShipAddress: '59 rue de l Abbaye', - ShipRegion: 'CJ', ShipPostalCode: '51100', ShipCountry: 'France', Freight: 32.38, Verified: !0 + OrderID: 10248, + CustomerID: 'VINET', + EmployeeID: 5, + OrderDate: new Date(8364186e5), + ShipName: 'Vins et alcools Chevalier', + ShipCity: 'Reims', + ShipAddress: '59 rue de l Abbaye', + ShipRegion: 'CJ', + ShipPostalCode: '51100', + ShipCountry: 'France', + Freight: 32.38, + Verified: true }, { - OrderID: 10249, CustomerID: 'TOMSP', EmployeeID: 6, OrderDate: new Date(836505e6), - ShipName: 'Toms Spezialitäten', ShipCity: 'Münster', ShipAddress: 'Luisenstr. 48', - ShipRegion: 'CJ', ShipPostalCode: '44087', ShipCountry: 'Germany', Freight: 11.61, Verified: !1 + OrderID: 10249, + CustomerID: 'TOMSP', + EmployeeID: 6, + OrderDate: new Date(836505e6), + ShipName: 'Toms Spezialitäten', + ShipCity: 'Münster', + ShipAddress: 'Luisenstr. 48', + ShipRegion: 'CJ', + ShipPostalCode: '44087', + ShipCountry: 'Germany', + Freight: 11.61, + Verified: false }, { - OrderID: 10250, CustomerID: 'HANAR', EmployeeID: 4, OrderDate: new Date(8367642e5), - ShipName: 'Hanari Carnes', ShipCity: 'Rio de Janeiro', ShipAddress: 'Rua do Paço, 67', - ShipRegion: 'RJ', ShipPostalCode: '05454-876', ShipCountry: 'Brazil', Freight: 65.83, Verified: !0 + OrderID: 10250, + CustomerID: 'HANAR', + EmployeeID: 4, + OrderDate: new Date(8367642e5), + ShipName: 'Hanari Carnes', + ShipCity: 'Rio de Janeiro', + ShipAddress: 'Rua do Paço, 67', + ShipRegion: 'RJ', + ShipPostalCode: '05454-876', + ShipCountry: 'Brazil', + Freight: 65.83, + Verified: true } - ]; -} + ]; +} \ No newline at end of file diff --git a/src/app/app.config.ts b/src/app/app.config.ts new file mode 100644 index 0000000..a1e7d6f --- /dev/null +++ b/src/app/app.config.ts @@ -0,0 +1,8 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { provideRouter } from '@angular/router'; + +import { routes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] +}; diff --git a/src/app/app.module.ts b/src/app/app.module.ts deleted file mode 100644 index df2b11a..0000000 --- a/src/app/app.module.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { AppComponent } from './app.component'; -import { GridModule, PagerModule } from '@syncfusion/ej2-angular-grids'; - -@NgModule({ - declarations: [ - AppComponent - ], - imports: [ - BrowserModule, - GridModule, PagerModule - ], - providers: [], - bootstrap: [AppComponent] -}) -export class AppModule { } diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 0000000..dc39edb --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,3 @@ +import { Routes } from '@angular/router'; + +export const routes: Routes = []; diff --git a/src/index.html b/src/index.html index 243b855..6d93716 100644 --- a/src/index.html +++ b/src/index.html @@ -2,8 +2,8 @@ - Sample15 - + ElectronApp + diff --git a/src/main.server.ts b/src/main.server.ts new file mode 100644 index 0000000..4b9d4d1 --- /dev/null +++ b/src/main.server.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; +import { config } from './app/app.config.server'; + +const bootstrap = () => bootstrapApplication(AppComponent, config); + +export default bootstrap; diff --git a/src/main.ts b/src/main.ts index c58dc05..ded2cf4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,5 @@ -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app/app.component'; -import { AppModule } from './app/app.module'; - - -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +bootstrapApplication(AppComponent) + .catch(err => console.error(err)); \ No newline at end of file diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..591b7a6 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,66 @@ +import { + AngularNodeAppEngine, + createNodeRequestHandler, + isMainModule, + writeResponseToNodeResponse, +} from '@angular/ssr/node'; +import express from 'express'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const serverDistFolder = dirname(fileURLToPath(import.meta.url)); +const browserDistFolder = resolve(serverDistFolder, '../browser'); + +const app = express(); +const angularApp = new AngularNodeAppEngine(); + +/** + * Example Express Rest API endpoints can be defined here. + * Uncomment and define endpoints as necessary. + * + * Example: + * ```ts + * app.get('/api/**', (req, res) => { + * // Handle API request + * }); + * ``` + */ + +/** + * Serve static files from /browser + */ +app.use( + express.static(browserDistFolder, { + maxAge: '1y', + index: false, + redirect: false, + }), +); + +/** + * Handle all other requests by rendering the Angular application. + */ +app.use('/**', (req, res, next) => { + angularApp + .handle(req) + .then((response) => + response ? writeResponseToNodeResponse(response, res) : next(), + ) + .catch(next); +}); + +/** + * Start the server if this module is the main entry point. + * The server listens on the port defined by the `PORT` environment variable, or defaults to 4000. + */ +if (isMainModule(import.meta.url)) { + const port = process.env['PORT'] || 4000; + app.listen(port, () => { + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +/** + * Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions. + */ +export const reqHandler = createNodeRequestHandler(app); diff --git a/src/styles.css b/src/styles.css index aa047f0..2bb8597 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,2 +1,2 @@ -@import '../node_modules/@syncfusion/ej2-material-theme/styles/material.css'; -/* You can add global styles to this file, and also import other style files */ +@import '../node_modules/@syncfusion/ej2-base/styles/material.css'; +@import '../node_modules/@syncfusion/ej2-angular-grids/styles/material.css'; \ No newline at end of file diff --git a/tsconfig.app.json b/tsconfig.app.json index 374cc9d..3775b37 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,4 +1,5 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ { "extends": "./tsconfig.json", "compilerOptions": { diff --git a/tsconfig.json b/tsconfig.json index ed966d4..5525117 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,28 +1,22 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ { "compileOnSave": false, "compilerOptions": { - "baseUrl": "./", "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "sourceMap": true, - "declaration": false, - "downlevelIteration": true, + "skipLibCheck": true, + "isolatedModules": true, + "esModuleInterop": true, "experimentalDecorators": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "importHelpers": true, "target": "ES2022", - "module": "ES2022", - "useDefineForClassFields": false, - "lib": [ - "ES2022", - "dom" - ] + "module": "ES2022" }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, diff --git a/tsconfig.spec.json b/tsconfig.spec.json index be7e9da..5fb748d 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -1,4 +1,5 @@ -/* To learn more about this file see: https://angular.io/config/tsconfig. */ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ { "extends": "./tsconfig.json", "compilerOptions": {