├── .editorconfig
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── README.md
├── angular.json
├── package-lock.json
├── package.json
├── src
├── app
│ ├── app-routing.module.ts
│ ├── app.component.html
│ ├── app.component.scss
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ └── app.module.ts
├── assets
│ └── .gitkeep
├── electron.dev.js
├── electron.prod.js
├── favicon.ico
├── index.html
├── main.ts
└── styles.scss
├── tsconfig.app.json
├── tsconfig.json
└── tsconfig.spec.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | .sass-cache/
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | testem.log
38 | /typings
39 |
40 | # System files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "pwa-chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:4200/"
11 | },
12 | {
13 | "name": "ng test",
14 | "type": "chrome",
15 | "request": "launch",
16 | "preLaunchTask": "npm: test",
17 | "url": "http://localhost:9876/debug.html"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "test",
26 | "isBackground": true,
27 | "problemMatcher": {
28 | "owner": "typescript",
29 | "pattern": "$tsc",
30 | "background": {
31 | "activeOnStart": true,
32 | "beginsPattern": {
33 | "regexp": "(.*?)"
34 | },
35 | "endsPattern": {
36 | "regexp": "bundle generation complete"
37 | }
38 | }
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Cli + Electron
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.3.
4 |
5 | The Angular project is wrapped in an Electron environment, that enables you to start the application in a separate window on your desktop.
6 |
7 | ## Development server
8 |
9 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
10 |
11 | ## Code scaffolding
12 |
13 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
14 |
15 | ## Build
16 |
17 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
18 |
19 | ## Running unit tests
20 |
21 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
22 |
23 | ## Running end-to-end tests
24 |
25 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
26 |
27 | ## Further help
28 |
29 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli).
30 |
31 | ## Add support for file system ([no official support](https://github.com/angular/angular-cli/issues/4227)):
32 |
33 | Create a file called `native.js` in the `src` folder and insert the following:
34 |
35 | ```js
36 | window.fs = require("fs");
37 | ```
38 |
39 | Add this file to the `.angular-cli.json` scripts array:
40 |
41 | ```json
42 | "scripts": [
43 | "native.js"
44 | ],
45 | ```
46 |
47 | Add the following lines to `polyfills.ts`:
48 |
49 | ```ts
50 | declare global {
51 | interface Window {
52 | fs: any;
53 | }
54 | }
55 | ```
56 |
57 | After that you can access the filesystem with:
58 |
59 | ```ts
60 | window.fs.writeFileSync("sample.txt", "my data");
61 | ```
62 |
63 | See this [pull request](https://github.com/PKief/angular-cli-electron/pull/1/files) to follow the changes.
64 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "angular-cli-electron": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:component": {
10 | "style": "scss"
11 | }
12 | },
13 | "root": "",
14 | "sourceRoot": "src",
15 | "prefix": "app",
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:browser",
19 | "options": {
20 | "outputPath": "dist/angular-cli-electron",
21 | "index": "src/index.html",
22 | "main": "src/main.ts",
23 | "polyfills": [
24 | "zone.js"
25 | ],
26 | "tsConfig": "tsconfig.app.json",
27 | "inlineStyleLanguage": "scss",
28 | "assets": [
29 | "src/favicon.ico",
30 | "src/assets"
31 | ],
32 | "styles": [
33 | "src/styles.scss"
34 | ],
35 | "scripts": []
36 | },
37 | "configurations": {
38 | "production": {
39 | "budgets": [
40 | {
41 | "type": "initial",
42 | "maximumWarning": "500kb",
43 | "maximumError": "1mb"
44 | },
45 | {
46 | "type": "anyComponentStyle",
47 | "maximumWarning": "2kb",
48 | "maximumError": "4kb"
49 | }
50 | ],
51 | "outputHashing": "all"
52 | },
53 | "development": {
54 | "buildOptimizer": false,
55 | "optimization": false,
56 | "vendorChunk": true,
57 | "extractLicenses": false,
58 | "sourceMap": true,
59 | "namedChunks": true
60 | }
61 | },
62 | "defaultConfiguration": "production"
63 | },
64 | "serve": {
65 | "builder": "@angular-devkit/build-angular:dev-server",
66 | "configurations": {
67 | "production": {
68 | "browserTarget": "angular-cli-electron:build:production"
69 | },
70 | "development": {
71 | "browserTarget": "angular-cli-electron:build:development"
72 | }
73 | },
74 | "defaultConfiguration": "development"
75 | },
76 | "extract-i18n": {
77 | "builder": "@angular-devkit/build-angular:extract-i18n",
78 | "options": {
79 | "browserTarget": "angular-cli-electron:build"
80 | }
81 | },
82 | "test": {
83 | "builder": "@angular-devkit/build-angular:karma",
84 | "options": {
85 | "polyfills": [
86 | "zone.js",
87 | "zone.js/testing"
88 | ],
89 | "tsConfig": "tsconfig.spec.json",
90 | "inlineStyleLanguage": "scss",
91 | "assets": [
92 | "src/favicon.ico",
93 | "src/assets"
94 | ],
95 | "styles": [
96 | "src/styles.scss"
97 | ],
98 | "scripts": []
99 | }
100 | }
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-cli-electron",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "concurrently \"ng serve\" \"npm run electron\"",
7 | "electron": "electron ./src/electron.dev",
8 | "build": "ng build",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e",
12 | "package:win": "npm run build && cross-var electron-packager dist/$npm_package_name $npm_package_name-$npm_package_version --out=packages --platform=win32 --arch=all --overwrite ",
13 | "package:linux": "npm run build && cross-var electron-packager dist/$npm_package_name $npm_package_name-$npm_package_version --out=packages --platform=linux --arch=all --overwrite ",
14 | "package:osx": "npm run build && cross-var electron-packager dist/$npm_package_name $npm_package_name-$npm_package_version --out=packages --platform=darwin --arch=all --overwrite ",
15 | "package:all": "npm run build && cross-var electron-packager dist/$npm_package_name $npm_package_name-$npm_package_version --out=packages --all --arch=all --overwrite "
16 | },
17 | "private": true,
18 | "dependencies": {
19 | "@angular/animations": "^15.0.0",
20 | "@angular/common": "^15.0.0",
21 | "@angular/compiler": "^15.0.0",
22 | "@angular/core": "^15.0.0",
23 | "@angular/forms": "^15.0.0",
24 | "@angular/platform-browser": "^15.0.0",
25 | "@angular/platform-browser-dynamic": "^15.0.0",
26 | "@angular/router": "^15.0.0",
27 | "rxjs": "~7.5.0",
28 | "tslib": "^2.3.0",
29 | "zone.js": "~0.12.0"
30 | },
31 | "devDependencies": {
32 | "@angular-devkit/build-angular": "^15.0.3",
33 | "@angular/cli": "~15.0.3",
34 | "@angular/compiler-cli": "^15.0.0",
35 | "@types/jasmine": "~4.3.0",
36 | "concurrently": "^7.6.0",
37 | "cross-var": "^1.1.0",
38 | "electron": "^22.0.0",
39 | "electron-packager": "^17.1.1",
40 | "jasmine-core": "~4.5.0",
41 | "karma": "~6.4.0",
42 | "karma-chrome-launcher": "~3.1.0",
43 | "karma-coverage": "~2.2.0",
44 | "karma-jasmine": "~5.1.0",
45 | "karma-jasmine-html-reporter": "~2.0.0",
46 | "typescript": "~4.8.2"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { RouterModule, Routes } from '@angular/router';
3 |
4 | const routes: Routes = [];
5 |
6 | @NgModule({
7 | imports: [RouterModule.forRoot(routes)],
8 | exports: [RouterModule]
9 | })
10 | export class AppRoutingModule { }
11 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
304 |
305 |
306 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
343 |
344 |
{{ title }} app is running!
345 |
346 |
350 |
351 |
352 |
353 |
354 |
Resources
355 |
Here are some links to help you get started:
356 |
357 |
388 |
389 |
390 |
Next Steps
391 |
What do you want to do next with your app?
392 |
393 |
394 |
395 |
396 |
400 |
401 |
405 |
406 |
410 |
411 |
415 |
416 |
420 |
421 |
425 |
426 |
427 |
428 |
429 |
ng generate component xyz
430 |
ng add @angular/material
431 |
ng add @angular/pwa
432 |
ng add _____
433 |
ng test
434 |
ng build
435 |
436 |
437 |
438 |
454 |
455 |
456 |
468 |
469 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
--------------------------------------------------------------------------------
/src/app/app.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PKief/angular-cli-electron/af34a82957d1d3ed6286bff8a8d396b138306b42/src/app/app.component.scss
--------------------------------------------------------------------------------
/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { RouterTestingModule } from '@angular/router/testing';
3 | import { AppComponent } from './app.component';
4 |
5 | describe('AppComponent', () => {
6 | beforeEach(async () => {
7 | await TestBed.configureTestingModule({
8 | imports: [
9 | RouterTestingModule
10 | ],
11 | declarations: [
12 | AppComponent
13 | ],
14 | }).compileComponents();
15 | });
16 |
17 | it('should create the app', () => {
18 | const fixture = TestBed.createComponent(AppComponent);
19 | const app = fixture.componentInstance;
20 | expect(app).toBeTruthy();
21 | });
22 |
23 | it(`should have as title 'angular-cli-electron'`, () => {
24 | const fixture = TestBed.createComponent(AppComponent);
25 | const app = fixture.componentInstance;
26 | expect(app.title).toEqual('angular-cli-electron');
27 | });
28 |
29 | it('should render title', () => {
30 | const fixture = TestBed.createComponent(AppComponent);
31 | fixture.detectChanges();
32 | const compiled = fixture.nativeElement as HTMLElement;
33 | expect(compiled.querySelector('.content span')?.textContent).toContain('angular-cli-electron app is running!');
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.scss']
7 | })
8 | export class AppComponent {
9 | title = 'angular-cli-electron';
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { BrowserModule } from '@angular/platform-browser';
3 |
4 | import { AppRoutingModule } from './app-routing.module';
5 | import { AppComponent } from './app.component';
6 |
7 | @NgModule({
8 | declarations: [
9 | AppComponent
10 | ],
11 | imports: [
12 | BrowserModule,
13 | AppRoutingModule
14 | ],
15 | providers: [],
16 | bootstrap: [AppComponent]
17 | })
18 | export class AppModule { }
19 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PKief/angular-cli-electron/af34a82957d1d3ed6286bff8a8d396b138306b42/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/electron.dev.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require("electron");
2 |
3 | // Keep a global reference of the window object, if you don't, the window will
4 | // be closed automatically when the JavaScript object is garbage collected.
5 | let win;
6 |
7 | const createWindow = () => {
8 | // set timeout to render the window not until the Angular
9 | // compiler is ready to show the project
10 | setTimeout(() => {
11 | // Create the browser window.
12 | win = new BrowserWindow({
13 | width: 800,
14 | height: 600,
15 | icon: "./src/favicon.ico",
16 | webPreferences: {
17 | nodeIntegration: false, // turn it on to use node features
18 | },
19 | });
20 |
21 | // and load the app.
22 | const url = new URL("http://localhost:4200");
23 | win.loadURL(url.toString());
24 |
25 | win.webContents.openDevTools();
26 |
27 | // Emitted when the window is closed.
28 | win.on("closed", () => {
29 | // Dereference the window object, usually you would store windows
30 | // in an array if your app supports multi windows, this is the time
31 | // when you should delete the corresponding element.
32 | win = null;
33 | });
34 | }, 10000);
35 | };
36 |
37 | // This method will be called when Electron has finished
38 | // initialization and is ready to create browser windows.
39 | // Some APIs can only be used after this event occurs.
40 | app.on("ready", createWindow);
41 |
42 | // Quit when all windows are closed.
43 | app.on("window-all-closed", () => {
44 | // On macOS it is common for applications and their menu bar
45 | // to stay active until the user quits explicitly with Cmd + Q
46 | if (process.platform !== "darwin") {
47 | app.quit();
48 | }
49 | });
50 |
51 | app.on("activate", () => {
52 | // On macOS it's common to re-create a window in the app when the
53 | // dock icon is clicked and there are no other windows open.
54 | if (win === null) {
55 | createWindow();
56 | }
57 | });
58 |
59 | // In this file you can include the rest of your app's specific main process
60 | // code. You can also put them in separate files and require them here.
61 |
--------------------------------------------------------------------------------
/src/electron.prod.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require("electron");
2 | const path = require("path");
3 | const url = require("url");
4 |
5 | // Keep a global reference of the window object, if you don't, the window will
6 | // be closed automatically when the JavaScript object is garbage collected.
7 | let win;
8 |
9 | const createWindow = () => {
10 | // Create the browser window.
11 | win = new BrowserWindow({
12 | width: 800,
13 | height: 600,
14 | icon: path.join(__dirname, "favicon.ico"),
15 | });
16 |
17 | // and load the index.html of the app.
18 | const url = new URL(`file://${path.join(__dirname, "index.html")}`);
19 | win.loadURL(url.toString());
20 |
21 | // Emitted when the window is closed.
22 | win.on("closed", () => {
23 | // Dereference the window object, usually you would store windows
24 | // in an array if your app supports multi windows, this is the time
25 | // when you should delete the corresponding element.
26 | win = null;
27 | });
28 | };
29 |
30 | // This method will be called when Electron has finished
31 | // initialization and is ready to create browser windows.
32 | // Some APIs can only be used after this event occurs.
33 | app.on("ready", createWindow);
34 |
35 | // Quit when all windows are closed.
36 | app.on("window-all-closed", () => {
37 | // On macOS it is common for applications and their menu bar
38 | // to stay active until the user quits explicitly with Cmd + Q
39 | if (process.platform !== "darwin") {
40 | app.quit();
41 | }
42 | });
43 |
44 | app.on("activate", () => {
45 | // On macOS it's common to re-create a window in the app when the
46 | // dock icon is clicked and there are no other windows open.
47 | if (win === null) {
48 | createWindow();
49 | }
50 | });
51 |
52 | // In this file you can include the rest of your app's specific main process
53 | // code. You can also put them in separate files and require them here.
54 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PKief/angular-cli-electron/af34a82957d1d3ed6286bff8a8d396b138306b42/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AngularCliElectron
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 |
3 | import { AppModule } from './app/app.module';
4 |
5 |
6 | platformBrowserDynamic().bootstrapModule(AppModule)
7 | .catch(err => console.error(err));
8 |
--------------------------------------------------------------------------------
/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts"
10 | ],
11 | "include": [
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "declaration": false,
15 | "downlevelIteration": true,
16 | "experimentalDecorators": true,
17 | "moduleResolution": "node",
18 | "importHelpers": true,
19 | "target": "ES2022",
20 | "module": "ES2022",
21 | "useDefineForClassFields": false,
22 | "lib": [
23 | "ES2022",
24 | "dom"
25 | ]
26 | },
27 | "angularCompilerOptions": {
28 | "enableI18nLegacyMessageIdFormat": false,
29 | "strictInjectionParameters": true,
30 | "strictInputAccessModifiers": true,
31 | "strictTemplates": true
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "include": [
11 | "src/**/*.spec.ts",
12 | "src/**/*.d.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------