From a0065cacc46c3dcc689fca97fe12486fceaff2a9 Mon Sep 17 00:00:00 2001
From: Olivier Combe <olivier.combe@gmail.com>
Date: Fri, 1 Dec 2023 14:52:30 +0100
Subject: [PATCH] feat: add esbuild, ssr and interactive ng-app template

---
 .gitignore                                    |   1 +
 .../angular-app-type/angular-app-options.ts   |  15 +-
 .../angular-app-type/angular.app-type.ts      |  10 +-
 .../angular-app-type/angular.application.ts   | 149 +++---
 .../angular-app-type/application.bundler.ts   | 261 +++++++++++
 .../application.dev-server.ts                 | 183 ++++++++
 .../app-types/angular-app-type/component.json |   9 +-
 .../runtime/api-middleware.js                 |  29 ++
 .../angular-app-type/runtime/renderer.js      |  18 +
 angular/app-types/angular-app-type/utils.ts   |  27 +-
 angular/devkit/common/component.json          |   3 +-
 angular/devkit/common/env-options.ts          |   2 +-
 angular/devkit/common/generic-angular-env.ts  |  15 +-
 angular/devkit/common/index.ts                |   2 +-
 angular/devkit/common/utils.ts                |  50 +-
 .../ng-compat/build-angular/browser-schema.ts |   3 -
 .../build-angular/builder-options.ts          |   2 +
 .../build-angular/builders/application.ts     |  24 +
 .../schemas/application.schema.ts             | 429 ++++++++++++++++++
 .../ng-compat/build-angular/utils/index.ts    |   4 +-
 .../utils/webpack-browser-config.ts           |   4 +-
 .../ng-compat/build-angular/webpack/stats.ts  |   4 +-
 angular/devkit/ng-compat/component.json       |   2 +
 angular/devkit/ng-compat/index.ts             |   4 +-
 .../devkit/preview/preview/angular-preview.ts |  13 +-
 angular/devkit/vite/component.json            |  32 +-
 angular/devkit/vite/config.factory.ts         | 182 ++++++++
 angular/devkit/vite/dev-server/config.ts      | 124 -----
 angular/devkit/vite/dev-server/types.ts       |  91 ----
 .../vite/dev-server/utils/html-plugin.ts      |  62 ---
 angular/devkit/vite/dev-server/utils/index.ts |   3 -
 .../vite/dev-server/utils/mdx-config.ts       | 109 -----
 angular/devkit/vite/index.ts                  |   5 +-
 angular/devkit/vite/ng-vite-dev-server.ts     |  82 ----
 angular/devkit/vite/ng-vite.bundler.ts        |  36 ++
 angular/devkit/vite/ng-vite.dev-server.ts     |  41 ++
 .../plugins/index-file/augment-index-html.ts  |   9 +-
 .../plugins/index-file/package-chunk-sort.ts  |   2 +-
 .../devkit/vite/plugins/index-html.plugin.ts  |  30 +-
 .../vite/plugins/server-entry.plugin.ts       | 113 +++++
 .../vite/{dev-server => }/utils/host-alias.ts |   3 +-
 angular/devkit/vite/utils/types.ts            |  36 ++
 angular/devkit/vite/utils/utils.ts            |  21 +
 angular/devkit/webpack/ng-webpack-bundler.ts  |  19 +-
 .../devkit/webpack/ng-webpack-dev-server.ts   |  16 +-
 .../webpack-plugins/angular-resolver.ts       |   4 +-
 angular/envs/angular-env/component.json       |   4 +-
 angular/envs/angular-env/env.jsonc            |  10 +
 angular/envs/angular-v13-env/env.jsonc        |   5 +
 .../angular-v13-env/webpack-config.factory.ts |  25 +-
 .../webpack/webpack5.serve.config.ts          |   9 +-
 angular/envs/angular-v14-env/env.jsonc        |   5 +
 .../angular-v14-env/webpack-config.factory.ts |  26 +-
 .../webpack/webpack5.serve.config.ts          |   9 +-
 angular/envs/angular-v15-env/env.jsonc        |   5 +
 .../angular-v15-env/webpack-config.factory.ts |  23 +-
 .../webpack/webpack5.serve.config.ts          |   4 +-
 .../angular-v16-env.bit-env.ts                |  38 +-
 angular/envs/angular-v16-env/component.json   |   3 +-
 angular/envs/angular-v16-env/env.jsonc        |  10 +
 .../angular-v16-env/webpack-config.factory.ts |  23 +-
 .../webpack/webpack5.serve.config.ts          |   4 +-
 .../angular-v17-env.bit-env.ts                |  38 +-
 angular/envs/angular-v17-env/component.json   |   4 +-
 angular/envs/angular-v17-env/env.jsonc        |  10 +
 .../angular-v17-env/webpack-config.factory.ts |  27 +-
 .../webpack/webpack5.serve.config.ts          |   4 +-
 .../envs/base-env/angular-base-env.bit-env.ts |  11 +-
 .../examples/my-angular-env/component.json    |   2 +-
 angular/examples/my-angular-env/env.jsonc     |  10 +
 angular/examples/my-angular-v17-env/env.jsonc |  14 +-
 angular/templates/generators/ng-app/index.ts  | 114 ++++-
 .../generators/ng-app/template-files/docs.ts  |   2 +-
 .../ng-app/template-files/ng-app.ts           |  18 +-
 .../src/app/app.component-html.ts             |  14 +-
 .../src/app/app.component-scss.ts             |   4 +-
 .../src/app/app.component-spec.ts             |   4 +-
 .../template-files/src/app/app.component.ts   |  22 +-
 .../src/app/app.config.server.ts              |  19 +
 .../template-files/src/app/app.config.ts      |   9 +-
 .../template-files/src/app/app.module.ts      |  11 +-
 .../ng-app/template-files/src/index-html.ts   |   2 +-
 .../ng-app/template-files/src/main.server.ts  |  29 ++
 .../ng-app/template-files/src/main.ts         |   7 +-
 .../template-files/src/server/api/hello.ts    |  10 +
 .../ng-app/template-files/src/styles.ts       |   4 +-
 .../ng-app/template-files/tsconfig.app.ts     |   8 +-
 .../templates/generators/ng-env/files/env.ts  |   4 +-
 integration/demo-app/demo-app.ng-app.ts       |  16 +-
 .../demo-app/src/app/app.component.html       |  17 +-
 .../demo-app/src/app/app.component.spec.ts    |   2 +-
 integration/demo-app/src/app/app.component.ts |   6 +-
 .../demo-app/src/app/app.config.server.ts     |  11 +
 integration/demo-app/src/app/app.config.ts    |   9 +
 integration/demo-app/src/app/app.routes.ts    |   3 +
 integration/demo-app/src/assets/favicon.ico   | Bin 959 -> 15086 bytes
 integration/demo-app/src/index.html           |   2 +-
 integration/demo-app/src/main.server.ts       |   6 +
 integration/demo-app/src/main.ts              |  26 +-
 integration/demo-app/src/polyfills.ts         |  65 ---
 .../demo-app/src/server/api/v1/hello.ts       |   3 +
 integration/demo-app/tsconfig.app.json        |   7 +-
 tsconfig.json                                 |   4 +-
 workspace.jsonc                               |  33 +-
 104 files changed, 2113 insertions(+), 984 deletions(-)
 create mode 100644 angular/app-types/angular-app-type/application.bundler.ts
 create mode 100644 angular/app-types/angular-app-type/application.dev-server.ts
 create mode 100644 angular/app-types/angular-app-type/runtime/api-middleware.js
 create mode 100644 angular/app-types/angular-app-type/runtime/renderer.js
 delete mode 100644 angular/devkit/ng-compat/build-angular/browser-schema.ts
 create mode 100644 angular/devkit/ng-compat/build-angular/builder-options.ts
 create mode 100644 angular/devkit/ng-compat/build-angular/builders/application.ts
 create mode 100644 angular/devkit/ng-compat/build-angular/schemas/application.schema.ts
 create mode 100644 angular/devkit/vite/config.factory.ts
 delete mode 100644 angular/devkit/vite/dev-server/config.ts
 delete mode 100644 angular/devkit/vite/dev-server/types.ts
 delete mode 100644 angular/devkit/vite/dev-server/utils/html-plugin.ts
 delete mode 100644 angular/devkit/vite/dev-server/utils/index.ts
 delete mode 100644 angular/devkit/vite/dev-server/utils/mdx-config.ts
 delete mode 100644 angular/devkit/vite/ng-vite-dev-server.ts
 create mode 100644 angular/devkit/vite/ng-vite.bundler.ts
 create mode 100644 angular/devkit/vite/ng-vite.dev-server.ts
 create mode 100644 angular/devkit/vite/plugins/server-entry.plugin.ts
 rename angular/devkit/vite/{dev-server => }/utils/host-alias.ts (92%)
 create mode 100644 angular/devkit/vite/utils/types.ts
 create mode 100644 angular/devkit/vite/utils/utils.ts
 create mode 100644 angular/templates/generators/ng-app/template-files/src/app/app.config.server.ts
 create mode 100644 angular/templates/generators/ng-app/template-files/src/main.server.ts
 create mode 100644 angular/templates/generators/ng-app/template-files/src/server/api/hello.ts
 create mode 100644 integration/demo-app/src/app/app.config.server.ts
 create mode 100644 integration/demo-app/src/app/app.config.ts
 create mode 100644 integration/demo-app/src/app/app.routes.ts
 create mode 100644 integration/demo-app/src/main.server.ts
 delete mode 100644 integration/demo-app/src/polyfills.ts
 create mode 100644 integration/demo-app/src/server/api/v1/hello.ts

diff --git a/.gitignore b/.gitignore
index 016df259..7c8239ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,6 +61,7 @@ dist-legacy/
 flow-typed/
 eslint-report.html
 types/*
+.nitro
 
 #distrubution
 distribution/
diff --git a/angular/app-types/angular-app-type/angular-app-options.ts b/angular/app-types/angular-app-type/angular-app-options.ts
index b0b9466a..69e36ab9 100644
--- a/angular/app-types/angular-app-type/angular-app-options.ts
+++ b/angular/app-types/angular-app-type/angular-app-options.ts
@@ -1,9 +1,12 @@
-import { BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+import {
+  ApplicationOptions,
+  BrowserOptions,
+  DevServerOptions
+} from '@bitdev/angular.dev-services.common';
 import { Bundler } from '@teambit/bundler';
 import { WebpackConfigTransformer } from '@teambit/webpack';
 import { AngularDeployContext } from './deploy-context';
 
-
 export type AngularAppOptions = {
   /**
    * Name of the application.
@@ -16,9 +19,9 @@ export type AngularAppOptions = {
   sourceRoot: string;
 
   /**
-   * Instance of bundler to use. default is Webpack.
+   * Instance of bundler to use, default is esbuild after v17 and webpack before that.
    */
-  bundler?: Bundler | string;
+  bundler?: Bundler;
 
   /**
    * Set webpack build transformers
@@ -43,10 +46,10 @@ export type AngularAppOptions = {
   /**
    * Angular options for `bit build`
    */
-  angularBuildOptions: BrowserOptions;
+  angularBuildOptions: BrowserOptions | ApplicationOptions;
 
   /**
    * Angular options for `bit run`
    */
-  angularServeOptions: BrowserOptions & DevServerOptions;
+  angularServeOptions: (BrowserOptions & DevServerOptions) | (ApplicationOptions & DevServerOptions);
 };
diff --git a/angular/app-types/angular-app-type/angular.app-type.ts b/angular/app-types/angular-app-type/angular.app-type.ts
index 9e3f0351..ee45cea0 100644
--- a/angular/app-types/angular-app-type/angular.app-type.ts
+++ b/angular/app-types/angular-app-type/angular.app-type.ts
@@ -2,6 +2,7 @@ import { GenericAngularEnv, getWorkspace, NG_APP_NAME } from '@bitdev/angular.de
 import { Application, ApplicationType } from '@teambit/application';
 import { DependencyResolverAspect, DependencyResolverMain } from '@teambit/dependency-resolver';
 import { EnvContext, EnvHandler } from '@teambit/envs';
+import { Logger } from '@teambit/logger';
 import { Workspace } from '@teambit/workspace';
 import { AngularAppOptions } from './angular-app-options';
 import { AngularApp } from './angular.application';
@@ -12,7 +13,8 @@ interface AngularAppTypeOptions {
 }
 
 export class AngularAppType implements ApplicationType<AngularAppOptions> {
-  constructor(readonly name: string, private angularEnv: GenericAngularEnv, private context: EnvContext, private depsResolver: DependencyResolverMain, private workspace?: Workspace) {}
+  constructor(readonly name: string, private angularEnv: GenericAngularEnv, private context: EnvContext, private depsResolver: DependencyResolverMain, private logger: Logger, private workspace?: Workspace) {
+  }
 
   createApp(options: AngularAppOptions): Application {
     return new AngularApp(
@@ -20,7 +22,8 @@ export class AngularAppType implements ApplicationType<AngularAppOptions> {
       this.context,
       options,
       this.depsResolver,
-      this.workspace,
+      this.logger,
+      this.workspace
     );
   }
 
@@ -29,7 +32,8 @@ export class AngularAppType implements ApplicationType<AngularAppOptions> {
       const name = options.name || NG_APP_NAME;
       const depsResolver = context.getAspect<DependencyResolverMain>(DependencyResolverAspect.id);
       const workspace = getWorkspace(context);
-      return new AngularAppType(name, options.angularEnv, context, depsResolver, workspace);
+      const logger = context.createLogger(name);
+      return new AngularAppType(name, options.angularEnv, context, depsResolver, logger, workspace);
     };
   }
 }
diff --git a/angular/app-types/angular-app-type/angular.application.ts b/angular/app-types/angular-app-type/angular.application.ts
index 2fe6c398..95e3acac 100644
--- a/angular/app-types/angular-app-type/angular.application.ts
+++ b/angular/app-types/angular-app-type/angular.application.ts
@@ -1,23 +1,35 @@
-import { GenericAngularEnv } from '@bitdev/angular.dev-services.common';
-import { AngularPreview, BundlerProvider, DevServerProvider } from '@bitdev/angular.dev-services.preview.preview';
+import { VERSION } from '@angular/cli';
+import {
+  ApplicationOptions,
+  GenericAngularEnv,
+  normalizePath
+} from '@bitdev/angular.dev-services.common';
+import {
+  AngularPreview,
+  BundlerProvider,
+  DevServerProvider
+} from '@bitdev/angular.dev-services.preview.preview';
 import { AppBuildContext, AppContext, Application } from '@teambit/application';
 import { Bundler, BundlerContext, DevServer, DevServerContext } from '@teambit/bundler';
 import { Component } from '@teambit/component';
 import { DependencyResolverMain } from '@teambit/dependency-resolver';
 import { EnvContext, EnvHandler } from '@teambit/envs';
 import { CACHE_ROOT } from '@teambit/legacy/dist/constants';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
+import { Logger } from '@teambit/logger';
 import { Preview } from '@teambit/preview';
 import { Port } from '@teambit/toolbox.network.get-port';
 import { Workspace } from '@teambit/workspace';
-import { existsSync, mkdirSync, writeFileSync } from 'fs-extra';
+import assert from 'assert';
+import { existsSync, mkdirSync, outputJsonSync } from 'fs-extra';
 import { cloneDeep } from 'lodash';
 import objectHash from 'object-hash';
 import { join } from 'path';
 import { readConfigFile, sys } from 'typescript';
 import { AngularAppOptions } from './angular-app-options';
 import { AngularAppBuildResult } from './angular-build-result';
-import { expandIncludeExclude } from './utils';
+import { buildApplication } from './application.bundler';
+import { serveApplication } from './application.dev-server';
+import { expandIncludeExclude, JsonObject } from './utils';
 
 const writeHash = new Map<string, string>();
 
@@ -35,17 +47,18 @@ export class AngularApp implements Application {
     private envContext: EnvContext,
     readonly options: AngularAppOptions,
     private depsResolver: DependencyResolverMain,
+    private logger: Logger,
     private workspace?: Workspace
   ) {
     this.name = options.name;
 
-    const idName = `bitdev.angular/${this.name}`;
+    const idName = `bitdev.angular/${ this.name }`;
     this.tempFolder = workspace?.getTempDir(idName) || join(CACHE_ROOT, idName);
     if (!existsSync(this.tempFolder)) {
       mkdirSync(this.tempFolder, { recursive: true });
     }
 
-    this.tsconfigPath = pathNormalizeToLinux(join(this.tempFolder, `__tsconfig-${Date.now()}.json`));
+    this.tsconfigPath = normalizePath(join(this.tempFolder, `tsconfig/tsconfig-${ Date.now() }.json`));
     this.preview = this.getPreview();
   }
 
@@ -55,11 +68,12 @@ export class AngularApp implements Application {
     return join(artifactsDir, this.name);
   }
 
-  private getDevServerContext(context: AppContext): DevServerContext {
+  private getDevServerContext(context: AppContext, appRootPath: string): DevServerContext {
+    // const ngEnvOptions = this.angularEnv.getNgEnvOptions();
     return Object.assign(cloneDeep(context), {
       entry: [],
-      rootPath: '',
-      publicPath: `${this.publicDir}/${this.options.name}`,
+      rootPath: /*ngEnvOptions.devServer === 'vite' ? appRootPath : */'',
+      publicPath: `${ this.publicDir }/${ this.options.name }`,
       title: this.options.name
     });
   }
@@ -67,7 +81,7 @@ export class AngularApp implements Application {
   private getBundlerContext(context: AppBuildContext): BundlerContext {
     const { capsule, artifactsDir } = context;
     const publicDir = this.getPublicDir(artifactsDir);
-    const outputPath = pathNormalizeToLinux(join(capsule.path, publicDir));
+    const outputPath = normalizePath(join(capsule.path, publicDir));
 
     return Object.assign(cloneDeep(context), {
       targets: [{
@@ -76,7 +90,7 @@ export class AngularApp implements Application {
         outputPath
       }],
       entry: [],
-      rootPath: '/',
+      rootPath: '.',
       appName: this.options.name
     });
   }
@@ -97,73 +111,81 @@ export class AngularApp implements Application {
     });
   }
 
-  private generateTsConfig(bitCmps: Component[], appRootPath: string, tsconfigPath: string): string {
-    const tsconfigJSON = readConfigFile(tsconfigPath, sys.readFile).config;
+  private generateTsConfig(bitCmps: Component[], appRootPath: string, tsconfigPath: string, serverEntry?: string): void {
+    const tsconfigJSON: JsonObject = readConfigFile(tsconfigPath, sys.readFile).config;
 
     // Add the paths to tsconfig to remap bit components to local folders
     tsconfigJSON.compilerOptions.paths = tsconfigJSON.compilerOptions.paths || {};
     bitCmps.forEach((dep: Component) => {
-        let componentDir = this.workspace?.componentDir(dep.id, {
-          ignoreVersion: true
-        });
-        if (componentDir) {
-          componentDir = pathNormalizeToLinux(componentDir);
-          const pkgName = this.depsResolver.getPackageName(dep);
-          // TODO we should find a way to use the real entry file based on the component config because people can change it
-          tsconfigJSON.compilerOptions.paths[pkgName] = [`${componentDir}/public-api.ts`, `${componentDir}`];
-          tsconfigJSON.compilerOptions.paths[`${pkgName}/*`] = [`${componentDir}/*`];
-        }
+      let componentDir = this.workspace?.componentDir(dep.id, {
+        ignoreVersion: true
+      });
+      if (componentDir) {
+        componentDir = normalizePath(componentDir);
+        const pkgName = this.depsResolver.getPackageName(dep);
+        // TODO we should find a way to use the real entry file based on the component config because people can change it
+        tsconfigJSON.compilerOptions.paths[pkgName] = [`${ componentDir }/public-api.ts`, `${ componentDir }`];
+        tsconfigJSON.compilerOptions.paths[`${ pkgName }/*`] = [`${ componentDir }/*`];
+      }
     });
 
+    if (serverEntry) {
+      tsconfigJSON.files.push(serverEntry);
+    }
+
     const tsconfigContent = expandIncludeExclude(tsconfigJSON, this.tsconfigPath, [appRootPath]);
     const hash = objectHash(tsconfigContent);
-
     // write only if link has changed (prevents triggering fs watches)
     if (writeHash.get(this.tsconfigPath) !== hash) {
-      writeFileSync(this.tsconfigPath, tsconfigContent);
+      outputJsonSync(this.tsconfigPath, tsconfigContent, { spaces: 2 });
       writeHash.set(this.tsconfigPath, hash);
     }
+  }
+
+  async getDevServer(context: AppContext, appRootPath: string): Promise<DevServer> {
+    const devServerContext = this.getDevServerContext(context, appRootPath);
+    const preview = this.preview(this.envContext);
 
-    return tsconfigContent;
+    return preview.getDevServer(devServerContext)(this.envContext);
   }
 
-  async getDevServer(context: AppContext): Promise<DevServer> {
-    if(!this.workspace) {
-      throw new Error('workspace is not defined');
-    }
+  // TODO: fix return type once bit has a new stable version
+  async run(context: AppContext): Promise<any> {
+    assert(this.workspace, 'Workspace is not defined');
+    const port = context.port || (await Port.getPortFromRange(this.options.portRange || [3000, 4000]));
     const appRootPath = this.workspace.componentDir(context.appComponent.id, {
       ignoreVersion: true
-    }) || '';
+    });
     const tsconfigPath = join(appRootPath, this.options.angularServeOptions.tsConfig);
     const workspaceCmpsIDs = await this.workspace.listIds();
     const bitCmps = await this.workspace.getMany(workspaceCmpsIDs);
     this.generateTsConfig(bitCmps, appRootPath, tsconfigPath);
-    const devServerContext = this.getDevServerContext(context);
-    const preview = this.preview(this.envContext);
 
-    return preview.getDevServer(devServerContext)(this.envContext);
-  }
+    if (Number(VERSION.major) >= 16) {
+      await serveApplication({
+        angularOptions: {
+          ...this.options.angularBuildOptions as ApplicationOptions,
+          tsConfig: this.tsconfigPath
+        },
+        sourceRoot: this.options.sourceRoot || 'src',
+        workspaceRoot: appRootPath,
+        port,
+        logger: this.logger,
+        tempFolder: this.tempFolder
+      });
+      return port;
+    }
 
-  async run(context: AppContext): Promise<number> {
-    const port = context.port || (await Port.getPortFromRange(this.options.portRange || [3000, 4000]));
-    const devServer = await this.getDevServer(context);
+    const devServer = await this.getDevServer(context, appRootPath);
     await devServer.listen(port);
     return port;
   }
 
   async getBundler(context: AppBuildContext): Promise<Bundler> {
-    if (this.options.bundler && typeof this.options.bundler !== 'string') {
-      return this.options.bundler as Bundler;
+    if (this.options.bundler) {
+      return this.options.bundler;
     }
 
-    if (this.options.bundler === 'vite') {
-      throw new Error('implement vite bundler');
-    }
-
-    const { capsule } = context;
-    const appRootPath = capsule.path;
-    const tsconfigPath = join(appRootPath, this.options.angularBuildOptions.tsConfig);
-    this.generateTsConfig([capsule.component], appRootPath, tsconfigPath);
     const bundlerContext = this.getBundlerContext(context);
     const preview = this.preview(this.envContext);
 
@@ -171,10 +193,33 @@ export class AngularApp implements Application {
   }
 
   async build(context: AppBuildContext): Promise<AngularAppBuildResult> {
-    const bundler = await this.getBundler(context);
-    await bundler.run();
+    const { capsule } = context;
+    const outputPath = this.getPublicDir(context.artifactsDir);
+    const appRootPath = capsule.path;
+    const tsconfigPath = join(appRootPath, this.options.angularBuildOptions.tsConfig);
+    const appOptions = this.options.angularBuildOptions as ApplicationOptions;
+    const entryServer = appOptions.ssr && Number(VERSION.major) >= 17 ? './entry.server.ts' : undefined;
+    this.generateTsConfig([capsule.component], appRootPath, tsconfigPath, entryServer);
+
+    if (!this.options.bundler && Number(VERSION.major) >= 16) {
+      await buildApplication({
+        angularOptions: {
+          ...appOptions,
+          tsConfig: this.tsconfigPath
+        },
+        outputPath,
+        sourceRoot: this.options.sourceRoot || 'src',
+        workspaceRoot: context.capsule.path,
+        logger: this.logger,
+        tempFolder: this.tempFolder,
+        entryServer
+      });
+    } else {
+      const bundler = await this.getBundler(context);
+      await bundler.run();
+    }
     return {
-      publicDir: `${this.getPublicDir(context.artifactsDir)}/${this.publicDir}`
+      publicDir: outputPath
     };
   }
 }
diff --git a/angular/app-types/angular-app-type/application.bundler.ts b/angular/app-types/angular-app-type/application.bundler.ts
new file mode 100644
index 00000000..f9c3a5d8
--- /dev/null
+++ b/angular/app-types/angular-app-type/application.bundler.ts
@@ -0,0 +1,261 @@
+/* eslint-disable no-param-reassign */
+import { OutputHashing } from '@angular-devkit/build-angular';
+import type { JsonObject } from '@angular-devkit/core';
+import { VERSION } from '@angular/cli';
+import {
+  ApplicationOptions,
+  dedupPaths,
+  getLoggerApi,
+  loadEsmModule,
+  normalizePath
+} from '@bitdev/angular.dev-services.common';
+import { buildApplicationInternal } from '@bitdev/angular.dev-services.ng-compat';
+import { Logger } from '@teambit/logger';
+import assert from 'assert';
+import { outputFileSync } from 'fs-extra';
+// @ts-ignore
+import type { NitroConfig } from 'nitropack';
+import { basename, extname, join, posix, relative, resolve } from 'path';
+import { getIndexInputFile } from './utils';
+
+export type BuildApplicationOptions = {
+  angularOptions: Partial<ApplicationOptions>;
+  outputPath: string;
+  sourceRoot: string;
+  workspaceRoot: string;
+  logger: Logger;
+  tempFolder: string;
+  entryServer?: string;
+}
+
+export async function buildApplication(options: BuildApplicationOptions): Promise<void> {
+  const { angularOptions: { tsConfig, ssr } } = options;
+  const isSsr = !!ssr && Number(VERSION.major) >= 17;
+
+  assert(tsConfig, 'tsConfig option is required');
+
+  if(isSsr) {
+    addEntryServer(options);
+  }
+
+  const appOptions = getAppOptions(options, isSsr);
+  const builderContext = getBuilderContext(options);
+  const builderPlugins: any[] = [];
+
+  for await (const result of buildApplicationInternal(
+    appOptions as any,
+    builderContext,
+    { write: true },
+    builderPlugins
+  )) {
+    if (!result.success && result.errors) {
+      throw new Error(result.errors.map((err: any) => err.text).join('\n'));
+    }
+  }
+
+  if (isSsr) {
+    await buildNitro(options);
+  }
+}
+
+function addEntryServer(options: BuildApplicationOptions): void {
+  const { entryServer, angularOptions: { ssr, server } } = options;
+  if (ssr && entryServer) {
+    const fileContent = `import type { ApplicationRef } from '@angular/core';
+import { renderApplication, renderModule } from '@angular/platform-server';
+import bootstrap from '${ server?.replace(extname(server), '') }';
+
+function isBootstrapFn(value: unknown): value is () => Promise<ApplicationRef> {
+  // We can differentiate between a module and a bootstrap function by reading compiler-generated "ɵmod" static property:
+  return typeof value === 'function' && !('ɵmod' in value);
+}
+
+export default async function render(url: string, document: string) {
+  let html: string;
+  if (isBootstrapFn(bootstrap)) {
+    html = await renderApplication(bootstrap, {
+      document,
+      url
+    });
+  } else {
+    html = await renderModule(bootstrap, {
+      document,
+      url
+    });
+  }
+
+  return html;
+}`;
+    outputFileSync(resolve(options.workspaceRoot, entryServer), fileContent);
+  }
+}
+
+function getAppOptions(options: BuildApplicationOptions, isSsr: boolean): any {
+  const { entryServer, angularOptions, outputPath, sourceRoot, workspaceRoot } = options;
+
+  // declare constants for all reusable values here
+  const normalizedIndex = `./${ join(sourceRoot, 'index.html') }`;
+  const normalizedBrowser = `./${ join(sourceRoot, 'main.ts') }`;
+
+  const dedupedAssets = dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]);
+  const dedupedStyles = dedupPaths([posix.join(sourceRoot, `styles.${angularOptions.inlineStyleLanguage}`), ...(angularOptions.styles ?? [])]);
+
+  return {
+    ...angularOptions,
+    baseHref: angularOptions.baseHref ?? './',
+    preserveSymlinks: false,
+    outputPath,
+    index: angularOptions.index ?? normalizedIndex,
+    browser: angularOptions.browser ?? normalizedBrowser,
+    tsConfig: relative(workspaceRoot, angularOptions.tsConfig!),
+    assets: dedupedAssets,
+    styles: dedupedStyles,
+    scripts: angularOptions.scripts,
+    namedChunks: angularOptions.namedChunks ?? true,
+    optimization: angularOptions.optimization ?? true,
+    aot: true,
+    deleteOutputPath: true,
+    sourceMap: angularOptions.sourceMap ?? true,
+    outputHashing: angularOptions.outputHashing ?? OutputHashing.All,
+    watch: false,
+    server: isSsr ? angularOptions.server : undefined,
+    prerender: isSsr ? (angularOptions.prerender ?? !!angularOptions.server) : undefined,
+    ssr: isSsr ? {
+      entry: entryServer
+    } : undefined
+  };
+}
+
+
+function getBuilderContext(options: BuildApplicationOptions): any {
+  const { workspaceRoot, sourceRoot, tempFolder } = options;
+  return {
+    id: 1,
+    builder: {
+      builderName: '@bitdev/build-angular:application',
+      description: 'Bit Angular Application Builder',
+      optionSchema: {}
+    },
+    logger: getLoggerApi(options.logger),
+    workspaceRoot: workspaceRoot,
+    currentDirectory: '',
+    // doesn't matter, just needs to exist
+    target: {
+      project: 'bit-ng-app-builder',
+      target: 'build'
+    },
+    getProjectMetadata: function(projectName: string): Promise<JsonObject> {
+      return Promise.resolve({
+        root: '',
+        sourceRoot,
+        cli: { cache: { enabled: true, path: resolve(tempFolder, 'angular/cache') } }
+      });
+    }
+  };
+}
+
+async function getNitroConfig(options: BuildApplicationOptions): Promise<NitroConfig> {
+  const {
+    workspaceRoot,
+    tempFolder,
+    outputPath,
+    angularOptions: { ssr, index, prerender }
+  } = options;
+
+  const outputDir = normalizePath(join(workspaceRoot, outputPath));
+  const browserDir = normalizePath(resolve(outputDir, 'browser'));
+  const serverDir = normalizePath(resolve(outputDir, 'server'));
+  const nitroDir = normalizePath(resolve(outputDir, 'nitro'));
+  const indexPath = getIndexInputFile(index!);
+
+  const prerenderedRoutes = prerender ? (await import(`${ outputDir }/prerendered-routes.json`)).default : undefined;
+
+  return {
+    rootDir: workspaceRoot,
+    logLevel: 1, // TODO reset this to 3 or 2 https://github.com/unjs/consola/#log-level
+    srcDir: normalizePath(`${ workspaceRoot }/src/server`),
+    scanDirs: [normalizePath(`${ workspaceRoot }/src/server`)],
+    buildDir: resolve(tempFolder, 'nitro'),
+
+    alias: ssr ? {
+      '#alias/entry.server': normalizePath(join(serverDir, 'server.mjs')),
+      '#alias/index': normalizePath(join(serverDir, `${ basename(indexPath, extname(indexPath)) }.server.html`))
+    } : {},
+    serverAssets: ssr ? [{
+      baseName: 'public',
+      dir: browserDir
+    }] : [],
+    publicAssets: ssr ? [{
+      dir: browserDir
+    }] : [],
+    output: ssr ? {
+      dir: nitroDir,
+      publicDir: posix.join(nitroDir, 'public')
+    } : {},
+    externals: {
+      external: [
+        'rxjs',
+        'node-fetch-native/dist/polyfill'
+      ]
+    },
+    moduleSideEffects: [
+      'zone.js/node',
+      'zone.js/fesm2015/zone-node'
+    ],
+    renderer: ssr ? normalizePath(require.resolve('./runtime/renderer')) : undefined,
+    // handlers: ssr ? [{
+    //   handler: normalizePath(require.resolve('./runtime/api-middleware')),
+    //   middleware: true
+    // }] : [],
+    prerender: prerenderedRoutes,
+    typescript: {
+      generateTsConfig: false
+    }
+    // TODO allow customizing this
+    // runtimeConfig: { ...nitroOptions?.runtimeConfig },
+  };
+}
+
+async function buildNitro(options: BuildApplicationOptions): Promise<void> {
+  const logger = options.logger.createLongProcessLogger('Building nitro server', options.angularOptions.prerender ? 2 : 1);
+  const nitroConfig = await getNitroConfig(options);
+
+  const {
+    createNitro,
+    build,
+    prepare,
+    copyPublicAssets,
+    prerender
+  } = await loadEsmModule<typeof import('nitropack')>('nitropack');
+
+
+  const nitro = await createNitro({
+    dev: false,
+    ...nitroConfig
+  });
+
+  await prepare(nitro);
+  await copyPublicAssets(nitro);
+
+  // const indexOutput = `${ nitroConfig?.output?.publicDir }/index.html`;
+  // if (
+  //   nitroConfig?.prerender?.routes
+  //   && nitroConfig?.prerender?.routes.find((route: string) => route === '/')
+  //   && existsSync(indexOutput)
+  // ) {
+  //   // Remove the root index.html so it can be replaced with the prerendered version
+  //   unlinkSync(`${ nitroConfig?.output?.publicDir }/index.html`);
+  // }
+
+
+  if (options.angularOptions.prerender) {
+    logger.logProgress(`Prerendering static pages`);
+    await prerender(nitro);
+  }
+
+  logger.logProgress('Building Server files');
+  await build(nitro);
+
+  await nitro.close();
+  logger.end();
+}
diff --git a/angular/app-types/angular-app-type/application.dev-server.ts b/angular/app-types/angular-app-type/application.dev-server.ts
new file mode 100644
index 00000000..97cbb42b
--- /dev/null
+++ b/angular/app-types/angular-app-type/application.dev-server.ts
@@ -0,0 +1,183 @@
+/* eslint-disable no-param-reassign */
+import { executeDevServerBuilder, OutputHashing } from '@angular-devkit/build-angular';
+import type { JsonObject } from '@angular-devkit/core';
+import { VERSION } from '@angular/cli';
+import {
+  dedupPaths,
+  getLoggerApi,
+  loadEsmModule,
+  normalizePath
+} from '@bitdev/angular.dev-services.common';
+import {
+  type ApplicationBuilderOptions,
+  type DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
+import { Logger } from '@teambit/logger';
+import assert from 'assert';
+import { createEvent } from 'h3';
+// @ts-ignore
+import type { NitroConfig } from 'nitropack';
+import { join, posix, relative, resolve } from 'path';
+// @ts-ignore
+import type { Connect } from 'vite';
+
+export type ServeApplicationOptions = {
+  angularOptions: Partial<ApplicationBuilderOptions & DevServerBuilderOptions>;
+  sourceRoot: string;
+  workspaceRoot: string;
+  logger: Logger;
+  port: number;
+  tempFolder: string;
+}
+
+// TODO allow customizing this
+const API_ROUTE = '/api';
+const OUTPUT_PATH = 'dist';
+const BUILDER_NAME = '@angular-devkit/build-angular:application';
+const CACHE_PATH = 'angular/cache';
+
+export async function serveApplication(options: ServeApplicationOptions): Promise<void> {
+  const {
+    angularOptions
+  } = options;
+  const isSsr = !!angularOptions.server && Number(VERSION.major) >= 17;
+
+  assert(angularOptions.tsConfig, 'tsConfig option is required');
+
+  const appOptions = getAppOptions(options, isSsr);
+  const builderContext = getBuilderContext(options, appOptions);
+  // intercept SIGINT and exit cleanly, otherwise the process will not exit properly on Ctrl+C
+  process.on('SIGINT', () => process.exit(1));
+
+  const devServerOptions = isSsr ? {
+    middleware: [await createNitroApiMiddleware(options)]
+  } : undefined;
+
+  // @ts-ignore only v17+ has 4 arguments, previous versions only have 3
+  const res = await executeDevServerBuilder(appOptions, builderContext as any, undefined, devServerOptions).toPromise();
+  console.log(res);
+}
+
+function getAppOptions(options: ServeApplicationOptions, isSsr: boolean): ApplicationBuilderOptions & DevServerBuilderOptions {
+  const { angularOptions, port, sourceRoot, workspaceRoot } = options;
+  // declare constants for all reusable values here
+  const normalizedIndex = `./${ join(sourceRoot, 'index.html') }`;
+  const normalizedBrowser = `./${ join(sourceRoot, 'main.ts') }`;
+  const serverPath = `./${ join(sourceRoot, 'main.server.ts') }`;
+
+  const dedupedAssets = dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]);
+  const dedupedStyles = dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage }`), ...(angularOptions.styles ?? [])]);
+
+  return {
+    ...angularOptions,
+    baseHref: angularOptions.baseHref ?? './',
+    preserveSymlinks: false,
+    outputPath: OUTPUT_PATH,
+    index: angularOptions.index ?? normalizedIndex,
+    browser: angularOptions.browser ?? normalizedBrowser,
+    tsConfig: relative(workspaceRoot, angularOptions.tsConfig!),
+    assets: dedupedAssets,
+    styles: dedupedStyles,
+    scripts: angularOptions.scripts,
+    namedChunks: angularOptions.namedChunks ?? true,
+    optimization: angularOptions.optimization ?? true,
+    aot: true,
+    deleteOutputPath: true,
+    sourceMap: angularOptions.sourceMap ?? true,
+    outputHashing: angularOptions.outputHashing ?? OutputHashing.All,
+    watch: true,
+    server: isSsr ? angularOptions.server ?? serverPath : undefined,
+    prerender: isSsr ? angularOptions.prerender ?? !!angularOptions.server : false,
+    ssr: isSsr ? (angularOptions.ssr ?? !!angularOptions.server) : false,
+    port,
+    browserTarget: BUILDER_NAME,
+    // @ts-ignore Angular 17+
+    buildTarget: BUILDER_NAME
+  };
+}
+
+function getBuilderContext(options: ServeApplicationOptions, appOptions: ApplicationBuilderOptions & DevServerBuilderOptions) {
+  const { workspaceRoot } = options;
+  return {
+    id: 1,
+    builder: {
+      builderName: BUILDER_NAME,
+      description: 'Bit Angular Application Builder',
+      optionSchema: {}
+    },
+    logger: getLoggerApi(options.logger),
+    workspaceRoot: workspaceRoot,
+    currentDirectory: '',
+    // doesn't matter, just needs to exist
+    target: {
+      project: 'bit-ng-app-builder',
+      target: 'development'
+    },
+    getProjectMetadata: getProjectMetadata(options),
+    addTeardown: (teardown: () => Promise<void> | void) => {
+      teardown();
+      return;
+    },
+    getBuilderNameForTarget: () => Promise.resolve(BUILDER_NAME),
+    getTargetOptions: () => Promise.resolve(appOptions as any as JsonObject),
+    validateOptions: () => Promise.resolve(appOptions as any)
+  };
+}
+
+function getProjectMetadata(options: ServeApplicationOptions) {
+  const { sourceRoot, tempFolder } = options;
+  return function(projectName: string): Promise<JsonObject> {
+    return Promise.resolve({
+      root: '',
+      sourceRoot,
+      cli: {
+        cache: {
+          enabled: true,
+          path: resolve(tempFolder, CACHE_PATH)
+        }
+      }
+    });
+  };
+}
+
+function getNitroConfig(options: ServeApplicationOptions): NitroConfig {
+  const { workspaceRoot, tempFolder } = options;
+  const rootDir = workspaceRoot;
+  return {
+    rootDir,
+    logLevel: 2,
+    srcDir: normalizePath(`${ rootDir }/src/server`),
+    scanDirs: [normalizePath(`${ rootDir }/src/server`)],
+    buildDir: resolve(tempFolder, 'nitro')
+  };
+}
+
+async function createNitroApiMiddleware(options: ServeApplicationOptions): Promise<Connect.NextHandleFunction> {
+  const nitroConfig = getNitroConfig(options);
+
+  const {
+    createNitro,
+    createDevServer,
+    build
+  } = await loadEsmModule<typeof import('nitropack')>('nitropack');
+
+  const nitro = await createNitro({
+    dev: true,
+    ...nitroConfig
+  });
+
+  const server = createDevServer(nitro);
+  await build(nitro);
+
+  return async(
+    req: any,
+    res: any,
+    next: any
+  ) => {
+    if (req.originalUrl.startsWith(API_ROUTE)) {
+      await server.app.handler(createEvent(req, res));
+      return;
+    }
+    next();
+  };
+}
diff --git a/angular/app-types/angular-app-type/component.json b/angular/app-types/angular-app-type/component.json
index e02010e0..8f065332 100644
--- a/angular/app-types/angular-app-type/component.json
+++ b/angular/app-types/angular-app-type/component.json
@@ -8,12 +8,17 @@
     "teambit.dependencies/dependency-resolver": {
       "policy": {
         "dependencies": {
+          "h3": "^1.9.0",
+          "nitropack": "^2.8.0",
           "@angular-devkit/build-angular": "-",
-          "typescript": "-"
+          "typescript": "-",
+          "#alias": "-"
         },
         "peerDependencies": {
           "@angular-devkit/build-angular": ">= 0.0.1",
-          "typescript": ">= 3.5.3"
+          "@angular/cli": ">= 13.0.0",
+          "typescript": ">= 3.5.3",
+          "vite": "^4.5.0 || ^5.0.0"
         }
       }
     }
diff --git a/angular/app-types/angular-app-type/runtime/api-middleware.js b/angular/app-types/angular-app-type/runtime/api-middleware.js
new file mode 100644
index 00000000..b350311a
--- /dev/null
+++ b/angular/app-types/angular-app-type/runtime/api-middleware.js
@@ -0,0 +1,29 @@
+/**
+ * This file is written in JavaScript
+ * because it is used by Nitro to build
+ * the renderer for SSR.
+ *
+ * The package is shipped as commonjs
+ * which won't be parsed by Nitro correctly.
+ */
+import { eventHandler, proxyRequest } from 'h3';
+
+export default eventHandler(async (event) => {
+  const apiPrefix = `/${import.meta.env.RUNTIME_CONFIG?.apiPrefix ?? 'api'}`;
+  if (event.node.req.url?.startsWith(apiPrefix)) {
+    const reqUrl = event.node.req.url?.replace(apiPrefix, '');
+
+    if (
+      event.node.req.method === 'GET' &&
+      // in the case of XML routes, we want to proxy the request so that nitro gets the correct headers
+      // and can render the XML correctly as a static asset
+      !event.node.req.url?.endsWith('.xml')
+    ) {
+      return $fetch(reqUrl);
+    }
+
+    return proxyRequest(event, reqUrl, {
+      fetch: $fetch.native,
+    });
+  }
+});
diff --git a/angular/app-types/angular-app-type/runtime/renderer.js b/angular/app-types/angular-app-type/runtime/renderer.js
new file mode 100644
index 00000000..345dcfb4
--- /dev/null
+++ b/angular/app-types/angular-app-type/runtime/renderer.js
@@ -0,0 +1,18 @@
+/**
+ * This file is written in JavaScript
+ * because it is used by Nitro to build
+ * the renderer for SSR.
+ *
+ * The package is shipped as commonjs
+ * which won't be parsed by Nitro correctly.
+ */
+import { eventHandler } from 'h3';
+
+import renderer from '#alias/entry.server';
+import template from '#alias/index';
+
+export default eventHandler(async (event) => {
+  const html = await renderer(event.node.req.url, template);
+
+  return html;
+});
diff --git a/angular/app-types/angular-app-type/utils.ts b/angular/app-types/angular-app-type/utils.ts
index e4fc58b8..d6c2b1f3 100644
--- a/angular/app-types/angular-app-type/utils.ts
+++ b/angular/app-types/angular-app-type/utils.ts
@@ -1,6 +1,11 @@
-import { pathNormalizeToLinux } from "@teambit/legacy/dist/utils";
+import { ApplicationOptions, normalizePath } from '@bitdev/angular.dev-services.common';
+import assert from 'assert';
 import { flatten } from 'lodash';
-import { relative, dirname } from 'path';
+import { dirname, relative } from 'path';
+
+export interface JsonObject {
+  [prop: string]: any;
+}
 
 /**
  * Takes a tsconfig.json file, a list of component directories, and returns a new tsconfig.json file with the include
@@ -10,7 +15,7 @@ import { relative, dirname } from 'path';
  * @param {string[]} compDirs - An array of paths to the component directories.
  * @returns the tsConfig object.
  */
-export function expandIncludeExclude(tsconfigJSON: any, targetPath: string, compDirs: string[]): string {
+export function expandIncludeExclude(tsconfigJSON: JsonObject, targetPath: string, compDirs: string[]): JsonObject {
   // eslint-disable-next-line no-param-reassign
   targetPath = dirname(targetPath);
 
@@ -19,7 +24,7 @@ export function expandIncludeExclude(tsconfigJSON: any, targetPath: string, comp
     tsconfigJSON.include = flatten(
       tsconfigJSON.include.map((includedPath: string) => {
         return compDirs.map((compDir: string) => {
-          const compDirRelative = pathNormalizeToLinux(relative(targetPath, compDir));
+          const compDirRelative = normalizePath(relative(targetPath, compDir));
           return `${compDirRelative}/${includedPath}`;
         });
       })
@@ -30,7 +35,7 @@ export function expandIncludeExclude(tsconfigJSON: any, targetPath: string, comp
     tsconfigJSON.exclude = flatten(
       tsconfigJSON.exclude.map((excludedPath: string) => {
         return compDirs.map((compDir: string) => {
-          const compDirRelative = pathNormalizeToLinux(relative(targetPath, compDir));
+          const compDirRelative = normalizePath(relative(targetPath, compDir));
           return `${compDirRelative}/${excludedPath}`;
         });
       })
@@ -41,12 +46,20 @@ export function expandIncludeExclude(tsconfigJSON: any, targetPath: string, comp
     tsconfigJSON.files = flatten(
       tsconfigJSON.files.map((filesPath: string) => {
         return compDirs.map((compDir: string) => {
-          const compDirRelative = pathNormalizeToLinux(relative(targetPath, compDir));
+          const compDirRelative = normalizePath(relative(targetPath, compDir));
           return `${compDirRelative}/${filesPath}`;
         });
       })
     );
   }
 
-  return JSON.stringify(tsconfigJSON, undefined, 2);
+  return tsconfigJSON;
+}
+
+export function getIndexInputFile(index: ApplicationOptions['index']): string {
+  assert(index, 'No index file provided');
+  if (typeof index === 'string') {
+    return index;
+  }
+  return (index as any).input;
 }
diff --git a/angular/devkit/common/component.json b/angular/devkit/common/component.json
index c3fb7ede..32603cbb 100644
--- a/angular/devkit/common/component.json
+++ b/angular/devkit/common/component.json
@@ -9,7 +9,8 @@
       "policy": {
         "dependencies": {
           "@angular-devkit/build-angular": "-",
-          "typescript": "-"
+          "typescript": "-",
+          "normalize-path": "^3.0.0"
         },
         "peerDependencies": {
           "@angular-devkit/build-angular": ">= 0.0.1",
diff --git a/angular/devkit/common/env-options.ts b/angular/devkit/common/env-options.ts
index 49db2c51..6ab1300b 100644
--- a/angular/devkit/common/env-options.ts
+++ b/angular/devkit/common/env-options.ts
@@ -22,7 +22,7 @@ export type AngularEnvOptions = {
    * Vite only works for apps, not preview yet.
    * @default 'webpack'
    */
-  devServer?: 'webpack' | 'vite';
+  // devServer?: 'webpack' | 'vite';
   /**
    * The bundler to use: webpack or vite.
    * Vite only works for apps, not preview yet.
diff --git a/angular/devkit/common/generic-angular-env.ts b/angular/devkit/common/generic-angular-env.ts
index 668c7c7c..c1181c56 100644
--- a/angular/devkit/common/generic-angular-env.ts
+++ b/angular/devkit/common/generic-angular-env.ts
@@ -1,4 +1,8 @@
-import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
+import type {
+  ApplicationBuilderOptions,
+  BrowserBuilderOptions,
+  DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
 import { AppsEnv } from '@teambit/application';
 import { BuilderEnv } from '@teambit/builder';
 import { Bundler, BundlerContext, DevServer, DevServerContext } from '@teambit/bundler';
@@ -8,8 +12,9 @@ import { PreviewEnv } from '@teambit/preview';
 import { Configuration, WebpackConfigTransformer, WebpackConfigWithDevServer } from '@teambit/webpack';
 import { AngularEnvOptions } from './env-options';
 
-export type BrowserOptions = Omit<BrowserBuilderOptions, "outputPath" | "preserveSymlinks">;
-export type DevServerOptions = Omit<DevServerBuilderOptions, "aot" | "baseHref" | "browserTarget" | "commonChunk" | "deployUrl" | "hmrWarning" | "open" | "optimization" | "port" | "progress" | "servePathDefaultWarning" | "sourceMap" | "vendorChunk">;
+export type BrowserOptions = Omit<BrowserBuilderOptions, "outputPath" | "deleteOutputPath" | "preserveSymlinks" | "inlineStyleLanguage"> & {inlineStyleLanguage?: "css" | "less" | "sass" | "scss"};
+export type DevServerOptions = Omit<DevServerBuilderOptions, "aot" | "baseHref" | "browserTarget" | "commonChunk" | "deployUrl" | "hmrWarning" | "open" | "progress" | "servePathDefaultWarning" | "vendorChunk">;
+export type ApplicationOptions = Omit<ApplicationBuilderOptions, "outputPath" | "deleteOutputPath" | "preserveSymlinks" | "aot">
 
 export interface GenericAngularEnv
   extends AppsEnv,
@@ -22,7 +27,7 @@ export interface GenericAngularEnv
     devServerContext: DevServerContext,
     ngEnvOptions: AngularEnvOptions,
     transformers?: WebpackConfigTransformer[],
-    angularOptions?: Partial<BrowserOptions & DevServerOptions>,
+    angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>,
     webpackOptions?: Partial<WebpackConfigWithDevServer | Configuration>,
     sourceRoot?: string
   ): AsyncEnvHandler<DevServer>;
@@ -31,7 +36,7 @@ export interface GenericAngularEnv
     bundlerContext: BundlerContext,
     ngEnvOptions: AngularEnvOptions,
     transformers?: WebpackConfigTransformer[],
-    angularOptions?: Partial<BrowserOptions & DevServerOptions>,
+    angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>,
     webpackOptions?: Partial<WebpackConfigWithDevServer | Configuration>,
     sourceRoot?: string
   ): AsyncEnvHandler<Bundler>
diff --git a/angular/devkit/common/index.ts b/angular/devkit/common/index.ts
index 5b9be709..4be2731c 100644
--- a/angular/devkit/common/index.ts
+++ b/angular/devkit/common/index.ts
@@ -1,4 +1,4 @@
 export type { AngularEnvOptions, WebpackConfigFactory } from './env-options';
-export { GenericAngularEnv, DevServerOptions, BrowserOptions } from './generic-angular-env';
+export * from './generic-angular-env';
 export * from './utils';
 export { AngularComponentTemplateOptions } from './templates';
diff --git a/angular/devkit/common/utils.ts b/angular/devkit/common/utils.ts
index 6a45640a..48a85357 100644
--- a/angular/devkit/common/utils.ts
+++ b/angular/devkit/common/utils.ts
@@ -4,11 +4,13 @@ import { Component, ComponentID } from '@teambit/component';
 import { DevFilesMain } from '@teambit/dev-files';
 import { EnvContext } from '@teambit/envs';
 import { IsolatorMain } from '@teambit/isolator';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
+import { Logger } from '@teambit/logger';
 import { PkgMain } from '@teambit/pkg';
 import TesterAspect from '@teambit/tester';
 import WorkspaceAspect, { Workspace } from '@teambit/workspace';
-import { existsSync, mkdirSync, writeFileSync } from 'fs-extra';
+import { outputFileSync } from 'fs-extra';
+// @ts-ignore
+import normalize from 'normalize-path';
 import objectHash from 'object-hash';
 import { dirname, join, posix, resolve } from 'path';
 import { readConfigFile, sys } from 'typescript';
@@ -116,13 +118,15 @@ export function isBuildContext(context: DevServerContext | BundlerContext): cont
   return (context as BundlerContext).capsuleNetwork !== undefined;
 }
 
-export function isAppDevContext(context: DevServerContext | AppContext): context is DevServerContext & AppContext {
+export function isAppDevContext(context: any): context is DevServerContext & AppContext {
   return (context as any).appName !== undefined;
 }
 
-export function isAppBuildContext(
-  context: BundlerContext | AppBuildContext
-): context is BundlerContext & AppBuildContext {
+export function isAppBuildContext(context: any): context is BundlerContext & AppBuildContext {
+  return (context as any).appName !== undefined;
+}
+
+export function isAppContext<T>(context: any): context is T {
   return (context as any).appName !== undefined;
 }
 
@@ -141,7 +145,7 @@ export function generateTsConfig(
 ): string {
   const tsconfigPath = join(appPath, 'tsconfig.app.json');
   const tsconfigJSON = readConfigFile(tsconfigPath, sys.readFile).config;
-  const pAppPath = pathNormalizeToLinux(appPath);
+  const pAppPath = normalizePath(appPath);
 
   // tsconfigJSON.config.angularCompilerOptions.enableIvy = this.enableIvy;
   tsconfigJSON.files = tsconfigJSON.files.map((file: string) => posix.join(pAppPath, file));
@@ -174,9 +178,6 @@ export function writeTsconfig(
   const includePaths = new Set<string>();
   const excludePaths = new Set<string>();
   const dirPath = join(tempFolder, context.id);
-  if (!existsSync(dirPath)) {
-    mkdirSync(dirPath, { recursive: true });
-  }
 
   // get the list of files for existing component compositions to include in the compilation
   context.components.forEach((component: Component) => {
@@ -192,9 +193,9 @@ export function writeTsconfig(
       if (!capsule) {
         throw new Error(`No capsule found for ${component.id} in network graph`);
       }
-      outputPath = pathNormalizeToLinux(capsule.path);
+      outputPath = normalizePath(capsule.path);
     } else {
-      outputPath = pathNormalizeToLinux(workspace?.componentDir(component.id, {
+      outputPath = normalizePath(workspace?.componentDir(component.id, {
         ignoreVersion: true
       }) || '');
     }
@@ -214,15 +215,15 @@ export function writeTsconfig(
 
   const content = generateTsConfig(rootPath, Array.from(includePaths), Array.from(excludePaths), tsPaths);
   const hash = objectHash(content);
-  const targetPath = join(dirPath, `__tsconfig-${timestamp}.json`);
+  const targetPath = join(dirPath, `tsconfig/tsconfig-${timestamp}.json`);
 
   // write only if the link has changed (prevents triggering fs watches)
   if (writeHash.get(targetPath) !== hash) {
-    writeFileSync(targetPath, content);
+    outputFileSync(targetPath, content);
     writeHash.set(targetPath, hash);
   }
 
-  return pathNormalizeToLinux(targetPath);
+  return normalizePath(targetPath);
 }
 
 export function dedupPaths(paths: (string | any)[]): string[] {
@@ -239,3 +240,22 @@ export function dedupPaths(paths: (string | any)[]): string[] {
 export function packagePath(packageName: string, path = ''): string {
   return join(dirname(require.resolve(`${packageName}/package.json`)), path);
 }
+
+/**
+ * Normalize slashes in a file path to be posix/unix-like forward slashes.
+ * Also condenses repeat slashes to a single slash and removes and trailing slashes, unless disabled.
+ */
+export function normalizePath(path: string, removeTrailingSlashes = false): string {
+  return normalize(path, removeTrailingSlashes);
+}
+
+export function getLoggerApi(logger: Logger) {
+  return {
+    error: (m: string) => logger.consoleFailure(m),
+    log: (m: string) => logger.console(m),
+    warn: (m: string) => logger.consoleWarning(m),
+    info: (m: string) => logger.console(m),
+    colorMessage: (m: string) => logger.console(m),
+    createChild: () => logger
+  } as any;
+}
diff --git a/angular/devkit/ng-compat/build-angular/browser-schema.ts b/angular/devkit/ng-compat/build-angular/browser-schema.ts
deleted file mode 100644
index b1211ddc..00000000
--- a/angular/devkit/ng-compat/build-angular/browser-schema.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/* eslint-disable */
-
-export let BrowserBuilderSchema = require('@angular-devkit/build-angular/src/builders/browser/schema').Schema;
diff --git a/angular/devkit/ng-compat/build-angular/builder-options.ts b/angular/devkit/ng-compat/build-angular/builder-options.ts
new file mode 100644
index 00000000..1d0bf512
--- /dev/null
+++ b/angular/devkit/ng-compat/build-angular/builder-options.ts
@@ -0,0 +1,2 @@
+/* eslint-disable */
+export type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
diff --git a/angular/devkit/ng-compat/build-angular/builders/application.ts b/angular/devkit/ng-compat/build-angular/builders/application.ts
new file mode 100644
index 00000000..a3d2aef2
--- /dev/null
+++ b/angular/devkit/ng-compat/build-angular/builders/application.ts
@@ -0,0 +1,24 @@
+import { ApplicationBuilderOptions } from '../schemas/application.schema';
+import type { BuilderContext, BuilderOutput } from '@angular-devkit/architect';
+import type { Plugin, OutputFile } from 'esbuild';
+import { VERSION } from '@angular/cli';
+
+export let buildApplicationInternal = (
+  options: ApplicationBuilderOptions,
+  context: BuilderContext & {
+    signal?: AbortSignal;
+  }, infrastructureSettings?: {
+    write?: boolean;
+  }, plugins?: Plugin[]
+  // @ts-ignore
+) => AsyncIterable<BuilderOutput & {
+  outputFiles?: OutputFile[];
+  assetFiles?: {
+    source: string;
+    destination: string;
+  }[];
+}>;
+
+if (Number(VERSION.major) >= 16) {
+  buildApplicationInternal = require('@angular-devkit/build-angular/src/builders/application').buildApplicationInternal;
+}
diff --git a/angular/devkit/ng-compat/build-angular/schemas/application.schema.ts b/angular/devkit/ng-compat/build-angular/schemas/application.schema.ts
new file mode 100644
index 00000000..e2c58cc1
--- /dev/null
+++ b/angular/devkit/ng-compat/build-angular/schemas/application.schema.ts
@@ -0,0 +1,429 @@
+/**
+ * Application builder target options
+ */
+export interface ApplicationBuilderOptions {
+  /**
+   * A list of CommonJS packages that are allowed to be used without a build time warning.
+   */
+  allowedCommonJsDependencies?: string[];
+  /**
+   * Build using Ahead of Time compilation.
+   */
+  aot?: boolean;
+  /**
+   * Generates an application shell during build time.
+   */
+  appShell?: boolean;
+  /**
+   * List of static application assets.
+   */
+  assets?: AssetPattern[];
+  /**
+   * Base url for the application being built.
+   */
+  baseHref?: string;
+  /**
+   * The full path for the browser entry point to the application, relative to the current
+   * workspace.
+   */
+  browser: string;
+  /**
+   * Budget thresholds to ensure parts of your application stay within boundaries which you
+   * set.
+   */
+  budgets?: Budget[];
+  /**
+   * Define the crossorigin attribute setting of elements that provide CORS support.
+   */
+  crossOrigin?: CrossOrigin;
+  /**
+   * Delete the output path before building.
+   */
+  deleteOutputPath?: boolean;
+  /**
+   * Exclude the listed external dependencies from being bundled into the bundle. Instead, the
+   * created bundle relies on these dependencies to be available during runtime.
+   */
+  externalDependencies?: string[];
+  /**
+   * Extract all licenses in a separate file.
+   */
+  extractLicenses?: boolean;
+  /**
+   * Replace compilation source files with other compilation source files in the build.
+   */
+  fileReplacements?: FileReplacement[];
+  /**
+   * How to handle duplicate translations for i18n.
+   */
+  i18nDuplicateTranslation?: I18NTranslation;
+  /**
+   * How to handle missing translations for i18n.
+   */
+  i18nMissingTranslation?: I18NTranslation;
+  /**
+   * Configures the generation of the application's HTML index.
+   */
+  index: IndexUnion;
+  /**
+   * The stylesheet language to use for the application's inline component styles.
+   */
+  inlineStyleLanguage?: "css" | "less" | "sass" | "scss";
+  /**
+   * Translate the bundles in one or more locales.
+   */
+  localize?: Localize;
+  /**
+   * Use file name for lazy loaded chunks.
+   */
+  namedChunks?: boolean;
+  /**
+   * Enables optimization of the build output. Including minification of scripts and styles,
+   * tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For
+   * more information, see
+   * https://angular.io/guide/workspace-config#optimization-configuration.
+   */
+  optimization?: OptimizationUnion;
+  /**
+   * Define the output filename cache-busting hashing mode.
+   */
+  outputHashing?: OutputHashing;
+  /**
+   * The full path for the new output directory, relative to the current workspace.
+   */
+  outputPath: string;
+  /**
+   * Enable and define the file watching poll time period in milliseconds.
+   */
+  poll?: number;
+  /**
+   * A list of polyfills to include in the build. Can be a full path for a file, relative to
+   * the current workspace or module specifier. Example: 'zone.js'.
+   */
+  polyfills?: string[];
+  /**
+   * Prerender (SSG) pages of your application during build time.
+   */
+  prerender?: PrerenderUnion;
+  /**
+   * Do not use the real path when resolving modules. If unset then will default to `true` if
+   * NodeJS option --preserve-symlinks is set.
+   */
+  preserveSymlinks?: boolean;
+  /**
+   * Log progress to the console while building.
+   */
+  progress?: boolean;
+  /**
+   * Global scripts to be included in the build.
+   */
+  scripts?: ScriptElement[];
+  /**
+   * The full path for the server entry point to the application, relative to the current
+   * workspace.
+   */
+  server?: string;
+  /**
+   * Generates a service worker configuration.
+   */
+  serviceWorker?: ServiceWorker;
+  /**
+   * Output source maps for scripts and styles. For more information, see
+   * https://angular.io/guide/workspace-config#source-map-configuration.
+   */
+  sourceMap?: SourceMapUnion;
+  /**
+   * Server side render (SSR) pages of your application during runtime.
+   */
+  ssr?: boolean;
+  /**
+   * Generates a 'stats.json' file which can be analyzed with
+   * https://esbuild.github.io/analyze/.
+   */
+  statsJson?: boolean;
+  /**
+   * Options to pass to style preprocessors.
+   */
+  stylePreprocessorOptions?: StylePreprocessorOptions;
+  /**
+   * Global styles to be included in the build.
+   */
+  styles?: StyleElement[];
+  /**
+   * Enables the use of subresource integrity validation.
+   */
+  subresourceIntegrity?: boolean;
+  /**
+   * The full path for the TypeScript configuration file, relative to the current workspace.
+   */
+  tsConfig: string;
+  /**
+   * Adds more details to output logging.
+   */
+  verbose?: boolean;
+  /**
+   * Run build when files change.
+   */
+  watch?: boolean;
+  /**
+   * TypeScript configuration for Web Worker modules.
+   */
+  webWorkerTsConfig?: string;
+}
+export type AssetPattern = AssetPatternClass | string;
+export interface AssetPatternClass {
+  /**
+   * Allow glob patterns to follow symlink directories. This allows subdirectories of the
+   * symlink to be searched.
+   */
+  followSymlinks?: boolean;
+  /**
+   * The pattern to match.
+   */
+  glob: string;
+  /**
+   * An array of globs to ignore.
+   */
+  ignore?: string[];
+  /**
+   * The input directory path in which to apply 'glob'. Defaults to the project root.
+   */
+  input: string;
+  /**
+   * Absolute path within the output.
+   */
+  output: string;
+}
+export interface Budget {
+  /**
+   * The baseline size for comparison.
+   */
+  baseline?: string;
+  /**
+   * The threshold for error relative to the baseline (min & max).
+   */
+  error?: string;
+  /**
+   * The maximum threshold for error relative to the baseline.
+   */
+  maximumError?: string;
+  /**
+   * The maximum threshold for warning relative to the baseline.
+   */
+  maximumWarning?: string;
+  /**
+   * The minimum threshold for error relative to the baseline.
+   */
+  minimumError?: string;
+  /**
+   * The minimum threshold for warning relative to the baseline.
+   */
+  minimumWarning?: string;
+  /**
+   * The name of the bundle.
+   */
+  name?: string;
+  /**
+   * The type of budget.
+   */
+  type: Type;
+  /**
+   * The threshold for warning relative to the baseline (min & max).
+   */
+  warning?: string;
+}
+/**
+ * The type of budget.
+ */
+export declare enum Type {
+  All = "all",
+  AllScript = "allScript",
+  Any = "any",
+  AnyComponentStyle = "anyComponentStyle",
+  AnyScript = "anyScript",
+  Bundle = "bundle",
+  Initial = "initial"
+}
+/**
+ * Define the crossorigin attribute setting of elements that provide CORS support.
+ */
+export declare enum CrossOrigin {
+  Anonymous = "anonymous",
+  None = "none",
+  UseCredentials = "use-credentials"
+}
+export interface FileReplacement {
+  replace: string;
+  with: string;
+}
+/**
+ * How to handle duplicate translations for i18n.
+ *
+ * How to handle missing translations for i18n.
+ */
+export declare enum I18NTranslation {
+  Error = "error",
+  Ignore = "ignore",
+  Warning = "warning"
+}
+/**
+ * Configures the generation of the application's HTML index.
+ */
+export type IndexUnion = boolean | IndexObject | string;
+export interface IndexObject {
+  /**
+   * The path of a file to use for the application's generated HTML index.
+   */
+  input: string;
+  /**
+   * The output path of the application's generated HTML index file. The full provided path
+   * will be used and will be considered relative to the application's configured output path.
+   */
+  output?: string;
+  [property: string]: any;
+}
+/**
+ * Translate the bundles in one or more locales.
+ */
+export type Localize = string[] | boolean;
+/**
+ * Enables optimization of the build output. Including minification of scripts and styles,
+ * tree-shaking, dead-code elimination, inlining of critical CSS and fonts inlining. For
+ * more information, see
+ * https://angular.io/guide/workspace-config#optimization-configuration.
+ */
+export type OptimizationUnion = boolean | OptimizationClass;
+export interface OptimizationClass {
+  /**
+   * Enables optimization for fonts. This option requires internet access. `HTTPS_PROXY`
+   * environment variable can be used to specify a proxy server.
+   */
+  fonts?: FontsUnion;
+  /**
+   * Enables optimization of the scripts output.
+   */
+  scripts?: boolean;
+  /**
+   * Enables optimization of the styles output.
+   */
+  styles?: StylesUnion;
+}
+/**
+ * Enables optimization for fonts. This option requires internet access. `HTTPS_PROXY`
+ * environment variable can be used to specify a proxy server.
+ */
+export type FontsUnion = boolean | FontsClass;
+export interface FontsClass {
+  /**
+   * Reduce render blocking requests by inlining external Google Fonts and Adobe Fonts CSS
+   * definitions in the application's HTML index file. This option requires internet access.
+   * `HTTPS_PROXY` environment variable can be used to specify a proxy server.
+   */
+  inline?: boolean;
+}
+/**
+ * Enables optimization of the styles output.
+ */
+export type StylesUnion = boolean | StylesClass;
+export interface StylesClass {
+  /**
+   * Extract and inline critical CSS definitions to improve first paint time.
+   */
+  inlineCritical?: boolean;
+  /**
+   * Minify CSS definitions by removing extraneous whitespace and comments, merging
+   * identifiers and minimizing values.
+   */
+  minify?: boolean;
+}
+/**
+ * Define the output filename cache-busting hashing mode.
+ */
+export declare enum OutputHashing {
+  All = "all",
+  Bundles = "bundles",
+  Media = "media",
+  None = "none"
+}
+/**
+ * Prerender (SSG) pages of your application during build time.
+ */
+export type PrerenderUnion = boolean | PrerenderClass;
+export interface PrerenderClass {
+  /**
+   * Whether the builder should process the Angular Router configuration to find all
+   * unparameterized routes and prerender them.
+   */
+  discoverRoutes?: boolean;
+  /**
+   * The path to a file that contains a list of all routes to prerender, separated by
+   * newlines. This option is useful if you want to prerender routes with parameterized URLs.
+   */
+  routesFile?: string;
+}
+export type ScriptElement = ScriptClass | string;
+export interface ScriptClass {
+  /**
+   * The bundle name for this extra entry point.
+   */
+  bundleName?: string;
+  /**
+   * If the bundle will be referenced in the HTML file.
+   */
+  inject?: boolean;
+  /**
+   * The file to include.
+   */
+  input: string;
+}
+/**
+ * Generates a service worker configuration.
+ */
+export type ServiceWorker = boolean | string;
+/**
+ * Output source maps for scripts and styles. For more information, see
+ * https://angular.io/guide/workspace-config#source-map-configuration.
+ */
+export type SourceMapUnion = boolean | SourceMapClass;
+export interface SourceMapClass {
+  /**
+   * Output source maps used for error reporting tools.
+   */
+  hidden?: boolean;
+  /**
+   * Output source maps for all scripts.
+   */
+  scripts?: boolean;
+  /**
+   * Output source maps for all styles.
+   */
+  styles?: boolean;
+  /**
+   * Resolve vendor packages source maps.
+   */
+  vendor?: boolean;
+}
+/**
+ * Options to pass to style preprocessors.
+ */
+export interface StylePreprocessorOptions {
+  /**
+   * Paths to include. Paths will be resolved to workspace root.
+   */
+  includePaths?: string[];
+}
+export type StyleElement = StyleClass | string;
+export interface StyleClass {
+  /**
+   * The bundle name for this extra entry point.
+   */
+  bundleName?: string;
+  /**
+   * If the bundle will be referenced in the HTML file.
+   */
+  inject?: boolean;
+  /**
+   * The file to include.
+   */
+  input: string;
+}
diff --git a/angular/devkit/ng-compat/build-angular/utils/index.ts b/angular/devkit/ng-compat/build-angular/utils/index.ts
index 78823414..2b6074eb 100644
--- a/angular/devkit/ng-compat/build-angular/utils/index.ts
+++ b/angular/devkit/ng-compat/build-angular/utils/index.ts
@@ -1,13 +1,13 @@
 /* eslint-disable */
 import { json, logging } from '@angular-devkit/core';
 import { VERSION } from '@angular/cli';
-import { BrowserBuilderSchema } from '../browser-schema';
+import { BrowserBuilderOptions } from '../builder-options';
 
 export * from './normalize-cache';
 export * from './package-chunk-sort';
 export * from './webpack-browser-config';
 
-export let normalizeBrowserSchema: (workspaceRoot: string, projectRoot: string, projectSourceRoot: string | undefined, options: typeof BrowserBuilderSchema, metadata?: json.JsonObject, logger?: logging.LoggerApi) => any;
+export let normalizeBrowserSchema: (workspaceRoot: string, projectRoot: string, projectSourceRoot: string | undefined, options: BrowserBuilderOptions, metadata?: json.JsonObject, logger?: logging.LoggerApi) => any;
 export let normalizeOptimization: (optimization?: any) => any;
 export let BuildBrowserFeatures: any;
 
diff --git a/angular/devkit/ng-compat/build-angular/utils/webpack-browser-config.ts b/angular/devkit/ng-compat/build-angular/utils/webpack-browser-config.ts
index c4221c56..d2d03881 100644
--- a/angular/devkit/ng-compat/build-angular/utils/webpack-browser-config.ts
+++ b/angular/devkit/ng-compat/build-angular/utils/webpack-browser-config.ts
@@ -2,7 +2,7 @@
 import { logging } from '@angular-devkit/core';
 import { VERSION } from '@angular/cli';
 import { Configuration } from '@teambit/webpack';
-import { BrowserBuilderSchema } from '../browser-schema';
+import { BrowserBuilderOptions } from '../builder-options';
 
 type wbConfigFn = (
   workspaceRoot: string,
@@ -26,7 +26,7 @@ type wbConfigFnV12 = (
 ) => Promise<Configuration>;
 
 export let generateWebpackConfig: wbConfigFn & wbConfigFnV12;
-export let getIndexOutputFile: (index: typeof BrowserBuilderSchema['index']) => string;
+export let getIndexOutputFile: (index: BrowserBuilderOptions['index']) => string;
 
 if (VERSION.major) {
   const webpackBrowserConfig = require('@angular-devkit/build-angular/src/utils/webpack-browser-config');
diff --git a/angular/devkit/ng-compat/build-angular/webpack/stats.ts b/angular/devkit/ng-compat/build-angular/webpack/stats.ts
index 7962341b..22311444 100644
--- a/angular/devkit/ng-compat/build-angular/webpack/stats.ts
+++ b/angular/devkit/ng-compat/build-angular/webpack/stats.ts
@@ -2,9 +2,9 @@
 import { WebpackLoggingCallback } from '@angular-devkit/build-webpack';
 import { logging } from '@angular-devkit/core';
 import { VERSION } from '@angular/cli';
-import { BrowserBuilderSchema } from '../browser-schema';
+import { BrowserBuilderOptions } from '../builder-options';
 
-export let createWebpackLoggingCallback: (options: typeof BrowserBuilderSchema, logger: logging.LoggerApi) => WebpackLoggingCallback;
+export let createWebpackLoggingCallback: (options: BrowserBuilderOptions, logger: logging.LoggerApi) => WebpackLoggingCallback;
 
 if ((VERSION.major === '16' && Number(VERSION.minor) >= 2) || Number(VERSION.major) > 16) {
   createWebpackLoggingCallback = require('@angular-devkit/build-angular/src/tools/webpack/utils/stats').createWebpackLoggingCallback;
diff --git a/angular/devkit/ng-compat/component.json b/angular/devkit/ng-compat/component.json
index c2f91fd2..2860d7fa 100644
--- a/angular/devkit/ng-compat/component.json
+++ b/angular/devkit/ng-compat/component.json
@@ -11,6 +11,8 @@
         },
         "peerDependencies": {
           "@angular-devkit/build-angular": ">= 0.0.1",
+          "@angular-devkit/architect": ">= 0.0.1",
+          "@angular/core": ">= 13.0.0",
           "@angular/cli": ">= 13.0.0",
           "webpack": ">= 4.44.2"
         }
diff --git a/angular/devkit/ng-compat/index.ts b/angular/devkit/ng-compat/index.ts
index ecb367c3..71efae7d 100644
--- a/angular/devkit/ng-compat/index.ts
+++ b/angular/devkit/ng-compat/index.ts
@@ -1,4 +1,6 @@
 export * from './build-angular/index-html-webpack-plugin';
 export * from './build-angular/webpack';
 export * from './build-angular/utils';
-export * from './build-angular/browser-schema';
+export * from './build-angular/builder-options';
+export * from './build-angular/schemas/application.schema';
+export * from './build-angular/builders/application';
diff --git a/angular/devkit/preview/preview/angular-preview.ts b/angular/devkit/preview/preview/angular-preview.ts
index b686eac4..8ed27d34 100644
--- a/angular/devkit/preview/preview/angular-preview.ts
+++ b/angular/devkit/preview/preview/angular-preview.ts
@@ -1,4 +1,9 @@
-import { AngularEnvOptions, BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+import {
+  AngularEnvOptions,
+  ApplicationOptions,
+  BrowserOptions,
+  DevServerOptions
+} from '@bitdev/angular.dev-services.common';
 import { AppContext } from '@teambit/application';
 import { Bundler, BundlerContext, DevServer, DevServerContext } from '@teambit/bundler';
 import { AsyncEnvHandler, EnvHandler } from '@teambit/envs';
@@ -12,7 +17,7 @@ import 'webpack-dev-server';
 export type DevServerProvider = (
   context: DevServerContext | (DevServerContext & AppContext),
   transformers?: WebpackConfigTransformer[],
-  angularOptions?: Partial<BrowserOptions & DevServerOptions>,
+  angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>,
   webpackOptions?: Partial<WebpackConfigWithDevServer | Configuration>,
   sourceRoot?: string
 ) => AsyncEnvHandler<DevServer>;
@@ -20,7 +25,7 @@ export type DevServerProvider = (
 export type BundlerProvider = (
   context: BundlerContext | (BundlerContext & AppContext),
   transformers?: WebpackConfigTransformer[],
-  angularOptions?: Partial<BrowserOptions & DevServerOptions>,
+  angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>,
   webpackOptions?: Partial<WebpackConfigWithDevServer | Configuration>,
   sourceRoot?: string
 ) => AsyncEnvHandler<Bundler>;
@@ -88,7 +93,7 @@ export class AngularPreview implements Preview {
   getDevServer(
     context: DevServerContext,
     transformers?: WebpackConfigTransformer[],
-    angularOptions?: Partial<BrowserOptions & DevServerOptions>,
+    angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>,
     webpackOptions?: Partial<WebpackConfigWithDevServer | Configuration>,
     sourceRoot?: string
   ): AsyncEnvHandler<DevServer> {
diff --git a/angular/devkit/vite/component.json b/angular/devkit/vite/component.json
index 33bd3e89..e2480587 100644
--- a/angular/devkit/vite/component.json
+++ b/angular/devkit/vite/component.json
@@ -8,40 +8,24 @@
     "teambit.dependencies/dependency-resolver": {
       "policy": {
         "dependencies": {
-          "@analogjs/vite-plugin-angular": "^0.2.0",
-          "@mdx-js/react": "^1.6.22",
-          "@originjs/vite-plugin-commonjs": "^1.0.3",
+          "@analogjs/platform": "-",
           "@teambit/node.deps-detectors.detective-es6": "0.0.1",
+          "@teambit/vite.vite-bundler": "*",
+          "@teambit/vite.vite-dev-server": "*",
+          "@types/express": "^4.17.17",
           "@types/memoizee": "0.4.5",
-          "@vitejs/plugin-react": "^4.0.0",
           "find-root": "1.1.0",
           "memoizee": "0.4.15",
-          "node-stdlib-browser": "^1.2.0",
-          "parse5-html-rewriting-stream": "7.0.0",
-          "remark-admonitions": "^1.2.1",
-          "remark-frontmatter": "^2.0.0",
-          "typescript": "-",
-          "unified": "^10.1.2",
-          "unist-util-remove": "^2.0.1",
-          "unist-util-visit": "^2.0.3",
-          "vite": "^4.4.9",
-          "vite-plugin-commonjs": "^0.8.2",
-          "vite-plugin-markdown": "2.1.0",
-          "vite-plugin-mdx": "^3.5.11",
-          "vite-plugin-node-polyfills": "^0.11.2",
-          "vite-plugin-require-transform": "^1.0.21",
-          "yaml": "^2.3.1"
+          "parse5-html-rewriting-stream": "7.0.0"
         },
         "devDependencies": {
           "@types/find-root": "1.1.2",
-          "@types/jest": "26.0.20",
-          "@types/node": "12.20.4",
-          "@babel/runtime": "7.20.0"
+          "@types/node": "12.20.4"
         },
         "peerDependencies": {
+          "@analogjs/platform": ">= 0.2.22",
           "@angular/common": ">= 13.0.0",
-          "typescript": ">= 3.5.3",
-          "vite": "4.4.8"
+          "vite": "5.0.0"
         }
       }
     }
diff --git a/angular/devkit/vite/config.factory.ts b/angular/devkit/vite/config.factory.ts
new file mode 100644
index 00000000..6ef6a3f4
--- /dev/null
+++ b/angular/devkit/vite/config.factory.ts
@@ -0,0 +1,182 @@
+import { default as analog } from '@analogjs/platform';
+import { isAppBuildContext, normalizePath } from '@bitdev/angular.dev-services.common';
+import { BundlerContext, DevServerContext } from '@teambit/bundler';
+import { CACHE_ROOT } from '@teambit/legacy/dist/constants';
+import assert from 'assert';
+import { basename, extname, join, posix, resolve } from 'path';
+// @ts-ignore
+import type { InlineConfig } from 'vite';
+import { getIndexInputFile, htmlPlugin } from './plugins/index-html.plugin';
+import { BuildMode, NgViteOptions, ViteAspectsContext } from './utils/types';
+import { joinPathFragments } from './utils/utils';
+
+type ConfigFactoryOptions = NgViteOptions & { context: DevServerContext | BundlerContext };
+
+
+const SSR_DIR = 'ssr';
+const BROWSER_DIR = 'browser';
+
+/**
+ * Generate Vite configuration object based on provided options.
+ *
+ * @param {ConfigFactoryOptions} options - The options for generating the configuration.
+ * @param {ViteAspectsContext} aspectContext - The context object for Vite aspects.
+ * @return {Promise<InlineConfig>} - The generated Vite configuration object.
+ */
+export async function configFactory(
+  options: ConfigFactoryOptions,
+  aspectContext: ViteAspectsContext
+): Promise<InlineConfig> {
+  const { mergeConfig } = await import('vite');
+  const {
+    angularOptions: { tsConfig, index },
+    context: { rootPath, envRuntime },
+    context,
+    name,
+    outputPath
+  } = options;
+  assert(rootPath, 'rootPath is required');
+  assert(outputPath, 'outputPath is required');
+  const { workspace } = aspectContext;
+  const idName = `${ envRuntime.id }/${ name }`;
+  const tempFolder = workspace ? workspace.getTempDir(idName) : join(CACHE_ROOT, idName);
+  const indexPath = getIndexInputFile(index!);
+  const browserDir = normalizePath(resolve(outputPath, BROWSER_DIR));
+  const ssrDir = normalizePath(resolve(outputPath, SSR_DIR));
+
+  assert(isAppBuildContext(context), 'Angular vite only support apps for now');
+  let appRootPath: string;
+  const capsule = (options.context as any).capsule;
+  if (capsule) {
+    appRootPath = capsule.path;
+  } else {
+    appRootPath = workspace?.componentDir(context.appComponent.id, {
+      ignoreVersion: true
+    }) || '';
+  }
+  const tsconfigPath = tsConfig ?? posix.join(appRootPath, 'tsconfig.app.json');
+
+  const baseConfig = createBaseConfig(options, tsconfigPath, tempFolder, browserDir, ssrDir, appRootPath, indexPath);
+  const serverConfig = await createServerConfig(rootPath);
+  const buildConfig = createBuildConfig(browserDir, appRootPath, indexPath);
+  const testConfig = createTestConfig();
+
+  return mergeConfig(
+    baseConfig,
+    {
+      build: buildConfig
+      //server: serverConfig,
+      //test: testConfig
+    }
+  );
+}
+
+function createBaseConfig(options: ConfigFactoryOptions, tsconfigPath: string, tempFolder: string, browserDir: string, ssrDir: string, appRootPath: string, indexPath: string) {
+  const {
+    angularOptions: { baseHref, server, ssr },
+    angularOptions,
+    context: { rootPath },
+    buildMode,
+    outputPath,
+    sourceRoot
+  } = options;
+
+  assert(rootPath, 'rootPath is required');
+  assert(outputPath, 'outputPath is required');
+
+  // TODO: fix this
+  const entryServer = ''; //(ssr as SsrClass)?.entry as string;
+
+  const baseConfig: InlineConfig = {
+    // publicDir: 'src/assets', // todo
+    root: join(appRootPath, sourceRoot || 'src'),
+    base: baseHref ?? './',
+    mode: buildMode,
+    resolve: {
+      mainFields: ['module']
+    },
+    define: {
+      'import.meta.vitest': buildMode !== BuildMode.Production
+    },
+    plugins: [
+      analog({
+        vite: {
+          tsconfig: tsconfigPath
+        },
+        ssr: !!server,
+        ssrBuildDir: ssr ? ssrDir : undefined,
+        entryServer: resolve(appRootPath, entryServer),
+        nitro: {
+          alias: ssr ? {
+            '#analog/ssr': join(ssrDir, basename(entryServer, extname(entryServer))),
+            '#analog/index': join(browserDir, basename(indexPath))
+          } : {},
+          serverAssets: ssr ? [{
+            baseName: 'public',
+            dir: browserDir
+          }] : [],
+          publicAssets: ssr ? [{
+            dir: browserDir
+          }] : [],
+          output: ssr ? {
+            dir: normalizePath(resolve(outputPath, 'server')),
+            publicDir: normalizePath(resolve(outputPath, 'server/public'))
+          } : {},
+          buildDir: normalizePath(resolve(tempFolder, 'nitro')),
+          prerender: {
+            concurrency: 4
+          }
+        },
+        index: indexPath,
+        workspaceRoot: appRootPath
+      })
+    ]
+  };
+
+  if (server) {
+    // When running the ssr dev server, CTRL+C doesn't seem to work anymore (bug in nitro?)
+    // This is a workaround to make sure the process exits when CTRL+C is pressed
+    process.on('SIGINT', () => process.exit(1));
+  } //else {
+    // When we are not using ssr, we need to add the html plugin to generate the index.html file
+  baseConfig.plugins!.push(htmlPlugin(angularOptions, rootPath!, indexPath, !!ssr));
+  //}
+  return baseConfig;
+}
+
+async function createServerConfig(rootPath: string) {
+  const { searchForWorkspaceRoot } = await import('vite');
+  return {
+    fs: {
+      allow: [
+        searchForWorkspaceRoot(joinPathFragments(rootPath)),
+        joinPathFragments('.', 'node_modules/vite')
+      ]
+    }
+  };
+}
+
+function createBuildConfig(browserDir: string, appRootPath: string, indexPath: string) {
+  return {
+    target: ['es2020'],
+    outDir: browserDir,
+    emptyOutDir: true,
+    reportCompressedSize: true,
+    commonjsOptions: {
+      transformMixedEsModules: true
+    }
+  };
+}
+
+function createTestConfig() {
+  return {
+    globals: true,
+    environment: 'jsdom',
+    setupFiles: ['src/test.ts'],
+    include: ['**/*.spec.ts']
+  };
+}
+
+
+
+
diff --git a/angular/devkit/vite/dev-server/config.ts b/angular/devkit/vite/dev-server/config.ts
deleted file mode 100644
index 7ee424f2..00000000
--- a/angular/devkit/vite/dev-server/config.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-// @ts-nocheck
-// Make sure bit recognizes the dependencies
-import '@mdx-js/react';
-import 'node-stdlib-browser';
-import { relative } from 'path';
-import { defineConfig, InlineConfig } from 'vite';
-import { nodePolyfills } from 'vite-plugin-node-polyfills';
-import { ViteDevServerAspectsContext, ViteDevServerOptions } from './types';
-import { getHostAlias } from './utils';
-// import react from "@vitejs/plugin-react";
-// import mdx from "vite-plugin-mdx";
-// import { htmlPlugin } from "./html-plugin";
-// import mdxOptions from "./mdx-config";
-
-/**
- * Generate a Vite config for dev server.
- *
- * 1. alias/fallbacks/provide for Node APIs and host deps
- * 2. module loaders like for MDX
- * 3. root path, public path, entry files, and html
- * 4. websocket protocol
- */
-export async function configFactory(options: ViteDevServerOptions, aspectContext: ViteDevServerAspectsContext, port: number): Promise<InlineConfig> {
-  const {
-    devServerContext: { publicPath, entry, rootPath, envRuntime },
-    define,
-    alias,
-    plugins,
-    transformers
-  } = options;
-  const { workspace } = aspectContext;
-  const entries = entry;
-
-  const root = options.root ?? workspace.path;
-  const publicDir = relative(workspace.path, publicPath);
-  const base = options.base ?? `/${rootPath}/`;
-
-  // TODO: for WebpackBitReporterPlugin
-  // id;
-  // pubsub;
-
-  // e.g. teambit.vite/examples/vue/vue@07106b6c1256c0efd94804266c07572a450cf675
-  const envId = envRuntime.id;
-  // directory to place preview.root files
-  // const previewRootDir = `./node_modules/.cache/bit/teambit.ui`;
-  // directory to place preview entries files
-  // e.g. ./node_modules/.cache/bit/teambit.preview/preview/{envId}/compositions-1687107103571.js
-  // const entriesDir = `./node_modules/.cache/bit/teambit.preview/preview/${envId}`;
-  // directory to place vite cache
-  // TODO
-  //   const cacheDir = `./node_modules/.cache/bit/teambit.vite/vite-dev-server/${envId}`;
-  const cacheDir = `./node_modules/.cache/bit/bitdev.angular/vite-dev-server/${envId}`;
-
-  // set host deps as alias
-  const hostAlias = getHostAlias(options.devServerContext);
-
-  // get full component list from workspace, and then
-  // - ignore them from watch
-  // - exclude them from optimizeDeps
-  const components = await workspace.list();
-  const packageList = components.map(c => workspace.componentPackageName(c));
-
-  const config: InlineConfig = defineConfig({
-    configFile: false,
-    envFile: false,
-    root,
-    base,
-    publicDir,
-    define,
-    resolve: {
-      mainFields: ['module'],
-      alias: [
-        {
-          // this is required for the SCSS modules
-          find: /^~(.*)$/,
-          replacement: '$1'
-        },
-        ...hostAlias,
-        ...alias || []
-      ]
-    },
-    // apply different cache dir for each env
-    cacheDir,
-    server: {
-      port,
-      watch: {
-        // 1. preview root
-        // 2. entry files
-        // 3. local packages
-        ignored: [
-          ...packageList.map(p => `!**/node_modules/${p}/**`)
-        ]
-      },
-      fs: {
-        strict: false
-      }
-    },
-    optimizeDeps: {
-      entries
-      // exclude: packageList,
-    },
-    // TODO: make it replaceable and reusable
-    plugins: [
-      nodePolyfills(),
-      // react(),
-      // mdx(mdxOptions),
-      // htmlPlugin(entries),
-      ...plugins || []
-    ]
-  });
-
-  // apply transformers
-  if (transformers) {
-    transformers.forEach(transformer => {
-      transformer(config);
-    });
-  }
-
-  return config;
-}
-
-
-
-
diff --git a/angular/devkit/vite/dev-server/types.ts b/angular/devkit/vite/dev-server/types.ts
deleted file mode 100644
index 44db8edc..00000000
--- a/angular/devkit/vite/dev-server/types.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-import {
-  AngularEnvOptions,
-  BrowserOptions,
-  DevServerOptions
-} from '@bitdev/angular.dev-services.common';
-import type { DevServerContext } from '@teambit/bundler';
-import { Logger } from '@teambit/logger';
-import { PubsubMain } from '@teambit/pubsub';
-import type { Workspace } from '@teambit/workspace';
-// @ts-ignore
-import type { Alias, InlineConfig, PluginOption } from 'vite';
-
-
-export type ViteConfigTransformer = (config: InlineConfig) => void;
-
-export type ViteDevServerAspectsContext = {
-  logger: Logger;
-  workspace: Workspace;
-  pubsub: PubsubMain;
-};
-
-export type NgViteDevServerOptions = {
-  angularOptions: Partial<BrowserOptions & DevServerOptions>;
-
-  /**
-   * context of the dev server execution.
-   */
-  devServerContext: DevServerContext;
-
-  /**
-   * name of the dev server.
-   */
-  name?: string;
-
-  ngEnvOptions: AngularEnvOptions;
-
-  sourceRoot?: string;
-
-  // TODO: fix type once we can support preview with vite
-  transformers?: (ViteConfigTransformer | any)[];
-
-  // TODO: remove this once we can support preview with vite
-  [key: string]: any;
-};
-
-export type ViteDevServerOptions = {
-  /**
-   * name of the dev server.
-   */
-  name?: string;
-
-  /**
-   * context of the dev server execution.
-   */
-  devServerContext: DevServerContext;
-
-  /**
-   * optimize entries before passing them to Vite.
-   */
-  optimizeEntries?: (entries: string[], context: ViteDevServerAspectsContext) => string[];
-
-  /**
-   * root path of the dev server.
-   */
-  root?: string;
-
-  /**
-   * base URL to use for all relative URLs in a document
-   */
-  base?: string;
-
-  /**
-   * variables to be injected to the dev server.
-   */
-  define?: Record<string, any>;
-
-  /**
-   * alias to be injected to the dev server.
-   */
-  alias?: Alias[];
-
-  /**
-   * list of plugins to be injected to the dev server.
-   */
-  plugins?: PluginOption[];
-
-  /**
-   * list of transformers to modify Vite config in an advanced way.
-   */
-  transformers?: ViteConfigTransformer[];
-};
diff --git a/angular/devkit/vite/dev-server/utils/html-plugin.ts b/angular/devkit/vite/dev-server/utils/html-plugin.ts
deleted file mode 100644
index f0b3968b..00000000
--- a/angular/devkit/vite/dev-server/utils/html-plugin.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import type { IncomingMessage, ServerResponse } from 'http';
-import type { Plugin } from 'vite';
-
-const cleanUrl = (url: string) => url.replace(/#.*$/s, '').replace(/\?.*$/s, '');
-
-const defaultHeadHtml = `
-<meta charset="utf-8">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<script>
-// Allow to use react dev-tools inside the examples
-try { window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__; } catch {}
-</script>
-<style> body { margin: 0; } </style>
-`
-
-const defaultBodyHtml = `
-<div id="root"></div>
-`
-
-const defaultGenScriptHtml = (entries: string[]): string => entries.map(
-  src => `<script type="module" src="${src}"></script>`).join('\n');
-
-const defaultGenHtml = (entries: string[]) => `
-<!DOCTYPE html>
-<html lang="en">
-<head>${defaultHeadHtml}</head>
-<body>
-${defaultBodyHtml}
-${defaultGenScriptHtml(entries)}
-</body>
-</html>`;
-
-export type HtmlPluginOptions = {
-  entries: string[];
-  genHtml?: (entries: string[], context: { req: IncomingMessage, res: ServerResponse }) => string;
-};
-
-export const htmlPlugin = ({ entries, genHtml }: HtmlPluginOptions): Plugin => {
-  return {
-    name: 'html-plugin',
-    configureServer(server) {
-      return () => {
-        server.middlewares.use(async (req, res, next) => {
-          const url = req.url && cleanUrl(req.url)
-          if (url?.endsWith('.html')) {
-            res.statusCode = 200
-            res.setHeader('Content-Type', 'text/html')
-            const preHtml = genHtml? genHtml(entries, { req, res }) : defaultGenHtml(entries);
-            const html = await server.transformIndexHtml(
-              url,
-              preHtml,
-              req.originalUrl
-            )
-            res.end(html)
-            return
-          }
-          next()
-        })
-      }
-    }
-  }
-}
diff --git a/angular/devkit/vite/dev-server/utils/index.ts b/angular/devkit/vite/dev-server/utils/index.ts
deleted file mode 100644
index 3131ccc4..00000000
--- a/angular/devkit/vite/dev-server/utils/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from './html-plugin';
-export * from './host-alias';
-export * from './mdx-config';
diff --git a/angular/devkit/vite/dev-server/utils/mdx-config.ts b/angular/devkit/vite/dev-server/utils/mdx-config.ts
deleted file mode 100644
index 331d4765..00000000
--- a/angular/devkit/vite/dev-server/utils/mdx-config.ts
+++ /dev/null
@@ -1,109 +0,0 @@
-import detectiveEs6 from '@teambit/node.deps-detectors.detective-es6';
-// @ts-ignore
-import remarkNotes from 'remark-admonitions';
-import detectFrontmatter from 'remark-frontmatter';
-import type { Pluggable } from 'unified';
-import remove from 'unist-util-remove';
-import visit from 'unist-util-visit';
-import type { MdxOptions } from 'vite-plugin-mdx';
-import yaml from 'yaml';
-
-type ImportSpecifier = {
-  /**
-   * relative/absolute or module name. e.g. the `y` in the example of `import x from 'y';`
-   */
-  fromModule: string;
-
-  /**
-   * is default import (e.g. `import x from 'y';`)
-   */
-  isDefault?: boolean;
-
-  /**
-   * the name used to identify the module, e.g. the `x` in the example of `import x from 'y';`
-   */
-  identifier?: string;
-};
-
-const DEFAULT_RENDERER = `
-// @ts-nocheck
-import React from 'react'
-import { mdx } from '@mdx-js/react'
-
-/* @jsxRuntime classic */
-/* @jsx mdx */
-`;
-
-function wrapWithScopeContext(): Pluggable {
-  return (tree, file) => {
-    const imports: ImportSpecifier[] = file.data?.imports || [];
-    const ids = imports.reduce<string[]>((identifiers: string[], importSpecifier: ImportSpecifier) => {
-      const newIds: string[] = [];
-      if (importSpecifier.identifier) newIds.push(importSpecifier.identifier);
-      return identifiers.concat(newIds);
-    }, []);
-
-    const preNode = {
-      type: 'jsx',
-      value: `<MDXScopeProvider components={{${ids.join(', ')}}}>`,
-    };
-
-    const postNode = {
-      type: 'jsx',
-      value: `</MDXScopeProvider>`,
-    };
-
-    tree.children.unshift({
-      type: 'import',
-      value: `import { MDXScopeProvider } from '@teambit/mdx.ui.mdx-scope-context';`,
-    });
-
-    tree.children.unshift(preNode);
-    tree.children.push(postNode);
-  };
-}
-
-function extractMetadata(): Pluggable {
-  return function transformer(tree, file) {
-    visit(tree, 'yaml', (node: any) => {
-      try {
-        // eslint-disable-next-line no-param-reassign
-        file.data.frontmatter = yaml.parse(node.value, { prettyErrors: true });
-      } catch (err: any) {
-        throw new Error(
-          `failed extracting metadata/front-matter using Yaml lib, due to an error (please disregard the line/column): ${err.message}`
-        );
-      }
-    });
-  };
-}
-
-function extractImports(): Pluggable {
-  return function transformer(tree, file) {
-    visit(tree, 'import', (node: any) => {
-      const es6Import = detectiveEs6(node.value);
-      const imports: ImportSpecifier[] = Object.keys(es6Import).flatMap((dep) => {
-        if (!es6Import[dep].importSpecifiers) {
-          return {
-            fromModule: dep,
-          };
-        }
-        return es6Import[dep].importSpecifiers.map((importSpecifier) => ({
-          fromModule: dep,
-          identifier: importSpecifier.name,
-          isDefault: importSpecifier.isDefault,
-        }));
-      });
-      // eslint-disable-next-line no-param-reassign
-      (file.data.imports ||= []).push(...imports);
-    });
-
-    remove(tree, 'yaml');
-  };
-}
-
-export const mdxOptions: MdxOptions = {
-  remarkPlugins: [remarkNotes, [detectFrontmatter, ['yaml']], extractMetadata, extractImports],
-  rehypePlugins: [wrapWithScopeContext],
-  renderer: DEFAULT_RENDERER,
-}
diff --git a/angular/devkit/vite/index.ts b/angular/devkit/vite/index.ts
index 025081cb..ca5e622d 100644
--- a/angular/devkit/vite/index.ts
+++ b/angular/devkit/vite/index.ts
@@ -1,2 +1,3 @@
-export * from './ng-vite-dev-server';
-export * from './dev-server/types';
+export * from './ng-vite.dev-server';
+export * from './ng-vite.bundler';
+export * from './utils/types';
diff --git a/angular/devkit/vite/ng-vite-dev-server.ts b/angular/devkit/vite/ng-vite-dev-server.ts
deleted file mode 100644
index 75762bfd..00000000
--- a/angular/devkit/vite/ng-vite-dev-server.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-// eslint-disable-next-line import/no-named-default
-import { default as ngVitePlugin } from '@analogjs/vite-plugin-angular';
-import { isAppDevContext } from '@bitdev/angular.dev-services.common';
-import type { DevServer } from '@teambit/bundler';
-import type { AsyncEnvHandler, EnvContext } from '@teambit/envs';
-import type { Workspace } from '@teambit/workspace';
-import type { Server } from 'http';
-import { posix } from 'path';
-// @ts-ignore
-import type { InlineConfig, Plugin } from 'vite';
-import { configFactory } from './dev-server/config';
-import {
-  NgViteDevServerOptions,
-  ViteDevServerAspectsContext,
-  ViteDevServerOptions
-} from './dev-server/types';
-import { htmlPlugin } from './plugins/index-html.plugin';
-
-export class NgViteDevServer {
-  id = 'ng-vite-dev-server';
-
-  constructor(
-    private options: ViteDevServerOptions,
-    private aspectContext: ViteDevServerAspectsContext
-  ) {
-  }
-
-  async listen(port: number): Promise<Server> {
-    const config: InlineConfig = await configFactory(this.options, this.aspectContext, port);
-    const vite = await import('vite');
-    const server = await vite.createServer(config);
-    await server.listen(port);
-    if (!server.httpServer) {
-      throw new Error('vite server failed to start');
-    }
-    return server.httpServer;
-  }
-
-  static from(options: NgViteDevServerOptions): AsyncEnvHandler<DevServer> {
-    return async(context: EnvContext): Promise<DevServer> => {
-      const {rootPath} = options.devServerContext;
-      const name = options.name || 'vite-dev-server';
-      const logger = context.createLogger(name);
-      const workspace: Workspace = context.getAspect<any>('teambit.workspace/workspace');
-      const pubsub = context.getAspect<any>('teambit.harmony/pubsub');
-
-      let appRootPath: string;
-      let tsconfigPath: string;
-      if (isAppDevContext(options.devServerContext)) { // When you use `bit run <app>`
-        appRootPath = workspace?.componentDir(options.devServerContext.appComponent.id, {
-          ignoreVersion: true
-        }) || '';
-        tsconfigPath = options?.angularOptions?.tsConfig ?? posix.join(appRootPath, 'tsconfig.app.json');
-      } else { // When you use `bit start`
-        // appRootPath = getPreviewRootPath(workspace);
-        // tsconfigPath = writeTsconfig(options.devServerContext, appRootPath, tempFolder, application, pkg, devFilesMain, workspace);
-        throw new Error('vite does not support preview yet');
-      }
-
-      const opts = {
-        devServerContext: options.devServerContext,
-        root: rootPath,
-        base: options.angularOptions.baseHref ?? './',
-        plugins: [
-          ngVitePlugin({
-            tsconfig: tsconfigPath,
-            workspaceRoot: rootPath
-          }) as Plugin[],
-          htmlPlugin(options.angularOptions, rootPath, options.sourceRoot)
-        ]
-      };
-
-      const aspectContext: ViteDevServerAspectsContext = {
-        logger,
-        workspace,
-        pubsub
-      };
-      return new NgViteDevServer(opts, aspectContext);
-    };
-  }
-}
-
diff --git a/angular/devkit/vite/ng-vite.bundler.ts b/angular/devkit/vite/ng-vite.bundler.ts
new file mode 100644
index 00000000..3586c0d8
--- /dev/null
+++ b/angular/devkit/vite/ng-vite.bundler.ts
@@ -0,0 +1,36 @@
+import type { Bundler, BundlerContext } from '@teambit/bundler';
+import type { AsyncEnvHandler, EnvContext } from '@teambit/envs';
+import { Logger } from '@teambit/logger';
+import { ViteBundler, ViteBundlerOptions } from '@teambit/vite.vite-bundler';
+import type { Workspace } from '@teambit/workspace';
+// @ts-ignore
+import type { InlineConfig } from 'vite';
+import { configFactory } from './config.factory';
+import { NgViteOptions } from './utils/types';
+
+export class NgViteBundler {
+
+  static from(options: NgViteOptions & { context: BundlerContext }): AsyncEnvHandler<Bundler> {
+    return async(context: EnvContext): Promise<Bundler> => {
+      options.name = options.name || 'ng-vite-bundler';
+      const logger: Logger = context.createLogger(options.name);
+      const workspace: Workspace = context.getAspect<any>('teambit.workspace/workspace');
+
+      const ngConfig = await configFactory(options, { logger, workspace });
+      // @ts-ignore
+      const transformer: any = (config: InlineConfig, vite: typeof import('vite')): InlineConfig => {
+        return vite.mergeConfig(config, ngConfig);
+      };
+
+      const viteConfig: ViteBundlerOptions = {
+        bundlerContext: options.context as BundlerContext,
+        name: options.name,
+        resolveHostAlias: true,
+        transformers: [transformer, ...options.transformers ?? []]
+      };
+
+      return ViteBundler.from(viteConfig)(context);
+    };
+  }
+}
+
diff --git a/angular/devkit/vite/ng-vite.dev-server.ts b/angular/devkit/vite/ng-vite.dev-server.ts
new file mode 100644
index 00000000..9c5725f2
--- /dev/null
+++ b/angular/devkit/vite/ng-vite.dev-server.ts
@@ -0,0 +1,41 @@
+import type { DevServer, DevServerContext } from '@teambit/bundler';
+import type { AsyncEnvHandler, EnvContext } from '@teambit/envs';
+import { ViteDevServer, ViteDevServerOptions } from '@teambit/vite.vite-dev-server';
+import { configFactory } from './config.factory';
+import { NgViteOptions } from './utils/types';
+
+// Extracted constant
+const DEFAULT_SERVER_NAME = 'ng-vite-dev-server';
+
+export class NgViteDevServer {
+  static from(options: NgViteOptions & { context: DevServerContext }): AsyncEnvHandler<DevServer> {
+    return async(context: EnvContext): Promise<DevServer> => {
+      options.name = options.name || DEFAULT_SERVER_NAME;
+      const logger = context.createLogger(options.name);
+      const workspace = context.getAspect<any>('teambit.workspace/workspace');
+
+      const ngConfig = await configFactory(options, { logger, workspace });
+
+      // @ts-ignore
+      function transformer(config: any, vite: typeof import('vite')): any {
+        return vite.mergeConfig(config, ngConfig);
+      }
+
+      const viteConfig: ViteDevServerOptions = {
+        define: ngConfig.define,
+        devServerContext: options.context as DevServerContext,
+        name: options.name,
+        optimizeEntries: options.optimizeEntries as any,
+        plugins: ngConfig.plugins as any,
+        resolveHostAlias: true,
+        // Improved readability for transformers array
+        transformers: [
+          transformer, ...(options.transformers ?? [])
+        ]
+      };
+
+      return ViteDevServer.from(viteConfig)(context);
+    };
+  }
+}
+
diff --git a/angular/devkit/vite/plugins/index-file/augment-index-html.ts b/angular/devkit/vite/plugins/index-file/augment-index-html.ts
index 20f907c5..d11a263f 100644
--- a/angular/devkit/vite/plugins/index-file/augment-index-html.ts
+++ b/angular/devkit/vite/plugins/index-file/augment-index-html.ts
@@ -7,6 +7,7 @@
  */
 
 import { loadEsmModule } from '@bitdev/angular.dev-services.common';
+import assert from 'assert';
 import { extname } from 'path';
 import { htmlRewritingStream } from './html-rewriting-stream';
 import { EntryPointsType } from './package-chunk-sort';
@@ -124,11 +125,9 @@ export async function augmentIndexHtml(
           break;
         case '.mjs':
         case '.mts':
-          if (!isModule) {
-            // It would be very confusing to link an `*.mjs` file in a non-module script context,
-            // so we disallow it entirely.
-            throw new Error('`.mjs` & `.mts` files *must* set `isModule` to `true`.');
-          }
+          // It would be very confusing to link an `*.mjs` file in a non-module script context,
+          // so we disallow it entirely.
+          assert(isModule, '`.mjs` & `.mts` files *must* set `isModule` to `true`.');
           scripts.set(file, true /* isModule */);
           break;
         case '.css':
diff --git a/angular/devkit/vite/plugins/index-file/package-chunk-sort.ts b/angular/devkit/vite/plugins/index-file/package-chunk-sort.ts
index 5d979939..d8ca0db4 100644
--- a/angular/devkit/vite/plugins/index-file/package-chunk-sort.ts
+++ b/angular/devkit/vite/plugins/index-file/package-chunk-sort.ts
@@ -8,7 +8,7 @@
 
 import {parse} from 'path';
 // import { ScriptElement, StyleElement } from '@angular-devkit/build-angular/src/builders/browser/schema';
-import type { BrowserBuilderOptions } from '@angular-devkit/build-angular';
+import type { BrowserBuilderOptions } from '@bitdev/angular.dev-services.ng-compat';
 
 export type EntryPointsType = [name: string, isModule: boolean, inject: boolean];
 
diff --git a/angular/devkit/vite/plugins/index-html.plugin.ts b/angular/devkit/vite/plugins/index-html.plugin.ts
index 71d09e49..2a96e027 100644
--- a/angular/devkit/vite/plugins/index-html.plugin.ts
+++ b/angular/devkit/vite/plugins/index-html.plugin.ts
@@ -1,31 +1,34 @@
-import type { BrowserBuilderOptions } from '@angular-devkit/build-angular';
 import type { ServerResponse } from 'http';
 import memoize from 'memoizee';
-import { join } from 'path';
+// @ts-ignore
 import type { Connect, Plugin, ViteDevServer } from 'vite';
+import { ApplicationOptions } from '@bitdev/angular.dev-services.common';
 import { IndexHtmlGenerator } from './index-file/index-html-generator';
 import { generateEntryPoints } from './index-file/package-chunk-sort';
+import assert from 'assert';
 
-export function getIndexInputFile(index: BrowserBuilderOptions['index']): string {
+export function getIndexInputFile(index: ApplicationOptions['index']): string {
+  assert(index, 'No index file provided');
   if (typeof index === 'string') {
     return index;
   }
-  return index.input;
+  return (index as any).input;
 }
 
 const cleanUrl = (url: string) => url.replace(/#.*$/s, '').replace(/\?.*$/s, '');
 
-async function genHtml(options: Partial<BrowserBuilderOptions>, rootPath: string, sourceRoot = 'src') {
+async function genHtml(options: Partial<ApplicationOptions>, rootPath: string, indexPath: string) {
+  assert(options.browser, 'No main file provided');
   const entrypoints = generateEntryPoints({
-    main: options.main ?? `./${join(sourceRoot, `main.ts`)}`,
-    polyfills: options.polyfills ?? `./${join(sourceRoot, `polyfills.ts`)}`,
+    main: options.browser,
+    polyfills: options.polyfills ?? [],
     scripts: options.scripts ?? [],
     styles: options.styles ?? []
   });
 
   const indexHtmlGenerator = new IndexHtmlGenerator({
     rootPath,
-    indexPath: getIndexInputFile(options.index ?? `./${join(sourceRoot, `index.html`)}`),
+    indexPath,
     entrypoints,
     crossOrigin: options.crossOrigin
   });
@@ -50,18 +53,21 @@ async function genHtml(options: Partial<BrowserBuilderOptions>, rootPath: string
 
 const memoized = memoize(genHtml);
 
-export const htmlPlugin = (options: Partial<BrowserBuilderOptions>, rootPath: string, sourceRoot = 'src'): Plugin => {
+export const htmlPlugin = (options: Partial<ApplicationOptions>, rootPath: string, indexPath: string, ssr: boolean): Plugin => {
   return {
-    name: 'html-plugin',
+    name: 'ng-vite-html-plugin',
     configureServer(server: ViteDevServer) {
       return (): void => {
+        // if(ssr) {
+        //   return;
+        // }
         server.middlewares.use(async(req: Connect.IncomingMessage, res: ServerResponse, next: Connect.NextFunction) => {
           const url = req.url && cleanUrl(req.url);
           if (url?.endsWith('.html')) {
             res.statusCode = 200;
             res.setHeader('Content-Type', 'text/html');
-            let html = await memoized(options, rootPath, sourceRoot);
-            html = await server.transformIndexHtml(options.index as string ?? `./${join(sourceRoot, `index.html`)}`, html, req.originalUrl);
+            let html = await memoized(options, rootPath, indexPath);
+            html = await server.transformIndexHtml(indexPath, html, req.originalUrl);
             res.end(html);
             return;
           }
diff --git a/angular/devkit/vite/plugins/server-entry.plugin.ts b/angular/devkit/vite/plugins/server-entry.plugin.ts
new file mode 100644
index 00000000..fb998fe2
--- /dev/null
+++ b/angular/devkit/vite/plugins/server-entry.plugin.ts
@@ -0,0 +1,113 @@
+// // SSR dev server, middleware and error page source modified from
+// // https://github.com/solidjs/solid-start/blob/main/packages/start/dev/server.js
+//
+// import { Connect, Plugin, ViteDevServer } from 'vite';
+// import * as path from 'path';
+// import * as fs from 'fs';
+//
+// interface ServerOptions {
+//   indexPath?: string;
+//   entryServer?: string;
+// }
+//
+// export function devServerPlugin(options: ServerOptions): Plugin {
+//   const entryServer = options.entryServer || 'src/main.server.ts';
+//   const index = options.indexPath || 'index.html';
+//
+//   return {
+//     name: 'ng-vite-server-entry-plugin',
+//     config() {
+//       return {
+//         resolve: {
+//           alias: {
+//             '~ng-vite/main-server': entryServer,
+//           },
+//         },
+//       };
+//     },
+//     configureServer(viteServer) {
+//       return async () => {
+//         remove_html_middlewares(viteServer.middlewares);
+//         viteServer.middlewares.use(async (req, res) => {
+//           let template = fs.readFileSync(
+//             path.resolve(viteServer.config.root, index),
+//             'utf-8'
+//           );
+//
+//           template = await viteServer.transformIndexHtml(
+//             req.originalUrl as string,
+//             template
+//           );
+//
+//           console.log(template);
+//
+//           try {
+//             const entryServer = (
+//               await viteServer.ssrLoadModule('~ng-vite/main-server')
+//             )['default'];
+//             const result = await entryServer(req.originalUrl, template);
+//             console.log(result);
+//
+//             res.setHeader('Content-Type', 'text/html');
+//             res.end(result);
+//           } catch (e) {
+//             viteServer && viteServer.ssrFixStacktrace(e as Error);
+//             res.statusCode = 500;
+//             res.end(`
+//               <!DOCTYPE html>
+//               <html lang="en">
+//                 <head>
+//                   <meta charset="UTF-8" />
+//                   <title>Error</title>
+//                   <script type="module">
+//                     import { ErrorOverlay } from '/@vite/client'
+//                     document.body.appendChild(new ErrorOverlay(${JSON.stringify(
+//               prepareError(req, e)
+//             ).replace(/</g, '\\u003c')}))
+//                   </script>
+//                 </head>
+//                 <body>
+//                 </body>
+//               </html>
+//             `);
+//           }
+//         });
+//       };
+//     },
+//   };
+// }
+//
+// /**
+//  * Removes Vite internal middleware
+//  *
+//  * @param server
+//  */
+// function remove_html_middlewares(server: ViteDevServer['middlewares']) {
+//   const html_middlewares = [
+//     'viteIndexHtmlMiddleware',
+//     'vite404Middleware',
+//     'viteSpaFallbackMiddleware',
+//   ];
+//   for (let i = server.stack.length - 1; i > 0; i--) {
+//     // @ts-ignore
+//     if (html_middlewares.includes(server.stack[i].handle.name)) {
+//       server.stack.splice(i, 1);
+//     }
+//   }
+// }
+//
+// /**
+//  * Formats error for SSR message in error overlay
+//  * @param req
+//  * @param error
+//  * @returns
+//  */
+// function prepareError(req: Connect.IncomingMessage, error: unknown) {
+//   const e = error as Error;
+//   return {
+//     message: `An error occured while server rendering ${req.url}:\n\n\t${
+//       typeof e === 'string' ? e : e.message
+//     } `,
+//     stack: typeof e === 'string' ? '' : e.stack,
+//   };
+// }
diff --git a/angular/devkit/vite/dev-server/utils/host-alias.ts b/angular/devkit/vite/utils/host-alias.ts
similarity index 92%
rename from angular/devkit/vite/dev-server/utils/host-alias.ts
rename to angular/devkit/vite/utils/host-alias.ts
index c42e5253..22dd5331 100644
--- a/angular/devkit/vite/dev-server/utils/host-alias.ts
+++ b/angular/devkit/vite/utils/host-alias.ts
@@ -2,6 +2,7 @@
 
 import findRoot from 'find-root';
 import type { Alias } from 'vite';
+import type {BundlerContext, DevServerContext} from '@teambit/bundler';
 
 export type ViteContext = {
   /**
@@ -30,7 +31,7 @@ export type ViteContext = {
   aliasHostDependencies?: boolean;
 };
 
-export function getHostAlias(context: ViteContext): Alias[] {
+export function getHostAlias(context: BundlerContext | DevServerContext): [] {
   const alias: Alias[] = [];
   const { hostDependencies: deps, aliasHostDependencies, hostRootDir } = context;
   if (deps && aliasHostDependencies) {
diff --git a/angular/devkit/vite/utils/types.ts b/angular/devkit/vite/utils/types.ts
new file mode 100644
index 00000000..ac8b517e
--- /dev/null
+++ b/angular/devkit/vite/utils/types.ts
@@ -0,0 +1,36 @@
+import { ApplicationOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+import { Logger } from '@teambit/logger';
+import type { ViteDevServerOptions } from '@teambit/vite.vite-dev-server';
+import { Workspace } from '@teambit/workspace';
+
+
+export type ViteAspectsContext = {
+  logger: Logger;
+  workspace: Workspace;
+};
+
+export enum BuildMode {
+  Development = 'development',
+  Production = 'production',
+}
+
+export type NgViteOptions = {
+  angularOptions: Partial<ApplicationOptions & DevServerOptions>;
+
+  /** name of the dev server */
+  name?: string;
+
+  // TODO: fix type once we can support preview with vite
+  /** list of transformers to modify Vite config in an advanced way */
+  transformers?: ViteDevServerOptions['transformers'];
+
+  /** optimize entries before passing them to Vite */
+  optimizeEntries?: (entries: string[], context: ViteAspectsContext) => string[];
+
+  /** Output folder path for build files */
+  outputPath?: string;
+
+  buildMode?: BuildMode;
+
+  sourceRoot?: string;
+};
diff --git a/angular/devkit/vite/utils/utils.ts b/angular/devkit/vite/utils/utils.ts
new file mode 100644
index 00000000..1251c9fe
--- /dev/null
+++ b/angular/devkit/vite/utils/utils.ts
@@ -0,0 +1,21 @@
+import * as path from 'path';
+
+function removeWindowsDriveLetter(osSpecificPath: string): string {
+  return osSpecificPath.replace(/^[A-Z]:/, '');
+}
+
+/**
+ * Coverts an os specific path to a unix style path. Use this when writing paths to config files.
+ * This should not be used to read files on disk because of the removal of Windows drive letters.
+ */
+export function normalizePath(osSpecificPath: string): string {
+  return removeWindowsDriveLetter(osSpecificPath).split('\\').join('/');
+}
+
+/**
+ * Normalized path fragments and joins them. Use this when writing paths to config files.
+ * This should not be used to read files on disk because of the removal of Windows drive letters.
+ */
+export function joinPathFragments(...fragments: string[]): string {
+  return normalizePath(path.join(...fragments));
+}
diff --git a/angular/devkit/webpack/ng-webpack-bundler.ts b/angular/devkit/webpack/ng-webpack-bundler.ts
index e30b1b5c..7a5621cb 100644
--- a/angular/devkit/webpack/ng-webpack-bundler.ts
+++ b/angular/devkit/webpack/ng-webpack-bundler.ts
@@ -1,5 +1,5 @@
 import {
-  AngularEnvOptions,
+  AngularEnvOptions, ApplicationOptions,
   BrowserOptions,
   BundlerSetup,
   DevServerOptions,
@@ -25,13 +25,14 @@ import {
   WebpackMain
 } from '@teambit/webpack';
 import { generateTransformers, runTransformers } from '@teambit/webpack.webpack-bundler';
+import assert from 'assert';
 import { join } from 'path';
 import type { Configuration, WebpackPluginInstance } from 'webpack';
 import { getPreviewRootPath, WebpackConfigFactoryOpts } from './utils';
 import { StatsLoggerPlugin } from './webpack-plugins/stats-logger';
 
 export type NgWebpackBundlerOptions = {
-  angularOptions?: Partial<BrowserOptions & DevServerOptions>;
+  angularOptions?: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>;
 
   /**
    * context of the bundler execution.
@@ -64,9 +65,7 @@ export type WebpackBuildConfigFactory =
 export class NgWebpackBundler {
   static from(options: NgWebpackBundlerOptions): AsyncEnvHandler<WebpackBundler> {
     return async(context: EnvContext): Promise<WebpackBundler> => {
-      if (!options.ngEnvOptions.webpackConfigFactory) {
-        throw new Error('ngEnvOptions.webpackConfigFactory is required to use the Webpack bundler');
-      }
+      assert(options.ngEnvOptions.webpackConfigFactory, 'webpackConfigFactory is required to use the Webpack bundler');
 
       const webpackBuildConfigFactory: WebpackBuildConfigFactory = options.ngEnvOptions.webpackConfigFactory;
       const name = options.name || 'ng-webpack-bundler';
@@ -90,11 +89,11 @@ export class NgWebpackBundler {
       let appRootPath: string;
       let tsconfigPath: string;
       let plugins: WebpackPluginInstance[] = [];
-      if (isAppBuildContext(bundlerContext)) { // When you use `bit run <app>`
-        appRootPath = bundlerContext.capsule.path;// this.workspace?.componentDir(context.appComponent.id, {ignoreVersion: true}) || '';
+      if (isAppBuildContext(bundlerContext)) { // When you use `bit build` for an actual angular app
+        appRootPath = bundlerContext.capsule.path;
         tsconfigPath = join(appRootPath, 'tsconfig.app.json');
         plugins = [new StatsLoggerPlugin()];
-      } else { // When you use `bit build`
+      } else { // When you use `bit build` for the preview app
         appRootPath = getPreviewRootPath(workspace);
         tsconfigPath = writeTsconfig(bundlerContext, appRootPath, tempFolder, application, pkg, devFilesMain, workspace);
       }
@@ -136,9 +135,7 @@ export class NgWebpackBundler {
         return afterMutation.raw;
       }));
 
-      if(!options.ngEnvOptions.webpackModulePath) {
-        throw new Error('ngEnvOptions.webpackModulePath is required to use the Webpack bundler');
-      }
+      assert(options.ngEnvOptions.webpackModulePath, 'webpackModulePath is required to use the Webpack bundler');
 
       // eslint-disable-next-line import/no-dynamic-require,global-require
       const webpack = require(options.ngEnvOptions.webpackModulePath);
diff --git a/angular/devkit/webpack/ng-webpack-dev-server.ts b/angular/devkit/webpack/ng-webpack-dev-server.ts
index 5538dbc4..3fa7fc61 100644
--- a/angular/devkit/webpack/ng-webpack-dev-server.ts
+++ b/angular/devkit/webpack/ng-webpack-dev-server.ts
@@ -1,5 +1,6 @@
 import {
   AngularEnvOptions,
+  ApplicationOptions,
   BrowserOptions,
   BundlerSetup,
   DevServerOptions,
@@ -27,12 +28,13 @@ import {
   WebpackMain
 } from '@teambit/webpack';
 import { generateTransformers, runTransformers } from '@teambit/webpack.webpack-bundler';
+import assert from 'assert';
 import { join, posix } from 'path';
 import type { Configuration } from 'webpack';
 import { getPreviewRootPath, WebpackConfigFactoryOpts } from './utils';
 
 export type WebpackDevServerOptions = {
-  angularOptions: Partial<BrowserOptions & DevServerOptions>;
+  angularOptions: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions>;
 
   /**
    * context of the dev server execution.
@@ -69,9 +71,7 @@ export type WebpackServeConfigFactory =
 export class NgWebpackDevServer {
   static from(options: WebpackDevServerOptions): AsyncEnvHandler<DevServer> {
     return async(context: EnvContext): Promise<DevServer> => {
-      if (!options.ngEnvOptions.webpackConfigFactory) {
-        throw new Error('ngEnvOptions.webpackConfigFactory is required to use the Webpack dev server');
-      }
+      assert(options.ngEnvOptions.webpackConfigFactory, 'ngEnvOptions.webpackConfigFactory is required to use the Webpack dev server');
 
       const name = options.name || 'ng-webpack-dev-server';
       const logger = context.createLogger(name);
@@ -153,12 +153,8 @@ export class NgWebpackDevServer {
         transformerContext
       );
 
-      if (!options.ngEnvOptions.webpackModulePath) {
-        throw new Error('ngEnvOptions.webpackModulePath is required to use the Webpack dev server');
-      }
-      if (!options.ngEnvOptions.webpackDevServerModulePath) {
-        throw new Error('ngEnvOptions.webpackDevServerModulePath is required to use the Webpack dev server');
-      }
+      assert(options.ngEnvOptions.webpackModulePath, 'ngEnvOptions.webpackModulePath is required to use the Webpack dev server');
+      assert(options.ngEnvOptions.webpackDevServerModulePath, 'ngEnvOptions.webpackDevServerModulePath is required to use the Webpack dev server');
 
       // eslint-disable-next-line import/no-dynamic-require,global-require
       const webpack = require(options.ngEnvOptions.webpackModulePath);
diff --git a/angular/devkit/webpack/webpack-plugins/angular-resolver.ts b/angular/devkit/webpack/webpack-plugins/angular-resolver.ts
index 19a12380..0c2bee82 100644
--- a/angular/devkit/webpack/webpack-plugins/angular-resolver.ts
+++ b/angular/devkit/webpack/webpack-plugins/angular-resolver.ts
@@ -6,7 +6,7 @@
  * found in the LICENSE file at https://angular.io/license
  */
 // eslint-disable-next-line max-classes-per-file
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
+import { normalizePath } from '@bitdev/angular.dev-services.common';
 import type { Compiler } from 'webpack';
 import { NodeJSFileSystem } from './nodejs-file-system';
 
@@ -33,7 +33,7 @@ function getResourceData(resolveData: any): ResourceData {
     packageName: descriptionFileData?.name,
     packageVersion: descriptionFileData?.version,
     relativePath,
-    packagePath: pathNormalizeToLinux(descriptionFileRoot),
+    packagePath: normalizePath(descriptionFileRoot),
     resource: resolveData.createData?.resource || resolveData.resource,
     entryPointPackageData: descriptionFileData
   };
diff --git a/angular/envs/angular-env/component.json b/angular/envs/angular-env/component.json
index 53b8168d..cb5d1e88 100644
--- a/angular/envs/angular-env/component.json
+++ b/angular/envs/angular-env/component.json
@@ -17,14 +17,16 @@
           "@angular-eslint/eslint-plugin-template": "~16.1.1",
           "@angular-eslint/template-parser": "~16.1.1",
           "@angular/animations": "^17.0.0",
+          "@angular/cli": "^17.0.0",
           "@angular/common": "^17.0.0",
           "@angular/compiler": "^17.0.0",
           "@angular/compiler-cli": "^17.0.0",
-          "@angular/cli": "^17.0.0",
           "@angular/core": "^17.0.0",
           "@angular/elements": "^17.0.0",
           "@angular/platform-browser": "^17.0.0",
           "@angular/platform-browser-dynamic": "^17.0.0",
+          "@angular/platform-server": "^17.0.0",
+          "@angular/ssr": "^17.0.0",
           "@jest/globals": "^29.3.1",
           "@ngtools/webpack": "^17.0.0",
           "@types/eslint": "^8.40.0",
diff --git a/angular/envs/angular-env/env.jsonc b/angular/envs/angular-env/env.jsonc
index 4777eaa5..d0cf9158 100644
--- a/angular/envs/angular-env/env.jsonc
+++ b/angular/envs/angular-env/env.jsonc
@@ -70,6 +70,16 @@
         "version": "^17.0.0",
         "supportedRange": "^17.0.0"
       },
+      {
+        "name": "@angular/platform-server",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
+      {
+        "name": "@angular/router",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
       {
         "name": "jest",
         "version": "^29.5.0",
diff --git a/angular/envs/angular-v13-env/env.jsonc b/angular/envs/angular-v13-env/env.jsonc
index b32e0f4f..d6b87c4c 100644
--- a/angular/envs/angular-v13-env/env.jsonc
+++ b/angular/envs/angular-v13-env/env.jsonc
@@ -70,6 +70,11 @@
         "version": "~13.2.0",
         "supportedRange": "^13.0.0"
       },
+      {
+        "name": "@angular/router",
+        "version": "~13.2.0",
+        "supportedRange": "^13.0.0"
+      },
       {
         "name": "jest",
         "version": "^27.4.4",
diff --git a/angular/envs/angular-v13-env/webpack-config.factory.ts b/angular/envs/angular-v13-env/webpack-config.factory.ts
index 13ef4227..df356acb 100644
--- a/angular/envs/angular-v13-env/webpack-config.factory.ts
+++ b/angular/envs/angular-v13-env/webpack-config.factory.ts
@@ -1,8 +1,11 @@
 /* eslint-disable no-param-reassign */
-import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
 import { OutputHashing } from '@angular-devkit/build-angular';
 import { getSystemPath, normalize, tags } from '@angular-devkit/core';
-import { BundlerSetup, dedupPaths } from '@bitdev/angular.dev-services.common';
+import { BundlerSetup, dedupPaths, getLoggerApi } from '@bitdev/angular.dev-services.common';
+import type {
+  BrowserBuilderOptions,
+  DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
 import {
   generateEntryPoints,
   generateWebpackConfig,
@@ -29,7 +32,8 @@ import {
   WebpackConfigTransformer,
   WebpackConfigWithDevServer
 } from '@teambit/webpack';
-import path, { join } from 'path';
+import assert from 'assert';
+import { join, posix, resolve } from 'path';
 import { Configuration } from 'webpack';
 import { webpack5BuildConfigFactory } from './webpack/webpack5.build.config';
 import { webpack5ServeConfigFactory } from './webpack/webpack5.serve.config';
@@ -99,6 +103,8 @@ async function getWebpackConfig(
   angularOptions: Partial<BrowserBuilderOptions> = {},
   sourceRoot = 'src'
 ): Promise<WebpackConfigWithDevServer | WebpackConfig> {
+  assert(!(angularOptions as any).server, "SSR is only available for Angular v16+");
+
   // Options from angular.json
   const browserOptions: BrowserBuilderOptions = {
     ...angularOptions,
@@ -109,8 +115,8 @@ async function getWebpackConfig(
     main: angularOptions.main ?? join(sourceRoot, `main.ts`),
     polyfills: angularOptions.polyfills ?? join(sourceRoot, `polyfills.ts`),
     tsConfig: angularOptions.tsConfig ?? tsconfigPath,
-    assets: dedupPaths([path.posix.join(sourceRoot, `favicon.ico`), path.posix.join(sourceRoot, `assets`), ...(angularOptions.assets ?? [])]),
-    styles: dedupPaths([path.posix.join(sourceRoot, `styles.scss`), ...(angularOptions.styles ?? [])]),
+    assets: dedupPaths([posix.join(sourceRoot, `favicon.ico`), posix.join(sourceRoot, `assets`), ...(angularOptions.assets ?? [])]),
+    styles: dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage ?? 'scss' }`), ...(angularOptions.styles ?? [])]),
     scripts: angularOptions.scripts,
     vendorChunk: angularOptions.vendorChunk ?? true,
     namedChunks: angularOptions.namedChunks ?? true,
@@ -123,6 +129,7 @@ async function getWebpackConfig(
     watch: setup === BundlerSetup.Serve,
     allowedCommonJsDependencies: ['dompurify', '@teambit/harmony', 'graphql', '@teambit/documenter.ng.content.copy-box', ...(angularOptions.allowedCommonJsDependencies || [])],
   };
+
   const normalizedWorkspaceRoot = normalize(workspaceRoot);
   // used to load component config files, such as tailwind config, ...
   const projectRoot = normalize(workspaceRoot);
@@ -147,11 +154,7 @@ async function getWebpackConfig(
     }
   );
 
-  const loggerApi = {
-    createChild: () => logger as any,
-    ...logger,
-    log: logger.console,
-  } as any;
+  const loggerApi = getLoggerApi(logger);
 
   let webpackConfig: any = await generateWebpackConfig(
     getSystemPath(normalizedWorkspaceRoot),
@@ -187,7 +190,7 @@ async function getWebpackConfig(
   const cacheOptions = normalizeCacheOptions({}, workspaceRoot);
   webpackConfig.plugins.push(
     new IndexHtmlWebpackPlugin({
-      indexPath: path.resolve(workspaceRoot, browserOptions.index as string),
+      indexPath: resolve(workspaceRoot, browserOptions.index as string),
       outputPath: getIndexOutputFile(normalizedIndex),
       baseHref: browserOptions.baseHref || '/',
       entrypoints,
diff --git a/angular/envs/angular-v13-env/webpack/webpack5.serve.config.ts b/angular/envs/angular-v13-env/webpack/webpack5.serve.config.ts
index 271130e9..1c4224a2 100644
--- a/angular/envs/angular-v13-env/webpack/webpack5.serve.config.ts
+++ b/angular/envs/angular-v13-env/webpack/webpack5.serve.config.ts
@@ -1,5 +1,8 @@
-import { BitDedupeModuleResolvePlugin, StatsLoggerPlugin } from '@bitdev/angular.dev-services.webpack';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
+import { normalizePath } from '@bitdev/angular.dev-services.common';
+import {
+  BitDedupeModuleResolvePlugin,
+  StatsLoggerPlugin
+} from '@bitdev/angular.dev-services.webpack';
 import { PubsubMain } from '@teambit/pubsub';
 import {
   fallbacks,
@@ -66,7 +69,7 @@ export function webpack5ServeConfigFactory(
       chunkFilename: 'static/js/[name].chunk.js',
 
       // point sourcemap entries to original disk locations (format as URL on windows)
-      devtoolModuleFilenameTemplate: (info: any) => pathNormalizeToLinux(resolve(info.absoluteResourcePath)),
+      devtoolModuleFilenameTemplate: (info: any) => normalizePath(resolve(info.absoluteResourcePath)),
 
       // this defaults to 'window', but by setting it to 'this' then
       // module chunks which are built will work in web workers as well.
diff --git a/angular/envs/angular-v14-env/env.jsonc b/angular/envs/angular-v14-env/env.jsonc
index e72572ec..b10bc0c1 100644
--- a/angular/envs/angular-v14-env/env.jsonc
+++ b/angular/envs/angular-v14-env/env.jsonc
@@ -70,6 +70,11 @@
         "version": "~14.0.2",
         "supportedRange": "^14.0.0"
       },
+      {
+        "name": "@angular/router",
+        "version": "~14.0.2",
+        "supportedRange": "^14.0.0"
+      },
       {
         "name": "jest",
         "version": "^28.0.0",
diff --git a/angular/envs/angular-v14-env/webpack-config.factory.ts b/angular/envs/angular-v14-env/webpack-config.factory.ts
index 7a1dc939..71b3e617 100644
--- a/angular/envs/angular-v14-env/webpack-config.factory.ts
+++ b/angular/envs/angular-v14-env/webpack-config.factory.ts
@@ -1,8 +1,11 @@
 /* eslint-disable no-param-reassign */
-import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
 import { OutputHashing } from '@angular-devkit/build-angular';
 import { getSystemPath, normalize, tags } from '@angular-devkit/core';
-import { BundlerSetup, dedupPaths } from '@bitdev/angular.dev-services.common';
+import { BundlerSetup, dedupPaths, getLoggerApi } from '@bitdev/angular.dev-services.common';
+import type {
+  BrowserBuilderOptions,
+  DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
 import {
   generateEntryPoints,
   generateWebpackConfig,
@@ -29,7 +32,8 @@ import {
   WebpackConfigTransformer,
   WebpackConfigWithDevServer
 } from '@teambit/webpack';
-import path, { join } from 'path';
+import assert from 'assert';
+import { join, posix, resolve } from 'path';
 import { Configuration } from 'webpack';
 import { webpack5BuildConfigFactory } from './webpack/webpack5.build.config';
 import { webpack5ServeConfigFactory } from './webpack/webpack5.serve.config';
@@ -99,6 +103,8 @@ async function getWebpackConfig(
   angularOptions: Partial<BrowserBuilderOptions> = {},
   sourceRoot = 'src'
 ): Promise<WebpackConfigWithDevServer | WebpackConfig> {
+  assert(!(angularOptions as any).server, "SSR is only available for Angular v16+");
+
   // Options from angular.json
   const browserOptions: BrowserBuilderOptions = {
     ...angularOptions,
@@ -109,8 +115,8 @@ async function getWebpackConfig(
     main: angularOptions.main ?? `./${join(sourceRoot, `main.ts`)}`,
     polyfills: angularOptions.polyfills ?? `./${join(sourceRoot, `polyfills.ts`)}`,
     tsConfig: angularOptions.tsConfig ?? tsconfigPath,
-    assets: dedupPaths([path.posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
-    styles: dedupPaths([path.posix.join(sourceRoot, `styles.scss`), ...(angularOptions.styles ?? [])]),
+    assets: dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
+    styles: dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage ?? 'scss' }`), ...(angularOptions.styles ?? [])]),
     scripts: angularOptions.scripts,
     vendorChunk: angularOptions.vendorChunk ?? true,
     namedChunks: angularOptions.namedChunks ?? true,
@@ -123,16 +129,12 @@ async function getWebpackConfig(
     watch: setup === BundlerSetup.Serve,
     allowedCommonJsDependencies: ['dompurify', '@teambit/harmony', 'graphql', '@teambit/documenter.ng.content.copy-box', ...(angularOptions.allowedCommonJsDependencies || [])]
   };
+
   const normalizedWorkspaceRoot = normalize(workspaceRoot);
   // used to load component config files, such as tailwind config, ...
   const projectRoot = normalize(workspaceRoot);
   const normalizedSourceRoot = normalize(sourceRoot);
-
-  const loggerApi = {
-    createChild: () => logger as any,
-    ...logger,
-    log: logger.console
-  } as any;
+  const loggerApi = getLoggerApi(logger);
 
   const normalizedOptions = normalizeBrowserSchema(
     normalizedWorkspaceRoot,
@@ -188,7 +190,7 @@ async function getWebpackConfig(
   const cacheOptions = normalizeCacheOptions({}, workspaceRoot);
   webpackConfig.plugins.push(
     new IndexHtmlWebpackPlugin({
-      indexPath: path.resolve(workspaceRoot, browserOptions.index as string),
+      indexPath: resolve(workspaceRoot, browserOptions.index as string),
       outputPath: getIndexOutputFile(normalizedIndex),
       baseHref: browserOptions.baseHref || '/',
       entrypoints,
diff --git a/angular/envs/angular-v14-env/webpack/webpack5.serve.config.ts b/angular/envs/angular-v14-env/webpack/webpack5.serve.config.ts
index 58c46378..14ae0ea2 100644
--- a/angular/envs/angular-v14-env/webpack/webpack5.serve.config.ts
+++ b/angular/envs/angular-v14-env/webpack/webpack5.serve.config.ts
@@ -1,5 +1,8 @@
-import { BitDedupeModuleResolvePlugin, StatsLoggerPlugin } from '@bitdev/angular.dev-services.webpack';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
+import { normalizePath } from '@bitdev/angular.dev-services.common';
+import {
+  BitDedupeModuleResolvePlugin,
+  StatsLoggerPlugin
+} from '@bitdev/angular.dev-services.webpack';
 import { PubsubMain } from '@teambit/pubsub';
 import {
   fallbacks,
@@ -65,7 +68,7 @@ export function webpack5ServeConfigFactory(
       chunkFilename: 'static/js/[name].chunk.js',
 
       // point sourcemap entries to original disk locations (format as URL on windows)
-      devtoolModuleFilenameTemplate: (info: any) => pathNormalizeToLinux(resolve(info.absoluteResourcePath))
+      devtoolModuleFilenameTemplate: (info: any) => normalizePath(resolve(info.absoluteResourcePath))
 
       // this defaults to 'window', but by setting it to 'this' then
       // module chunks which are built will work in web workers as well.
diff --git a/angular/envs/angular-v15-env/env.jsonc b/angular/envs/angular-v15-env/env.jsonc
index d3cf253f..1bdbf7e7 100644
--- a/angular/envs/angular-v15-env/env.jsonc
+++ b/angular/envs/angular-v15-env/env.jsonc
@@ -70,6 +70,11 @@
         "version": "~15.0.4",
         "supportedRange": "^15.0.0"
       },
+      {
+        "name": "@angular/router",
+        "version": "~15.0.4",
+        "supportedRange": "^15.0.0"
+      },
       {
         "name": "jest",
         "version": "^29.3.1",
diff --git a/angular/envs/angular-v15-env/webpack-config.factory.ts b/angular/envs/angular-v15-env/webpack-config.factory.ts
index 11fdacc1..33ef14c6 100644
--- a/angular/envs/angular-v15-env/webpack-config.factory.ts
+++ b/angular/envs/angular-v15-env/webpack-config.factory.ts
@@ -2,7 +2,7 @@
 import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
 import { OutputHashing } from '@angular-devkit/build-angular';
 import { getSystemPath, normalize, tags } from '@angular-devkit/core';
-import { BundlerSetup, dedupPaths } from '@bitdev/angular.dev-services.common';
+import { BundlerSetup, dedupPaths, getLoggerApi } from '@bitdev/angular.dev-services.common';
 import {
   generateEntryPoints,
   generateWebpackConfig,
@@ -29,7 +29,8 @@ import {
   WebpackConfigTransformer,
   WebpackConfigWithDevServer
 } from '@teambit/webpack';
-import path, { join } from 'path';
+import assert from 'assert';
+import { join, posix, resolve } from 'path';
 import { Configuration } from 'webpack';
 import { webpack5BuildConfigFactory } from './webpack/webpack5.build.config';
 import { webpack5ServeConfigFactory } from './webpack/webpack5.serve.config';
@@ -99,6 +100,8 @@ async function getWebpackConfig(
   angularOptions: Partial<BrowserBuilderOptions> = {},
   sourceRoot = 'src'
 ): Promise<WebpackConfigWithDevServer | WebpackConfig> {
+  assert(!(angularOptions as any).server, "SSR is only available for Angular v16+");
+
   // Options from angular.json
   const browserOptions: BrowserBuilderOptions = {
     ...angularOptions,
@@ -107,10 +110,10 @@ async function getWebpackConfig(
     outputPath: 'public', // doesn't matter because it will be deleted from the config
     index: angularOptions.index ?? `./${join(sourceRoot, `index.html`)}`,
     main: angularOptions.main ?? `./${join(sourceRoot, `main.ts`)}`,
-    polyfills: angularOptions.polyfills ?? `./${join(sourceRoot, `polyfills.ts`)}`,
+    polyfills: angularOptions.polyfills,
     tsConfig: angularOptions.tsConfig ?? tsconfigPath,
-    assets: dedupPaths([path.posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
-    styles: dedupPaths([path.posix.join(sourceRoot, `styles.scss`), ...(angularOptions.styles ?? [])]),
+    assets: dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
+    styles: dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage ?? 'scss' }`), ...(angularOptions.styles ?? [])]),
     scripts: angularOptions.scripts,
     vendorChunk: angularOptions.vendorChunk ?? true,
     namedChunks: angularOptions.namedChunks ?? true,
@@ -123,16 +126,12 @@ async function getWebpackConfig(
     watch: setup === BundlerSetup.Serve,
     allowedCommonJsDependencies: ['dompurify', '@teambit/harmony', 'graphql', '@teambit/documenter.ng.content.copy-box', ...(angularOptions.allowedCommonJsDependencies || [])]
   };
+
   const normalizedWorkspaceRoot = normalize(workspaceRoot);
   // used to load component config files, such as tailwind config, ...
   const projectRoot = normalize(workspaceRoot);
   const normalizedSourceRoot = normalize(sourceRoot);
-
-  const loggerApi = {
-    createChild: () => logger as any,
-    ...logger,
-    log: logger.console
-  } as any;
+  const loggerApi = getLoggerApi(logger);
 
   const normalizedOptions = normalizeBrowserSchema(
     normalizedWorkspaceRoot,
@@ -189,7 +188,7 @@ async function getWebpackConfig(
   const cacheOptions = normalizeCacheOptions({}, workspaceRoot);
   webpackConfig.plugins.push(
     new IndexHtmlWebpackPlugin({
-      indexPath: path.resolve(workspaceRoot, browserOptions.index as string),
+      indexPath: resolve(workspaceRoot, browserOptions.index as string),
       outputPath: getIndexOutputFile(normalizedIndex),
       baseHref: browserOptions.baseHref || '/',
       entrypoints,
diff --git a/angular/envs/angular-v15-env/webpack/webpack5.serve.config.ts b/angular/envs/angular-v15-env/webpack/webpack5.serve.config.ts
index d4527652..dc2c9dd5 100644
--- a/angular/envs/angular-v15-env/webpack/webpack5.serve.config.ts
+++ b/angular/envs/angular-v15-env/webpack/webpack5.serve.config.ts
@@ -1,5 +1,5 @@
+import { normalizePath } from '@bitdev/angular.dev-services.common';
 import { BitDedupeModuleResolvePlugin, StatsLoggerPlugin } from '@bitdev/angular.dev-services.webpack';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
 import { PubsubMain } from '@teambit/pubsub';
 import {
   fallbacks,
@@ -65,7 +65,7 @@ export function webpack5ServeConfigFactory(
       chunkFilename: 'static/js/[name].chunk.js',
 
       // point sourcemap entries to original disk locations (format as URL on windows)
-      devtoolModuleFilenameTemplate: (info: any) => pathNormalizeToLinux(resolve(info.absoluteResourcePath))
+      devtoolModuleFilenameTemplate: (info: any) => normalizePath(resolve(info.absoluteResourcePath))
 
       // this defaults to 'window', but by setting it to 'this' then
       // module chunks which are built will work in web workers as well.
diff --git a/angular/envs/angular-v16-env/angular-v16-env.bit-env.ts b/angular/envs/angular-v16-env/angular-v16-env.bit-env.ts
index 288e3eb1..adecc205 100644
--- a/angular/envs/angular-v16-env/angular-v16-env.bit-env.ts
+++ b/angular/envs/angular-v16-env/angular-v16-env.bit-env.ts
@@ -1,19 +1,6 @@
-import {
-  AngularEnvOptions,
-  BrowserOptions,
-  DevServerOptions,
-  isAppDevContext
-} from '@bitdev/angular.dev-services.common';
-import { NgViteDevServer, ViteConfigTransformer } from '@bitdev/angular.dev-services.vite';
+import { AngularEnvOptions } from '@bitdev/angular.dev-services.common';
 import { AngularBaseEnv } from '@bitdev/angular.envs.base-env';
-import { DevServer, DevServerContext } from '@teambit/bundler';
-import { AsyncEnvHandler } from '@teambit/envs';
 import { NativeCompileCache } from '@teambit/toolbox.performance.v8-cache';
-import {
-  Configuration,
-  WebpackConfigTransformer,
-  WebpackConfigWithDevServer
-} from '@teambit/webpack';
 import { webpackConfigFactory } from './webpack-config.factory';
 
 // Disable v8-caching because it breaks ESM loaders
@@ -39,29 +26,8 @@ export class AngularV16Env extends AngularBaseEnv {
     // resolving to the webpack used by angular devkit to avoid multiple instances of webpack
     // otherwise, if we use a different version, it would break
     webpackModulePath: require.resolve('webpack', { paths: [require.resolve('@angular-devkit/build-angular')] }),
-    devServer: 'webpack',
+    // devServer: 'webpack',
   };
-
-  override getDevServer(
-    devServerContext: DevServerContext,
-    ngEnvOptions: AngularEnvOptions,
-    transformers: (WebpackConfigTransformer | ViteConfigTransformer)[] = [],
-    angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
-    webpackOptions: Partial<WebpackConfigWithDevServer | Configuration> = {},
-    sourceRoot?: string
-  ): AsyncEnvHandler<DevServer> {
-    if (this.ngEnvOptions.devServer === 'vite' && isAppDevContext(devServerContext)) {
-      return NgViteDevServer.from({
-        angularOptions,
-        devServerContext,
-        ngEnvOptions,
-        sourceRoot,
-        transformers,
-        webpackOptions
-      });
-    }
-    return super.getDevServer(devServerContext, ngEnvOptions, transformers as WebpackConfigTransformer[], angularOptions, webpackOptions, sourceRoot);
-  }
 }
 
 export default new AngularV16Env();
diff --git a/angular/envs/angular-v16-env/component.json b/angular/envs/angular-v16-env/component.json
index 59afd1f9..fc95fe93 100644
--- a/angular/envs/angular-v16-env/component.json
+++ b/angular/envs/angular-v16-env/component.json
@@ -17,14 +17,15 @@
           "@angular-eslint/eslint-plugin-template": "~16.1.1",
           "@angular-eslint/template-parser": "~16.1.1",
           "@angular/animations": "~16.2.0",
+          "@angular/cli": "~16.2.0",
           "@angular/common": "~16.2.0",
           "@angular/compiler": "~16.2.0",
           "@angular/compiler-cli": "~16.2.0",
-          "@angular/cli": "~16.2.0",
           "@angular/core": "~16.2.0",
           "@angular/elements": "~16.2.0",
           "@angular/platform-browser": "~16.2.0",
           "@angular/platform-browser-dynamic": "~16.2.0",
+          "@angular/platform-server": "~16.2.0",
           "@jest/globals": "^29.3.1",
           "@ngtools/webpack": "~16.2.0",
           "@types/eslint": "^8.40.0",
diff --git a/angular/envs/angular-v16-env/env.jsonc b/angular/envs/angular-v16-env/env.jsonc
index d0bb3237..30930fd2 100644
--- a/angular/envs/angular-v16-env/env.jsonc
+++ b/angular/envs/angular-v16-env/env.jsonc
@@ -70,6 +70,16 @@
         "version": "~16.2.0",
         "supportedRange": "^16.2.0"
       },
+      {
+        "name": "@angular/platform-server",
+        "version": "^16.2.0",
+        "supportedRange": "^16.2.0"
+      },
+      {
+        "name": "@angular/router",
+        "version": "^16.2.0",
+        "supportedRange": "^16.2.0"
+      },
       {
         "name": "jest",
         "version": "^29.5.0",
diff --git a/angular/envs/angular-v16-env/webpack-config.factory.ts b/angular/envs/angular-v16-env/webpack-config.factory.ts
index 63f15c4f..09fa6897 100644
--- a/angular/envs/angular-v16-env/webpack-config.factory.ts
+++ b/angular/envs/angular-v16-env/webpack-config.factory.ts
@@ -1,8 +1,11 @@
 /* eslint-disable no-param-reassign */
-import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
 import { OutputHashing } from '@angular-devkit/build-angular';
 import { getSystemPath, normalize, tags } from '@angular-devkit/core';
-import { BundlerSetup, dedupPaths } from '@bitdev/angular.dev-services.common';
+import { BundlerSetup, dedupPaths, getLoggerApi } from '@bitdev/angular.dev-services.common';
+import type {
+  BrowserBuilderOptions,
+  DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
 import {
   generateEntryPoints,
   generateWebpackConfig,
@@ -29,7 +32,7 @@ import {
   WebpackConfigTransformer,
   WebpackConfigWithDevServer
 } from '@teambit/webpack';
-import path, { join } from 'path';
+import { join, posix, resolve } from 'path';
 import type { Configuration } from 'webpack';
 import { webpack5BuildConfigFactory } from './webpack/webpack5.build.config';
 import { webpack5ServeConfigFactory } from './webpack/webpack5.serve.config';
@@ -107,10 +110,10 @@ async function getWebpackConfig(
     outputPath: 'public', // doesn't matter because it will be deleted from the config
     index: angularOptions.index ?? `./${join(sourceRoot, `index.html`)}`,
     main: angularOptions.main ?? `./${join(sourceRoot, `main.ts`)}`,
-    polyfills: angularOptions.polyfills ?? `./${join(sourceRoot, `polyfills.ts`)}`,
+    polyfills: angularOptions.polyfills,
     tsConfig: angularOptions.tsConfig ?? tsconfigPath,
-    assets: dedupPaths([path.posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
-    styles: dedupPaths([path.posix.join(sourceRoot, `styles.scss`), ...(angularOptions.styles ?? [])]),
+    assets: dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
+    styles: dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage ?? 'scss' }`), ...(angularOptions.styles ?? [])]),
     scripts: angularOptions.scripts,
     vendorChunk: angularOptions.vendorChunk ?? true,
     namedChunks: angularOptions.namedChunks ?? true,
@@ -127,11 +130,7 @@ async function getWebpackConfig(
   // used to load component config files, such as tailwind config, ...
   const projectRoot = normalize(workspaceRoot);
   const normalizedSourceRoot = normalize(sourceRoot);
-  const loggerApi = {
-    createChild: () => logger as any,
-    ...logger,
-    log: logger.console
-  } as any;
+  const loggerApi = getLoggerApi(logger);
 
   const normalizedOptions = normalizeBrowserSchema(
     normalizedWorkspaceRoot,
@@ -188,7 +187,7 @@ async function getWebpackConfig(
   const cacheOptions = normalizeCacheOptions({}, workspaceRoot);
   webpackConfig.plugins.push(
     new IndexHtmlWebpackPlugin({
-      indexPath: path.resolve(workspaceRoot, browserOptions.index as string),
+      indexPath: resolve(workspaceRoot, browserOptions.index as string),
       outputPath: getIndexOutputFile(normalizedIndex),
       baseHref: browserOptions.baseHref || '/',
       entrypoints,
diff --git a/angular/envs/angular-v16-env/webpack/webpack5.serve.config.ts b/angular/envs/angular-v16-env/webpack/webpack5.serve.config.ts
index d4527652..dc2c9dd5 100644
--- a/angular/envs/angular-v16-env/webpack/webpack5.serve.config.ts
+++ b/angular/envs/angular-v16-env/webpack/webpack5.serve.config.ts
@@ -1,5 +1,5 @@
+import { normalizePath } from '@bitdev/angular.dev-services.common';
 import { BitDedupeModuleResolvePlugin, StatsLoggerPlugin } from '@bitdev/angular.dev-services.webpack';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
 import { PubsubMain } from '@teambit/pubsub';
 import {
   fallbacks,
@@ -65,7 +65,7 @@ export function webpack5ServeConfigFactory(
       chunkFilename: 'static/js/[name].chunk.js',
 
       // point sourcemap entries to original disk locations (format as URL on windows)
-      devtoolModuleFilenameTemplate: (info: any) => pathNormalizeToLinux(resolve(info.absoluteResourcePath))
+      devtoolModuleFilenameTemplate: (info: any) => normalizePath(resolve(info.absoluteResourcePath))
 
       // this defaults to 'window', but by setting it to 'this' then
       // module chunks which are built will work in web workers as well.
diff --git a/angular/envs/angular-v17-env/angular-v17-env.bit-env.ts b/angular/envs/angular-v17-env/angular-v17-env.bit-env.ts
index b57df631..2988b5b5 100644
--- a/angular/envs/angular-v17-env/angular-v17-env.bit-env.ts
+++ b/angular/envs/angular-v17-env/angular-v17-env.bit-env.ts
@@ -1,19 +1,6 @@
-import {
-  AngularEnvOptions,
-  BrowserOptions,
-  DevServerOptions,
-  isAppDevContext
-} from '@bitdev/angular.dev-services.common';
-import { NgViteDevServer, ViteConfigTransformer } from '@bitdev/angular.dev-services.vite';
+import { AngularEnvOptions } from '@bitdev/angular.dev-services.common';
 import { AngularBaseEnv } from '@bitdev/angular.envs.base-env';
-import { DevServer, DevServerContext } from '@teambit/bundler';
-import { AsyncEnvHandler } from '@teambit/envs';
 import { NativeCompileCache } from '@teambit/toolbox.performance.v8-cache';
-import {
-  Configuration,
-  WebpackConfigTransformer,
-  WebpackConfigWithDevServer
-} from '@teambit/webpack';
 import { webpackConfigFactory } from './webpack-config.factory';
 
 // Disable v8-caching because it breaks ESM loaders
@@ -39,29 +26,8 @@ export class AngularV17Env extends AngularBaseEnv {
     // resolving to the webpack used by angular devkit to avoid multiple instances of webpack
     // otherwise, if we use a different version, it would break
     webpackModulePath: require.resolve('webpack', { paths: [require.resolve('@angular-devkit/build-angular')] }),
-    devServer: 'webpack',
+    // devServer: 'vite',
   };
-
-  override getDevServer(
-    devServerContext: DevServerContext,
-    ngEnvOptions: AngularEnvOptions,
-    transformers: (WebpackConfigTransformer | ViteConfigTransformer)[] = [],
-    angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
-    webpackOptions: Partial<WebpackConfigWithDevServer | Configuration> = {},
-    sourceRoot?: string
-  ): AsyncEnvHandler<DevServer> {
-    if (this.ngEnvOptions.devServer === 'vite' && isAppDevContext(devServerContext)) {
-      return NgViteDevServer.from({
-        angularOptions,
-        devServerContext,
-        ngEnvOptions,
-        sourceRoot,
-        transformers,
-        webpackOptions
-      });
-    }
-    return super.getDevServer(devServerContext, ngEnvOptions, transformers as WebpackConfigTransformer[], angularOptions, webpackOptions, sourceRoot);
-  }
 }
 
 export default new AngularV17Env();
diff --git a/angular/envs/angular-v17-env/component.json b/angular/envs/angular-v17-env/component.json
index e726de23..0fefd6c0 100644
--- a/angular/envs/angular-v17-env/component.json
+++ b/angular/envs/angular-v17-env/component.json
@@ -17,14 +17,16 @@
           "@angular-eslint/eslint-plugin-template": "~16.1.1",
           "@angular-eslint/template-parser": "~16.1.1",
           "@angular/animations": "^17.0.0",
+          "@angular/cli": "^17.0.0",
           "@angular/common": "^17.0.0",
           "@angular/compiler": "^17.0.0",
           "@angular/compiler-cli": "^17.0.0",
-          "@angular/cli": "^17.0.0",
           "@angular/core": "^17.0.0",
           "@angular/elements": "^17.0.0",
           "@angular/platform-browser": "^17.0.0",
           "@angular/platform-browser-dynamic": "^17.0.0",
+          "@angular/platform-server": "^17.0.0",
+          "@angular/ssr": "^17.0.0",
           "@jest/globals": "^29.3.1",
           "@ngtools/webpack": "^17.0.0",
           "@types/eslint": "^8.40.0",
diff --git a/angular/envs/angular-v17-env/env.jsonc b/angular/envs/angular-v17-env/env.jsonc
index 4777eaa5..d0cf9158 100644
--- a/angular/envs/angular-v17-env/env.jsonc
+++ b/angular/envs/angular-v17-env/env.jsonc
@@ -70,6 +70,16 @@
         "version": "^17.0.0",
         "supportedRange": "^17.0.0"
       },
+      {
+        "name": "@angular/platform-server",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
+      {
+        "name": "@angular/router",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
       {
         "name": "jest",
         "version": "^29.5.0",
diff --git a/angular/envs/angular-v17-env/webpack-config.factory.ts b/angular/envs/angular-v17-env/webpack-config.factory.ts
index 2d4c0937..7c133669 100644
--- a/angular/envs/angular-v17-env/webpack-config.factory.ts
+++ b/angular/envs/angular-v17-env/webpack-config.factory.ts
@@ -1,8 +1,11 @@
 /* eslint-disable no-param-reassign */
-import type { BrowserBuilderOptions, DevServerBuilderOptions } from '@angular-devkit/build-angular';
 import { OutputHashing } from '@angular-devkit/build-angular';
 import { getSystemPath, normalize, tags } from '@angular-devkit/core';
-import { BundlerSetup, dedupPaths } from '@bitdev/angular.dev-services.common';
+import { BundlerSetup, dedupPaths, getLoggerApi } from '@bitdev/angular.dev-services.common';
+import type {
+  BrowserBuilderOptions,
+  DevServerBuilderOptions
+} from '@bitdev/angular.dev-services.ng-compat';
 import {
   generateEntryPoints,
   generateWebpackConfig,
@@ -29,7 +32,7 @@ import {
   WebpackConfigTransformer,
   WebpackConfigWithDevServer
 } from '@teambit/webpack';
-import path, { join } from 'path';
+import { join, posix, resolve } from 'path';
 import type { Configuration } from 'webpack';
 import { webpack5BuildConfigFactory } from './webpack/webpack5.build.config';
 import { webpack5ServeConfigFactory } from './webpack/webpack5.serve.config';
@@ -96,7 +99,7 @@ async function getWebpackConfig(
   logger: Logger,
   setup: BundlerSetup,
   webpackOptions: Partial<WebpackConfigWithDevServer | WebpackConfig> = {},
-  angularOptions: Partial<BrowserBuilderOptions> = {},
+  angularOptions: Partial<any> = {},
   sourceRoot = 'src'
 ): Promise<WebpackConfigWithDevServer | WebpackConfig> {
   // Options from angular.json
@@ -106,11 +109,11 @@ async function getWebpackConfig(
     preserveSymlinks: false,
     outputPath: 'public', // doesn't matter because it will be deleted from the config
     index: angularOptions.index ?? `./${join(sourceRoot, `index.html`)}`,
-    main: angularOptions.main ?? `./${join(sourceRoot, `main.ts`)}`,
-    polyfills: angularOptions.polyfills ?? `./${join(sourceRoot, `polyfills.ts`)}`,
+    main: angularOptions.browser ?? `./${join(sourceRoot, `main.ts`)}`,
+    polyfills: angularOptions.polyfills,
     tsConfig: angularOptions.tsConfig ?? tsconfigPath,
-    assets: dedupPaths([path.posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
-    styles: dedupPaths([path.posix.join(sourceRoot, `styles.scss`), ...(angularOptions.styles ?? [])]),
+    assets: dedupPaths([posix.join(sourceRoot, `assets/**/*`), ...(angularOptions.assets ?? [])]),
+    styles: dedupPaths([posix.join(sourceRoot, `styles.${ angularOptions.inlineStyleLanguage ?? 'scss' }`), ...(angularOptions.styles ?? [])]),
     scripts: angularOptions.scripts,
     vendorChunk: angularOptions.vendorChunk ?? true,
     namedChunks: angularOptions.namedChunks ?? true,
@@ -127,11 +130,7 @@ async function getWebpackConfig(
   // used to load component config files, such as tailwind config, ...
   const projectRoot = normalize(workspaceRoot);
   const normalizedSourceRoot = normalize(sourceRoot);
-  const loggerApi = {
-    createChild: () => logger as any,
-    ...logger,
-    log: logger.console
-  } as any;
+  const loggerApi = getLoggerApi(logger);
   const normalizedOptions = normalizeBrowserSchema(
     normalizedWorkspaceRoot,
     projectRoot,
@@ -187,7 +186,7 @@ async function getWebpackConfig(
   const cacheOptions = normalizeCacheOptions({}, workspaceRoot);
   webpackConfig.plugins.push(
     new IndexHtmlWebpackPlugin({
-      indexPath: path.resolve(workspaceRoot, browserOptions.index as string),
+      indexPath: resolve(workspaceRoot, browserOptions.index as string),
       outputPath: getIndexOutputFile(normalizedIndex),
       baseHref: browserOptions.baseHref || '/',
       entrypoints,
diff --git a/angular/envs/angular-v17-env/webpack/webpack5.serve.config.ts b/angular/envs/angular-v17-env/webpack/webpack5.serve.config.ts
index d4527652..dc2c9dd5 100644
--- a/angular/envs/angular-v17-env/webpack/webpack5.serve.config.ts
+++ b/angular/envs/angular-v17-env/webpack/webpack5.serve.config.ts
@@ -1,5 +1,5 @@
+import { normalizePath } from '@bitdev/angular.dev-services.common';
 import { BitDedupeModuleResolvePlugin, StatsLoggerPlugin } from '@bitdev/angular.dev-services.webpack';
-import { pathNormalizeToLinux } from '@teambit/legacy/dist/utils';
 import { PubsubMain } from '@teambit/pubsub';
 import {
   fallbacks,
@@ -65,7 +65,7 @@ export function webpack5ServeConfigFactory(
       chunkFilename: 'static/js/[name].chunk.js',
 
       // point sourcemap entries to original disk locations (format as URL on windows)
-      devtoolModuleFilenameTemplate: (info: any) => pathNormalizeToLinux(resolve(info.absoluteResourcePath))
+      devtoolModuleFilenameTemplate: (info: any) => normalizePath(resolve(info.absoluteResourcePath))
 
       // this defaults to 'window', but by setting it to 'this' then
       // module chunks which are built will work in web workers as well.
diff --git a/angular/envs/base-env/angular-base-env.bit-env.ts b/angular/envs/base-env/angular-base-env.bit-env.ts
index dc582e65..495f1521 100644
--- a/angular/envs/base-env/angular-base-env.bit-env.ts
+++ b/angular/envs/base-env/angular-base-env.bit-env.ts
@@ -1,6 +1,7 @@
 import { AngularAppType } from '@bitdev/angular.app-types.angular-app-type';
 import {
   AngularEnvOptions,
+  ApplicationOptions,
   BrowserOptions,
   DevServerOptions,
   NG_APP_NAME
@@ -76,9 +77,9 @@ export abstract class AngularBaseEnv implements AngularEnvInterface {
    */
   public setNgEnvOptions(...ngEnvOptions: Partial<AngularEnvOptions>[]): void {
     this.ngEnvOptions = merge(this.ngEnvOptions || {}, ...ngEnvOptions);
-    if (this.ngEnvOptions.devServer === 'vite' && this.angularVersion < 16) {
+    /*if (this.ngEnvOptions.devServer === 'vite' && this.angularVersion < 16) {
       throw new Error(`Vite dev server is only supported for Angular 16+`);
-    }
+    }*/
   }
 
   /**
@@ -148,7 +149,7 @@ export abstract class AngularBaseEnv implements AngularEnvInterface {
     devServerContext: DevServerContext,
     ngEnvOptions: AngularEnvOptions,
     transformers: WebpackConfigTransformer[] = [],
-    angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
+    angularOptions: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions> = {},
     webpackOptions: any = {},
     sourceRoot?: string
   ): AsyncEnvHandler<DevServer> {
@@ -166,7 +167,7 @@ export abstract class AngularBaseEnv implements AngularEnvInterface {
     bundlerContext: BundlerContext,
     ngEnvOptions: AngularEnvOptions,
     transformers: WebpackConfigTransformer[] = [],
-    angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
+    angularOptions: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions> = {},
     webpackOptions: any = {},
     sourceRoot?: string
   ): AsyncEnvHandler<Bundler> {
@@ -185,7 +186,7 @@ export abstract class AngularBaseEnv implements AngularEnvInterface {
     const devServerProvider: DevServerProvider = (
       devServerContext: DevServerContext,
       transformers: WebpackConfigTransformer[] = [],
-      angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
+      angularOptions: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions> = {},
       webpackOptions: any = {},
       sourceRoot?: string
     ) => this.getDevServer(devServerContext, ngEnvOptions, transformers, angularOptions, webpackOptions, sourceRoot);
diff --git a/angular/examples/my-angular-env/component.json b/angular/examples/my-angular-env/component.json
index 5c315ebf..0d2e7acb 100644
--- a/angular/examples/my-angular-env/component.json
+++ b/angular/examples/my-angular-env/component.json
@@ -12,7 +12,7 @@
           "@bitdev/angular.dev-services.linter.eslint": ">= 1.0.0",
           "@types/jest": "^29.5.0",
           "jest": "^29.5.0",
-          "jest-preset-angular": "~13.1.0"
+          "jest-preset-angular": "~13.1.3"
         }
       }
     }
diff --git a/angular/examples/my-angular-env/env.jsonc b/angular/examples/my-angular-env/env.jsonc
index 4777eaa5..d0cf9158 100644
--- a/angular/examples/my-angular-env/env.jsonc
+++ b/angular/examples/my-angular-env/env.jsonc
@@ -70,6 +70,16 @@
         "version": "^17.0.0",
         "supportedRange": "^17.0.0"
       },
+      {
+        "name": "@angular/platform-server",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
+      {
+        "name": "@angular/router",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
       {
         "name": "jest",
         "version": "^29.5.0",
diff --git a/angular/examples/my-angular-v17-env/env.jsonc b/angular/examples/my-angular-v17-env/env.jsonc
index b3028bec..d0cf9158 100644
--- a/angular/examples/my-angular-v17-env/env.jsonc
+++ b/angular/examples/my-angular-v17-env/env.jsonc
@@ -70,6 +70,16 @@
         "version": "^17.0.0",
         "supportedRange": "^17.0.0"
       },
+      {
+        "name": "@angular/platform-server",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
+      {
+        "name": "@angular/router",
+        "version": "^17.0.0",
+        "supportedRange": "^17.0.0"
+      },
       {
         "name": "jest",
         "version": "^29.5.0",
@@ -78,7 +88,7 @@
       {
         "name": "rxjs",
         "version": "^7.8.1",
-        "supportedRange": "^7.8.0"
+        "supportedRange": "^6.5.3 || ^7.4.0"
       },
       {
         "name": "tslib",
@@ -88,7 +98,7 @@
       {
         "name": "typescript",
         "version": "~5.2.2",
-        "supportedRange": ">=5.2 <5.3"
+        "supportedRange": ">=4.9.3 <5.3.0"
       },
       {
         "name": "zone.js",
diff --git a/angular/templates/generators/ng-app/index.ts b/angular/templates/generators/ng-app/index.ts
index 6abffa7c..76ab5e1d 100644
--- a/angular/templates/generators/ng-app/index.ts
+++ b/angular/templates/generators/ng-app/index.ts
@@ -1,24 +1,32 @@
 import { AngularComponentTemplateOptions } from '@bitdev/angular.dev-services.common';
+import { confirm, group, select } from '@clack/prompts';
+import { EnvContext, EnvHandler } from '@teambit/envs';
 import { ComponentContext, ComponentTemplate } from '@teambit/generator';
+import { Logger } from '@teambit/logger';
+import { isCI } from 'std-env';
 import { indexFile } from './template-files';
 import { docsFile } from './template-files/docs';
 import { ngAppFile } from './template-files/ng-app';
 import { appComponentFile } from './template-files/src/app/app.component';
 import { appComponentHtmlFile } from './template-files/src/app/app.component-html';
-import { appComponentScssFile } from './template-files/src/app/app.component-scss';
+import { appComponentStyleSheetFile } from './template-files/src/app/app.component-scss';
 import { appComponentSpecFile } from './template-files/src/app/app.component-spec';
 import { appConfigFile } from './template-files/src/app/app.config';
+import { serverConfigFile } from './template-files/src/app/app.config.server';
 import { appModuleFile } from './template-files/src/app/app.module';
 import { appRoutesFile } from './template-files/src/app/app.routes';
 import { gitKeepFile } from './template-files/src/assets/gitkeep';
 import { indexHtmlFile } from './template-files/src/index-html';
 import { mainNgAppFile } from './template-files/src/main';
+import { mainServerFile } from './template-files/src/main.server';
 import { polyfillsFile } from './template-files/src/polyfills';
+import { helloApiFile } from './template-files/src/server/api/hello';
 import { stylesFile } from './template-files/src/styles';
 import { tsconfigFile } from './template-files/tsconfig.app';
 
 export class NgAppTemplate implements ComponentTemplate {
   private constructor(
+    private logger: Logger,
     readonly angularVersion: number,
     readonly name = 'ng-app',
     readonly description = 'create an Angular application',
@@ -26,51 +34,113 @@ export class NgAppTemplate implements ComponentTemplate {
   ) {
   }
 
-  generateFiles(context: ComponentContext) {
+  async prompt(context: ComponentContext) {
+    this.logger.off();
+
+    const prompts: { [id: string]: () => Promise<any> } = {
+      styleSheet: () => select({
+        message: 'Which stylesheet format would you like to use?',
+        options: [
+          { label: 'CSS', value: 'css' },
+          { label: 'SCSS', value: 'scss', hint: 'https://sass-lang.com/documentation/syntax#scss' },
+          {
+            label: 'Sass',
+            value: 'sass',
+            hint: 'https://sass-lang.com/documentation/syntax#the-indented-syntax'
+          },
+          { label: 'Less', value: 'less', hint: 'http://lesscss.org' }
+        ]
+      }) as Promise<string>
+    };
+
+    if (this.angularVersion > 13) {
+      prompts.standalone = () => confirm({
+        message: 'Do you want to use standalone components?'
+      }) as Promise<boolean>;
+    }
+
+    if (this.angularVersion >= 16) {
+      prompts.ssr = () => confirm({
+        message: 'Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)?'
+      }) as Promise<boolean>;
+    }
+
+    const params = await group(prompts);
+
+    this.logger.on();
+
+    return params;
+  }
+
+  async generateFiles(context: ComponentContext) {
+    let params: { [id: string]: any } = {
+      styleSheet: 'scss',
+      standalone: this.angularVersion > 13,
+      ssr: this.angularVersion >= 17 // todo: check if we can use 16 here
+    };
+
+    if (!isCI) {
+      params = await this.prompt(context);
+    }
+
     const files = [
       docsFile(context),
       indexFile(context),
-      ngAppFile(context, this.angularVersion),
-      tsconfigFile(this.angularVersion),
+      ngAppFile(context, params.styleSheet, params.ssr),
+      tsconfigFile(this.angularVersion, params.ssr),
       indexHtmlFile(context),
-      mainNgAppFile(this.angularVersion),
-      stylesFile(),
+      mainNgAppFile(params.standalone),
+      stylesFile(params.styleSheet),
       appComponentHtmlFile(),
-      appComponentScssFile(),
-      appComponentSpecFile(context, this.angularVersion),
-      appComponentFile(context, this.angularVersion),
+      appComponentStyleSheetFile(params.styleSheet),
+      appComponentSpecFile(context, params.standalone),
+      appComponentFile(context, params.styleSheet, params.standalone),
       gitKeepFile(),
+      appRoutesFile()
     ];
 
+    if (params.ssr) {
+      files.push(
+        mainServerFile(params.standalone),
+        helloApiFile()
+      );
+
+      if (params.standalone) {
+        files.push(serverConfigFile());
+      }
+    }
+
     if (this.angularVersion < 15) {
       files.push(
         // starting from Angular 15, the `polyfills` option accept an array of module specifiers.
         // https://github.com/angular/angular-cli/commit/597bfea1b29cc7b25d1f466eb313cbeeb6dffc98
-        polyfillsFile(),
+        polyfillsFile()
       );
     }
 
-    if (this.angularVersion >= 17) {
-      files.push(
-        appConfigFile(),
-        appRoutesFile(),
-      );
-    } else {
-      files.push(
-        appModuleFile(),
-      );
+    if (params.standalone) {
+      files.push(appConfigFile(this.angularVersion, params.ssr));
+    }
+    if (!params.standalone) {
+      files.push(appModuleFile(params.ssr));
     }
 
     return files;
   }
 
-  static from(options: AngularComponentTemplateOptions & { angularVersion: number }) {
-    return () =>
-      new NgAppTemplate(
+  static from(options: AngularComponentTemplateOptions & {
+    angularVersion: number
+  }): EnvHandler<ComponentTemplate> {
+    return (context: EnvContext) => {
+      const name = options.name || 'ng-app-template';
+      const logger = context.createLogger(name);
+      return new NgAppTemplate(
+        logger,
         options.angularVersion,
         options.name,
         options.description,
         options.hidden
       );
+    };
   }
 }
diff --git a/angular/templates/generators/ng-app/template-files/docs.ts b/angular/templates/generators/ng-app/template-files/docs.ts
index 0adabadd..2d187f46 100644
--- a/angular/templates/generators/ng-app/template-files/docs.ts
+++ b/angular/templates/generators/ng-app/template-files/docs.ts
@@ -1,7 +1,7 @@
 import { ComponentContext, ComponentFile } from '@teambit/generator';
 
 export const docsFile = (context: ComponentContext): ComponentFile => {
-  const { name, namePascalCase: Name } = context;
+  const { name } = context;
 
   return {
     relativePath: `${name}.docs.md`,
diff --git a/angular/templates/generators/ng-app/template-files/ng-app.ts b/angular/templates/generators/ng-app/template-files/ng-app.ts
index c3b1d6e5..4445b08a 100644
--- a/angular/templates/generators/ng-app/template-files/ng-app.ts
+++ b/angular/templates/generators/ng-app/template-files/ng-app.ts
@@ -1,26 +1,26 @@
 import { ComponentContext, ComponentFile } from '@teambit/generator';
 
-export const ngAppFile = (context: ComponentContext, angularVersion: number): ComponentFile => {
+export const ngAppFile = (context: ComponentContext, styleSheet: string, ssr: boolean): ComponentFile => {
   const { name, namePascalCase: Name } = context;
   return {
     relativePath: `${name}.ng-app.ts`,
     content: `import { AngularAppOptions } from '@bitdev/angular.app-types.angular-app-type';
-import { BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+import { ${ssr ? `ApplicationOptions`: `BrowserOptions` }, DevServerOptions } from '@bitdev/angular.dev-services.common';
 
-const angularOptions: BrowserOptions & DevServerOptions = {
-  main: './src/main.ts',
-  polyfills: ${angularVersion >= 15 ? `[
-    "zone.js",
-    "zone.js/testing"
-  ]` : `'./src/polyfills.ts'`},
+const angularOptions: ${ssr ? `ApplicationOptions`: `BrowserOptions` } & DevServerOptions = {
+  ${ssr ? `browser: './src/main.ts',
+  server: './src/main.server.ts',
+  prerender: true,
+  ssr: true,` : `main: './src/main.ts',`}
   index: './src/index.html',
   tsConfig: './tsconfig.app.json',
+  inlineStyleLanguage: '${styleSheet}',
   assets: [{
     "glob": "**/*",
     "input": "src/assets/",
     "output": "/assets/"
   }],
-  styles: ['./src/styles.scss'],
+  styles: ['./src/styles.${styleSheet}'],
 };
 
 export const ${Name}Options: AngularAppOptions = {
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.component-html.ts b/angular/templates/generators/ng-app/template-files/src/app/app.component-html.ts
index f0ecbeb4..1b163777 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.component-html.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.component-html.ts
@@ -20,6 +20,8 @@ export const appComponentHtmlFile = (): ComponentFile => {
     box-sizing: border-box;
     -webkit-font-smoothing: antialiased;
     -moz-osx-font-smoothing: grayscale;
+    --electric-violet: #8815f5;
+    --vivid-pink: #ff006e;
   }
 
   h1,
@@ -47,7 +49,7 @@ export const appComponentHtmlFile = (): ComponentFile => {
     height: 60px;
     display: flex;
     align-items: center;
-    background-color: #1976d2;
+    background-color: #000;
     color: white;
     font-weight: 600;
   }
@@ -140,7 +142,7 @@ export const appComponentHtmlFile = (): ComponentFile => {
   }
 
   .card.highlight-card {
-    background-color: #1976d2;
+    background-color: #000;
     color: white;
     font-weight: 600;
     border: none;
@@ -312,7 +314,7 @@ export const appComponentHtmlFile = (): ComponentFile => {
   <img
     width="40"
     alt="Angular Logo"
-    src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
+    src="https://angular.dev/assets/content/images/press-kit/angular_icon_gradient.gif"
   />
   <span>Welcome</span>
   <div class="spacer"></div>
@@ -335,9 +337,13 @@ export const appComponentHtmlFile = (): ComponentFile => {
   <div class="card highlight-card card-small">
 
     <svg id="rocket" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
+      <linearGradient id="rocket-gradient"  x2="0" y2="1">
+        <stop offset="0%" stop-color="var(--electric-violet)" />
+        <stop offset="100%" stop-color="var(--vivid-pink)" />
+      </linearGradient>
       <title>Rocket Ship</title>
       <g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
-        <circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
+        <circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="url(#rocket-gradient) pink"/>
         <g id="Group_47" data-name="Group 47" transform="translate(165.185 720.185)">
           <path id="Path_33" data-name="Path 33" d="M3.4,42.615a3.084,3.084,0,0,0,3.553,3.553,21.419,21.419,0,0,0,12.215-6.107L9.511,30.4A21.419,21.419,0,0,0,3.4,42.615Z" transform="translate(0.371 3.363)" fill="#fff"/>
           <path id="Path_34" data-name="Path 34" d="M53.3,3.221A3.09,3.09,0,0,0,50.081,0,48.227,48.227,0,0,0,18.322,13.437c-6-1.666-14.991-1.221-18.322,7.218A33.892,33.892,0,0,1,9.439,25.1l-.333.666a3.013,3.013,0,0,0,.555,3.553L23.985,43.641a2.9,2.9,0,0,0,3.553.555l.666-.333A33.892,33.892,0,0,1,32.647,53.3c8.55-3.664,8.884-12.326,7.218-18.322A48.227,48.227,0,0,0,53.3,3.221ZM34.424,9.772a6.439,6.439,0,1,1,9.106,9.106,6.368,6.368,0,0,1-9.106,0A6.467,6.467,0,0,1,34.424,9.772Z" transform="translate(0 0.005)" fill="#fff"/>
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.component-scss.ts b/angular/templates/generators/ng-app/template-files/src/app/app.component-scss.ts
index 546258a3..565b0956 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.component-scss.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.component-scss.ts
@@ -1,8 +1,8 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const appComponentScssFile = (): ComponentFile => {
+export const appComponentStyleSheetFile = (styleSheet: string): ComponentFile => {
   return {
-    relativePath: `src/app/app.component.scss`,
+    relativePath: `src/app/app.component.${styleSheet}`,
     content: ``,
   };
 };
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.component-spec.ts b/angular/templates/generators/ng-app/template-files/src/app/app.component-spec.ts
index 3e7358e3..6a893b84 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.component-spec.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.component-spec.ts
@@ -1,6 +1,6 @@
 import { ComponentContext, ComponentFile } from '@teambit/generator';
 
-export const appComponentSpecFile = (context: ComponentContext, angularVersion: number): ComponentFile => {
+export const appComponentSpecFile = (context: ComponentContext, standalone: boolean): ComponentFile => {
   const { name } = context;
   return {
     relativePath: `src/app/app.component.spec.ts`,
@@ -10,7 +10,7 @@ import { AppComponent } from './app.component';
 describe('AppComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      ${angularVersion >= 17 ? `imports: [AppComponent]` : `declarations: [AppComponent]`},
+      ${standalone ? `imports: [AppComponent]` : `declarations: [AppComponent]`},
     }).compileComponents();
   });
 
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.component.ts b/angular/templates/generators/ng-app/template-files/src/app/app.component.ts
index de9ede36..8930f7e2 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.component.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.component.ts
@@ -1,29 +1,19 @@
 import { ComponentContext, ComponentFile } from '@teambit/generator';
 
-export const appComponentFile = (context: ComponentContext, angularVersion: number): ComponentFile => {
+export const appComponentFile = (context: ComponentContext, styleSheet: string, standalone: boolean): ComponentFile => {
   const { name } = context;
   return {
     relativePath: `src/app/app.component.ts`,
-    content: angularVersion >= 17 ? `import { Component } from '@angular/core';
-import { CommonModule } from '@angular/common';
+    content: `import { Component } from '@angular/core';${standalone ? `
+import { CommonModule } from '@angular/common';` : ''}
 import { RouterOutlet } from '@angular/router';
 
 @Component({
-  selector: 'app-root',
+  selector: 'app-root',${standalone ? `
   standalone: true,
-  imports: [CommonModule, RouterOutlet],
+  imports: [CommonModule, RouterOutlet],` : ''}
   templateUrl: './app.component.html',
-  styleUrls: ['./app.component.scss']
-})
-export class AppComponent {
-  title = '${name}';
-}
-` : `import { Component } from '@angular/core';
-
-@Component({
-  selector: 'app-root',
-  templateUrl: './app.component.html',
-  styleUrls: ['./app.component.scss']
+  styleUrls: ['./app.component.${ styleSheet }']
 })
 export class AppComponent {
   title = '${name}';
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.config.server.ts b/angular/templates/generators/ng-app/template-files/src/app/app.config.server.ts
new file mode 100644
index 00000000..c86dff49
--- /dev/null
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.config.server.ts
@@ -0,0 +1,19 @@
+import { ComponentFile } from '@teambit/generator';
+
+export const serverConfigFile = (): ComponentFile => {
+  return {
+    relativePath: `src/app/app.config.server.ts`,
+    content: `import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
+import { provideServerRendering } from '@angular/platform-server';
+import { appConfig } from './app.config';
+
+const serverConfig: ApplicationConfig = {
+  providers: [
+    provideServerRendering()
+  ]
+};
+
+export const config = mergeApplicationConfig(appConfig, serverConfig);
+`,
+  };
+};
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.config.ts b/angular/templates/generators/ng-app/template-files/src/app/app.config.ts
index 59775b28..ba4bfa05 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.config.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.config.ts
@@ -1,15 +1,16 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const appConfigFile = (): ComponentFile => {
+export const appConfigFile = (angularVersion: number, ssr: boolean): ComponentFile => {
   return {
     relativePath: `src/app/app.config.ts`,
-    content: `import { ApplicationConfig } from '@angular/core';
+    content: `import { ApplicationConfig } from '${angularVersion >= 16 ? '@angular/core' : '@angular/platform-browser'}';
 import { provideRouter } from '@angular/router';
 
-import { routes } from './app.routes';
+import { routes } from './app.routes';${ssr ? `
+import { provideClientHydration } from '@angular/platform-browser';` : ''}
 
 export const appConfig: ApplicationConfig = {
-  providers: [provideRouter(routes)]
+  providers: [provideRouter(routes)${ssr ? ', provideClientHydration()' : ''}]
 };
 `,
   };
diff --git a/angular/templates/generators/ng-app/template-files/src/app/app.module.ts b/angular/templates/generators/ng-app/template-files/src/app/app.module.ts
index 1f4e9b05..af323209 100644
--- a/angular/templates/generators/ng-app/template-files/src/app/app.module.ts
+++ b/angular/templates/generators/ng-app/template-files/src/app/app.module.ts
@@ -1,11 +1,13 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const appModuleFile = (): ComponentFile => {
+export const appModuleFile = (ssr: boolean): ComponentFile => {
   return {
     relativePath: `src/app/app.module.ts`,
     content: `import { NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
-
+import { RouterModule } from '@angular/router';${ssr ? `
+import { provideClientHydration } from '@angular/platform-browser';` : ''}
+import { routes } from './app.routes';
 import { AppComponent } from './app.component';
 
 @NgModule({
@@ -13,9 +15,10 @@ import { AppComponent } from './app.component';
     AppComponent
   ],
   imports: [
-    BrowserModule
+    BrowserModule,
+    RouterModule.forRoot(routes)
   ],
-  providers: [],
+  providers: [${ssr ? `provideClientHydration()` : ``}],
   bootstrap: [AppComponent]
 })
 export class AppModule { }
diff --git a/angular/templates/generators/ng-app/template-files/src/index-html.ts b/angular/templates/generators/ng-app/template-files/src/index-html.ts
index 5522d02f..c151562b 100644
--- a/angular/templates/generators/ng-app/template-files/src/index-html.ts
+++ b/angular/templates/generators/ng-app/template-files/src/index-html.ts
@@ -11,7 +11,7 @@ export const indexHtmlFile = (context: ComponentContext): ComponentFile => {
   <title>${Name}</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
-  <link rel="icon" type="image/x-icon" href="data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAeCAYAAAA/xX6fAAAACXBIWXMAAAsSAAALEgHS3X78AAADZklEQVRIiZVXS0wTURS98+nMlNIWdUeRlgllow5ujC4MNnFjYgSCbBQ/hbjRRGCpRiPGDUt140YNMVFjjAoYjKIhhYif+Am48UMEplCkfEI/JIKa1NyxM7wOnc7MSSZ9895978y9c++ZWyqTyYBViEGpHgCUS56OeXiOG2dZ9kFqceqs1TNMCcWgtB0AwtnLq85PRKc0G5qmMwLPjzpYtjOxEL1vm1AMSgGCxJ9vI0lIgmGYvwLPD7Msez4xL78yJBSDUglBUl3oKXft3AE/43MQGVp3Xg4cDvYXz3HPWYZtX5qXZYWwonJbOPte6gruJnDvzi2Yjc9BfWOT1S0g8Pysw8H2IaH1rAGAMl8pDEWeKeOKqmqYlKN2tgNtyxoA2lpPaeOOC2fsblcIB60aezxuONhQq93X1+6HkhJvwT0kOI5L2PKwOXwk597r9UD76ZN2jlA8HLFq3BI+um4ufOywZTKWYSaRMGHFuLGhDtzuYmUci82AnK1Df/lmy6QURSUte9jWuha6q9euQ8flTu3ealhpmn5jyUMsdJ+vVBmn08vQ/3IAunv7IJlMKXPV0lYI1ew2JaQoiCPhpJkh6V3/iwFIpdKQSCQVUhXtreZeUhT9QZE2MSgZFj9Z6Iia0D6Yjs0oWhrwl8PE91FtzUwIMqtLlFoWSWPv1godk6WszKeEGEOIhDIh4oWEAL8ooIq3GJQiALBHb4SFPvJx2PAQPfCdBqokJdx6YNGvpuMbVA/zJo6+0M1QSAhoilohPewAgIt6o9FPr7Xa+/L1m5IsKlZWVrUxyhtmKgJDHAhK6whdRUWDy0uxEGv00GShIw41teQQkh9gMnlUIei6fTe/p9nfiH6BLIWHj3pzyPTAzOx58lSbzRdWhqG7wejzRBb6f8IeQzIVpEeFhEAlzJE3MlmwFN6+e29KiCJAloheCGiKfgy6nmbErJchYdRE5QP2Nr+X54tID2F87DO2g80AIFs+yQTYwbmLXTdVMtC/w/Gxz10AgMSXCqmPGVBVsAzcLldlanH6BGlu2Ahn28YrAHA837pRSJ2C8IPnuL1qW6iHlc4bm+IuvfTpCVG6nIJwIF/zS8LyfwsxKIWyHiuJpRJiQjgF4VxyYQrXzIGEdi5snP3ilijj3PTHvdF3w9b+TAb+Afl3jDi6Q4zhAAAAAElFTkSuQmCC">
+  <link rel="icon" type="image/x-icon" href="https://angular.dev/assets/icons/favicon.ico">
 </head>
 <body>
   <app-root></app-root>
diff --git a/angular/templates/generators/ng-app/template-files/src/main.server.ts b/angular/templates/generators/ng-app/template-files/src/main.server.ts
new file mode 100644
index 00000000..14889084
--- /dev/null
+++ b/angular/templates/generators/ng-app/template-files/src/main.server.ts
@@ -0,0 +1,29 @@
+import { ComponentFile } from '@teambit/generator';
+
+export const mainServerFile = (standalone: boolean): ComponentFile => {
+  return {
+    relativePath: `src/main.server.ts`,
+    content: `import 'zone.js/node';
+${standalone ? `import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+import { config } from './app/app.config.server';
+
+export default function bootstrap() {
+  return bootstrapApplication(AppComponent, config);
+}` : `import { provideServerRendering } from '@angular/platform-server';
+import { NgModule } from '@angular/core';
+import { ServerModule } from '@angular/platform-server';
+import { AppModule } from './app/app.module';
+import { AppComponent } from './app/app.component';
+
+@NgModule({
+  imports: [
+    AppModule,
+    ServerModule,
+  ],
+  providers: [provideServerRendering()],
+  bootstrap: [AppComponent],
+})
+export default class AppServerModule {}`}`,
+  };
+};
diff --git a/angular/templates/generators/ng-app/template-files/src/main.ts b/angular/templates/generators/ng-app/template-files/src/main.ts
index c54d63f7..b63f6c39 100644
--- a/angular/templates/generators/ng-app/template-files/src/main.ts
+++ b/angular/templates/generators/ng-app/template-files/src/main.ts
@@ -1,9 +1,10 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const mainNgAppFile = (angularVersion: number): ComponentFile => {
+export const mainNgAppFile = (standalone: boolean): ComponentFile => {
   return {
     relativePath: `src/main.ts`,
-    content: angularVersion >= 17 ? `import { bootstrapApplication } from '@angular/platform-browser';
+    content: `import 'zone.js';
+${standalone ? `import { bootstrapApplication } from '@angular/platform-browser';
 import { appConfig } from './app/app.config';
 import { AppComponent } from './app/app.component';
 
@@ -14,6 +15,6 @@ import { AppModule } from './app/app.module';
 
 platformBrowserDynamic().bootstrapModule(AppModule)
   .catch(err => console.error(err));
-`,
+`}`,
   };
 };
diff --git a/angular/templates/generators/ng-app/template-files/src/server/api/hello.ts b/angular/templates/generators/ng-app/template-files/src/server/api/hello.ts
new file mode 100644
index 00000000..efd7282f
--- /dev/null
+++ b/angular/templates/generators/ng-app/template-files/src/server/api/hello.ts
@@ -0,0 +1,10 @@
+import { ComponentFile } from '@teambit/generator';
+
+export const helloApiFile = (): ComponentFile => {
+  return {
+    relativePath: `src/server/api/hello.ts`,
+    content: `import { defineEventHandler } from 'h3';
+
+export default defineEventHandler(() => ({ message: 'Hello World' }));`,
+  };
+};
diff --git a/angular/templates/generators/ng-app/template-files/src/styles.ts b/angular/templates/generators/ng-app/template-files/src/styles.ts
index 7119a19a..39cf45a3 100644
--- a/angular/templates/generators/ng-app/template-files/src/styles.ts
+++ b/angular/templates/generators/ng-app/template-files/src/styles.ts
@@ -1,8 +1,8 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const stylesFile = (): ComponentFile => {
+export const stylesFile = (styleSheet: string): ComponentFile => {
   return {
-    relativePath: `src/styles.scss`,
+    relativePath: `src/styles.${styleSheet}`,
     content: `/* You can add global styles to this file, and also import other style files */
 `,
   };
diff --git a/angular/templates/generators/ng-app/template-files/tsconfig.app.ts b/angular/templates/generators/ng-app/template-files/tsconfig.app.ts
index 3ca5d415..00e0e8cb 100644
--- a/angular/templates/generators/ng-app/template-files/tsconfig.app.ts
+++ b/angular/templates/generators/ng-app/template-files/tsconfig.app.ts
@@ -1,6 +1,6 @@
 import { ComponentFile } from '@teambit/generator';
 
-export const tsconfigFile = (angularVersion: number): ComponentFile => {
+export const tsconfigFile = (angularVersion: number, ssr: boolean): ComponentFile => {
   return {
     relativePath: 'tsconfig.app.json',
     content: `/* To learn more about this file see: https://angular.io/config/tsconfig. */
@@ -23,7 +23,8 @@ export const tsconfigFile = (angularVersion: number): ComponentFile => {
     "allowJs": true,
     ${angularVersion >= 17 ? `"target": "ES2022",
     "module": "ES2022"` : `"target": "es2017",
-    "module": "es2020"`},
+    "module": "es2020"`},${angularVersion >= 15 ? `
+    "useDefineForClassFields": false,` : ``}
     "preserveSymlinks": false,
     "lib": [
       "${angularVersion >= 17 ? `ES2022` : `ES2018`}",
@@ -37,7 +38,8 @@ export const tsconfigFile = (angularVersion: number): ComponentFile => {
     "strictInputAccessModifiers": true
   },
   "files": [
-    "./src/main.ts"${angularVersion >= 15 ? `` : `,
+    "./src/main.ts",${ssr ? `
+    "./src/main.server.ts",` : ``}${angularVersion >= 15 ? `` : `
     "./src/polyfills.ts"`}
   ],
   "include": [
diff --git a/angular/templates/generators/ng-env/files/env.ts b/angular/templates/generators/ng-env/files/env.ts
index 2e4be7c9..88e59f79 100644
--- a/angular/templates/generators/ng-env/files/env.ts
+++ b/angular/templates/generators/ng-env/files/env.ts
@@ -2,7 +2,7 @@ import { ComponentContext } from '@teambit/generator';
 
 export function envFile({ namePascalCase: Name, name }: ComponentContext, envName: string, angularVersion: number, envPkgName: string) {
   // language=TypeScript
-  return `import { BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+  return `import { ApplicationOptions, BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
 import { AngularPreview, BundlerProvider, DevServerProvider } from '@bitdev/angular.dev-services.preview.preview';
 import { ${envName} } from '${envPkgName}';
 import { NgAppTemplate, NgEnvTemplate, NgModuleTemplate, NgStandaloneTemplate } from '@bitdev/angular.templates.generators';
@@ -88,7 +88,7 @@ export class ${Name} extends ${envName} {
     const devServerProvider: DevServerProvider = (
       devServerContext: DevServerContext,
       transformers: WebpackConfigTransformer[] = [],
-      angularOptions: Partial<BrowserOptions & DevServerOptions> = {},
+      angularOptions: Partial<(BrowserOptions | ApplicationOptions) & DevServerOptions> = {},
       webpackOptions: any = {},
       sourceRoot?: string
     ) => this.getDevServer(devServerContext, ngEnvOptions, transformers, angularOptions, webpackOptions, sourceRoot);
diff --git a/integration/demo-app/demo-app.ng-app.ts b/integration/demo-app/demo-app.ng-app.ts
index 43a61f43..5a56a413 100644
--- a/integration/demo-app/demo-app.ng-app.ts
+++ b/integration/demo-app/demo-app.ng-app.ts
@@ -1,13 +1,16 @@
 import type { AngularAppOptions } from '@bitdev/angular.app-types.angular-app-type';
-import type { BrowserOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
+import type { ApplicationOptions, DevServerOptions } from '@bitdev/angular.dev-services.common';
 
-const angularOptions: BrowserOptions & DevServerOptions = {
-  main: './src/main.ts',
-  polyfills: './src/polyfills.ts',
+const angularOptions: ApplicationOptions & DevServerOptions = {
+  browser: './src/main.ts',
+  server: './src/main.server.ts',
   index: './src/index.html',
   tsConfig: 'tsconfig.app.json',
   assets: ['./src/favicon.ico', './src/assets'],
-  styles: ['./src/styles.scss']
+  styles: ['./src/styles.scss'],
+  inlineStyleLanguage: "scss",
+  prerender: true,
+  ssr: true
 };
 
 export const DemoAppOptions: AngularAppOptions = {
@@ -29,8 +32,7 @@ export const DemoAppOptions: AngularAppOptions = {
   /**
    * Angular options for `bit run`
    */
-  angularServeOptions: angularOptions,
-
+  angularServeOptions: angularOptions
 };
 
 export default DemoAppOptions;
diff --git a/integration/demo-app/src/app/app.component.html b/integration/demo-app/src/app/app.component.html
index 2a42646f..e4916cf6 100644
--- a/integration/demo-app/src/app/app.component.html
+++ b/integration/demo-app/src/app/app.component.html
@@ -15,6 +15,8 @@
     box-sizing: border-box;
     -webkit-font-smoothing: antialiased;
     -moz-osx-font-smoothing: grayscale;
+    --electric-violet: #8815f5;
+    --vivid-pink: #ff006e;
   }
 
   h1,
@@ -42,7 +44,7 @@
     height: 60px;
     display: flex;
     align-items: center;
-    background-color: #1976d2;
+    background-color: #000;
     color: white;
     font-weight: 600;
   }
@@ -135,7 +137,7 @@
   }
 
   .card.highlight-card {
-    background-color: #1976d2;
+    background-color: #000;
     color: white;
     font-weight: 600;
     border: none;
@@ -307,7 +309,7 @@
   <img
     width="40"
     alt="Angular Logo"
-    src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
+    src="https://angular.dev/assets/content/images/press-kit/angular_icon_gradient.gif"
   />
   <span>Welcome</span>
   <div class="spacer"></div>
@@ -331,9 +333,13 @@
   <div class="card highlight-card card-small">
 
     <svg id="rocket" xmlns="http://www.w3.org/2000/svg" width="101.678" height="101.678" viewBox="0 0 101.678 101.678">
+      <linearGradient id="rocket-gradient"  x2="0" y2="1">
+        <stop offset="0%" stop-color="var(--electric-violet)" />
+        <stop offset="100%" stop-color="var(--vivid-pink)" />
+      </linearGradient>
       <title>Rocket Ship</title>
       <g id="Group_83" data-name="Group 83" transform="translate(-141 -696)">
-        <circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="#dd0031"/>
+        <circle id="Ellipse_8" data-name="Ellipse 8" cx="50.839" cy="50.839" r="50.839" transform="translate(141 696)" fill="url(#rocket-gradient) pink"/>
         <g id="Group_47" data-name="Group 47" transform="translate(165.185 720.185)">
           <path id="Path_33" data-name="Path 33" d="M3.4,42.615a3.084,3.084,0,0,0,3.553,3.553,21.419,21.419,0,0,0,12.215-6.107L9.511,30.4A21.419,21.419,0,0,0,3.4,42.615Z" transform="translate(0.371 3.363)" fill="#fff"/>
           <path id="Path_34" data-name="Path 34" d="M53.3,3.221A3.09,3.09,0,0,0,50.081,0,48.227,48.227,0,0,0,18.322,13.437c-6-1.666-14.991-1.221-18.322,7.218A33.892,33.892,0,0,1,9.439,25.1l-.333.666a3.013,3.013,0,0,0,.555,3.553L23.985,43.641a2.9,2.9,0,0,0,3.553.555l.666-.333A33.892,33.892,0,0,1,32.647,53.3c8.55-3.664,8.884-12.326,7.218-18.322A48.227,48.227,0,0,0,53.3,3.221ZM34.424,9.772a6.439,6.439,0,1,1,9.106,9.106,6.368,6.368,0,0,1-9.106,0A6.467,6.467,0,0,1,34.424,9.772Z" transform="translate(0 0.005)" fill="#fff"/>
@@ -479,3 +485,6 @@ <h2>Next Steps</h2>
 <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
 <!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * -->
 <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
+
+
+<router-outlet></router-outlet>
diff --git a/integration/demo-app/src/app/app.component.spec.ts b/integration/demo-app/src/app/app.component.spec.ts
index 88bc80b3..051ec289 100644
--- a/integration/demo-app/src/app/app.component.spec.ts
+++ b/integration/demo-app/src/app/app.component.spec.ts
@@ -4,7 +4,7 @@ import { AppComponent } from './app.component';
 describe('AppComponent', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      declarations: [AppComponent]
+      imports: [AppComponent],
     }).compileComponents();
   });
 
diff --git a/integration/demo-app/src/app/app.component.ts b/integration/demo-app/src/app/app.component.ts
index 08ea3d9e..e5bb61af 100644
--- a/integration/demo-app/src/app/app.component.ts
+++ b/integration/demo-app/src/app/app.component.ts
@@ -1,9 +1,13 @@
 import { Component } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterOutlet } from '@angular/router';
 
 @Component({
   selector: 'app-root',
+  standalone: true,
+  imports: [CommonModule, RouterOutlet],
   templateUrl: './app.component.html',
-  styleUrls: ['./app.component.scss']
+  styleUrls: ['./app.component.scss'],
 })
 export class AppComponent {
   title = 'demo-app';
diff --git a/integration/demo-app/src/app/app.config.server.ts b/integration/demo-app/src/app/app.config.server.ts
new file mode 100644
index 00000000..b4d57c94
--- /dev/null
+++ b/integration/demo-app/src/app/app.config.server.ts
@@ -0,0 +1,11 @@
+import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
+import { provideServerRendering } from '@angular/platform-server';
+import { appConfig } from './app.config';
+
+const serverConfig: ApplicationConfig = {
+  providers: [
+    provideServerRendering()
+  ]
+};
+
+export const config = mergeApplicationConfig(appConfig, serverConfig);
diff --git a/integration/demo-app/src/app/app.config.ts b/integration/demo-app/src/app/app.config.ts
new file mode 100644
index 00000000..e5a3cf10
--- /dev/null
+++ b/integration/demo-app/src/app/app.config.ts
@@ -0,0 +1,9 @@
+import { ApplicationConfig } from '@angular/core';
+import { provideRouter } from '@angular/router';
+
+import { routes } from './app.routes';
+import { provideClientHydration } from '@angular/platform-browser';
+
+export const appConfig: ApplicationConfig = {
+  providers: [provideRouter(routes), provideClientHydration()]
+};
diff --git a/integration/demo-app/src/app/app.routes.ts b/integration/demo-app/src/app/app.routes.ts
new file mode 100644
index 00000000..dc39edb5
--- /dev/null
+++ b/integration/demo-app/src/app/app.routes.ts
@@ -0,0 +1,3 @@
+import { Routes } from '@angular/router';
+
+export const routes: Routes = [];
diff --git a/integration/demo-app/src/assets/favicon.ico b/integration/demo-app/src/assets/favicon.ico
index b20b53e6e04640905d93b95130e5a7c5be0aeb95..57614f9c967596fad0a3989bec2b1deff33034f6 100644
GIT binary patch
literal 15086
zcmd^G33O9Omi+`8$@{|M-I6TH3wzF-p5CV8o}7f~KxR60LK+ApEFB<$bcciv%@SmA
zV{n>g85YMFFeU*Uvl=i4v)C*qgnb;$GQ=3XTe9{Y%c`mO<tM&Bl57ox;hfPqkLUVT
zzv|vsua^I+V3=M^Z)U^@hH5cWC})^|W*9~+?o5X>%su)noNCCQ*@t1WXn|B(hQ7i~
zrUK8|pUkD6#lNo!bt$6)jR!&C?`P5G(`e((P($RaLeq+o0Vd~f11;qB05kdbAOm?r
zXv~GYr_sibQO9NGTCdT;+G(!{4Xs@4fPak8#L8PjgJwcs-Mm#nR_Z0s&u?nDX5^~@
z+A6?}g0|=4e_LoE69pPFO`yCD@BCjgKpzMH0O4Xs{Ahc?K3<?BQv_-<UC>HC5;l=f
zg>}alhBXX&);z$E-wai+9TTRtBX-bWYY@cl$@YN#gMd~tM_5lj6W%8ah4;uZ;jP@Q
zVbuel1rPA?2@x9Y+u?e`l{Z4ngfG5q5BLH5QsEu4GVpt{KIp1?U)=3+KQ;%7ec8l*
zdV=zZgN5>O3G(3L2fqj3;oBbZZw$Ij@`Juz@?+yy#OPw)>#wsTewVgTK9BGt5Ab<U
ze$Tf(VBZpa!SSqoXlj(c_>Z&?K&B3GVF&yu?@(Xj3fR3n+ZP0%+wo)D9_xp>Z$`A4
zfV>}NWjO#3lqumR0`gvnffd9Ka}JJMuHS&|55-*mCD#8e^anA<+sFZVaJe7{=p*oX
zE_Uv?1>e~ga=seYzh{9P+n5<+7&9}<n&VL-3~Og{<S)TZE4h*#P`v^L#_Z0pidV7T
z|Ib<xXZ+do&R-q5D%lf8SW`2_x^ho>&(kwqSaz;1aD|YM3HBiy<))4~QJSIryyqp|
z8nGc(8<b%O&Bp|DVqS`wWF{E*^YfmUv_Uw3r7mDGG4`GR*q(1;f_^;UhdzKc_IbgK
zICR2{aDBicoldxr=tGynCuo=7-^G>>3(_nEI4n)n7j(&d4idW1tVLjZ7QbNLXg;LB
ziHsS5pXHEjGJZb59K<i<Ee&OtiLJ`)M3V_+b)4D=vLUwF0FoC|YuFKcTMx1?`byI+
z(a~UU_3@v>cvS~wv;uZR-+4qEq<Dv4CQD>ow`;JCfB*+b^UL^3!?;-^F%yt=VjU|v
z39SSqKcRu_NVvz!zJzL0CceJaS6%!(eMshPv_0U5G`~!a#I$qI5Ic(>IONej@aH=f
z)($TAT#1I{iCS4f{D2+ApS=$3E7}5=+y(rA9mM#;Cky%b*Gi0KfFA`ofKTzu`AV-9
znW|y@19rrZ*!N2AvDi<_ZeR3O2R{#dh1#3-d%$k${Rx42h+i&GZo5!C^dSL34*AKp
z27mTd>k>?V&X;Nl%GZ(>0s`1UN~Hfyj>KPjtnc|)xM@{H_B9rNr~LuH`Gr5_am&Ep
zTjZA8hljNj5H1Ipm-uD9rC}U{-vR!eay5&6x6FkfupdpT*84MVwGpdd(}ib)zZ3Ky
z7C$p<Hy;Do`sgqRiyt`v4|vWm>njc82(W_y_F{PhYj?o!@3__UUvpX)v69aBSzYj3
zdi}YQkKs^SyXyFG2LTRz9{(w}y~!`{EuAaUr6G1M{*%c+kP1olW9z23dSH!G4_HSK
zzae-DF$OGR{ofP*!$a(r^5Go>I3SObVI6FLY)N@o<*gl0&kLo-OT{Tl*7nCz>Iq=?
zcigIDHtj|H;6sR?or8Wd_a4996GI*CXGU}o;D9`^FM!AT1pBY~?|4h^61BY#_yIfO
zKO?E0<gGmaIqZ?!V)C4TU)ygD!7%{#2Z4PA_Z^sH&W~^s5a8g62h300cYOT~^&L-X
zs{`!igBqM?Qtqn#Sxdn7fL{~!Wf%O|2f%?lFT#H9GR1z8V(0SU_6798%0zpQ{r8}>
zJ{Pc`9rVEI&$xxXu`<5E)&+m(7zX^v0rqofLs&bnQT(1baQkAr^kEsk)15vlzAZ-l
z@OO9RF<+IiJ*O@HE256gCt!bF=NM*vh|WVWmjVawcNoksRTMvR03H{p@cjwKh(CL4
z7_<J2TUZ-fC3|#k{4sefes&DdKHzfT?xA7by!j#_$N_mE2QCko-_cgxX^3a~Gj3bO
zh1n|c9@3V$%VmFxUpsIkI|le1U~R+pH;ZhUcPM`3fIK|;(}}_D7Jv5E*hY66_Q+s+
z#P99{^dX#!I{SgUhb|CXHv)d-aD(~|p96PnL;3FT_?zD%*}XuSbdV?|`-w_aMBMmk
zAF%Tf?FSeO*bj6Zxc5<ek}UfWKXSmnKwrYX0H1<B@Mk{kjtk6%P4be4R_PHJevS{Z
z<Jc1i`aOpA!o0%8j~uxDfIOfdKn_W?8TkH_>PB(dM=kO)!s4fW!1p0f93YN@?ZSG`
z$B!JaAJCtW$B97}HNO9(x-t30&E}Mo1UPi@Av%uHj~?T|!4JLwV;KCx8xO#b9IlUW
zI6+{a@Wj|<2Y=U;a@vXbxqZNngH8^}LleE_4*0&O7#3iGxfJ%Id>+sb;7{L=aIic8
z|EW|{{S)J-wr@;3PmlxRXU8!e2gm_%s|ReH!reFcY8%$Hl4M5>;6^UDUUae?kOy#h
zk~6Ee_@ZAn48Bab__^bN<q%(Zo;%n3!t5yz_MM01_UnKdcmN0F0eu1cG*9pK<QcVj
zCE`a8h+jo<1HYcs(~~mrT~Z>mQ~+k=02<Q%#1pWs`lOPf^+T!%;71PNLrT%U!`!_M
zmVa6r&e&kR0N(-pH(zWg=abv~iYWk=#*}l%06$1$+68m7_~<rIaoMMZn_myiS+E9N
z9c(rN2Y<c|)w1&Vx}i7Q>jz)e0d9Z3>G?RGG!65?d1>9}7iG17?P*=GUV-#<F7Z__
zAx;G$3`2-b<kGq@m#*mT(vU~R!7%BdZ44s<O~2s6xM_Tj<xo2rMgis6-y^Msw3T5{
zH$%FaVNln1rq2?J<6DL~?bi1NWI4lB5UMjlQ@p)7TA>SbLRw)Hu{zx*azHxWk<Mz7
zBi#mR)L~AA4$`Ovgxsg;4Aj&LY?|r{c;1U@deR6wgX#*<0*0}Hl|&5V1g)SvGZfBV
z!27<!DFAItcd&MIraQRyfO}eED!-xPzNh8>GNTWl@HeWjA?39Ia|sCi{e;!^`1Oec
zb>Z|b65OM*;eC=ZLSy?_fg$&^2xI>qSLA2G*$nA3GEnp3$N-)46`|36m*sc#4%C|h
zBN<2U;7k>&G_wL4=Ve5z`ubVD&*Hxi)r@{4RCDw7U_D`lbC(9&pG5C*z#W>8>HU)h
z!h3g?2UL&sS!oY5$3?VlA0Me9W5e~V;2jds*fz^updz#AJ%G8w2V}AEE?E^=MK%Xt
z__Bx1cr7+DQmuHmzn*|hh%~eEc9@m05@clWfpEFcr+06%0&dZJH&@8^&@*$qR@}o3
z@Tuuh2FsLz^zH+dN&T&?0G3I?MpmYJ;GP$J!Ez<EAfkuO_$)Rv+PDYrG)x<4BOp`h
zJq(cPAzCs!NJ-`dHj*yfLn^oUtkjRp8S#4g%oyu5l=laiCeIjXeRo!v{vD9N4p5I@
z98&uSkbeYJjm-`IZftS%xyQ~@eKol<O7B;BUv+ht$L|-IQxpmM{O;a+TKU@GrHk8w
zzHpzF&yO{vu9KTAfa7Vk;jJEMR~wk2GzTtlp9L?7)Bfw`R5Qtl*RJvQ-qU)n30^u|
zAMiOntNttv>jeM#YLJ!W$}MVNb0^HfOA>5Fe~UNn%Zk(PT@~9}1d<z7w`*I>t)1UQ
zU*B5K?Dl#G74qmg|2>^>0WtLX#Jz{lO4NT`NYB*(L#D|5IpXr9v&7a@YsGp3vLR7L
zHYGHZg7{ie6n~2p$6Yz>=^cEg7tEgk-1YRl%-s7^cbqFb(U7&Dp78+&ut5!Tn(hER
z|Gp4Ed@CnOPeAe|N>U(dB;SZ?NU^AzoD^UAH_vamp6Ws}{|mSq`^+VP1<S4$8S@Se
zdq@Do?xA+FBFXjv=6TY2GV_CcsfKO8P|`pSB>g~2B{%N-!mWz<`)G)<vVBk6H#4){
z=Vu$l=6$8~d<`)`{hr#zXE}+Q>>V-<`9`L4?3dM%Qh6<@kba+m`JS{Ya@9Fq*m6$$
zA1%Ogc~VRH33|S9l%CNb4zM%k^EIpqY}@h{w(aBcJ9c05oiZx#SK9t->5lSI`=&l~
z+-Ic)a{FbBhXV$Xt!WRd`R#Jk-$+_Z52rS>?Vpt2IK<84|E-SBEoIw>cs=a{BlQ7O
z-?{Fy_M&84&9|KM5wt~)*!~i~E=(6m8(uCO)I=)M?)&sRbzH$9Rovzd?ZEY}GqX+~
zFbEbLz`BZ49=2Yh-|<`waK-_4!7`ro@zlC|r&I4fc4oyb+m=|c8)8%tZ-z5FwhzDt
zL5kB@u53`d@%nHl0Sp)Dw`(QU&>vujEn?GPEXUW!Wi<+4e%BORl&BIH+SwRcbS}X@
z01Pk|vA%OdJKAs17zSXtO55k!;%m9>1eW9LnyAX4uj7@${O6cfii`49qTNItzny5J
zH&Gj`e}o}?xjQ}r?LrI%FjUd@xflT3|7LA|ka%Q3i}a8gVm<D-KiB{<ME*mIIJvPX
z_?wI2B8`LWm6;zq*T#3f=@x16x)y0E8#iX#r#5i)1K5F{J<#z8^A*_d?BI4g#=_WG
z(g+s@><`HIWoJGH=$EGClX^C0lysQJ>UO(q&;`T#8txuoQ_{l^kEV9CAdXuU1Ghg8
zN_6hHFuy&1x<z(mSz}ryX-+vs&<1V{v0JO#2INfkHdp6~?c+=2jv8nmG2EbI;k%(W
z3#`BVw)knNw=uO+>24q5-(Z7;!poYdt*`UTdrQOIQ!2O7_+AHV2hgXaEz7)>$LEdG
z<8vE^T<d5Y^c`tRKI2e{51fJd7xVqqF#b=-4dqqC+dHlfHtM^3zdr491GL{FId%-@
zzV6ERH2;j~e#`|~>w$|YwZHZDPM!SNOAWG$?J)MdmEk{U!!$M#fp7<eLLj6-0}zjd
zxPG-%QE9&hq6;&EEVqg3K{9Qkvzd<c(@PxbOO`klOER2_UKxZ64OOs`?&y_4<-W)!
zu!(5=B+RBDtM!Cvtpwr}u;~?3amOjT^)gzx^Y@#+ZK)%L=92#qnvVRTuhG4y#C&gh
zOh`k&Q6cJ8uLT)xqv-#~qA>*Wo}jJ$Q(=8>R`Ats?e|VU?Zt7Cdh%AdnfyN3MBWw{
z$OnREvPf7%z6`#2##_7id|H%Y{vV^vWXb?5d5?a_y&t3@p9t$ncHj-NBdo&X{wrfJ
zamN)VMYROYh_SvjJ=Xd!Ga?PY_$;*L=SxFte!4O6%0HEh%iZ4=gvns7IWIyJHa|hT
z2;1+e)`TvbNb3-0z&DD_)Jomsg-7p_Uh`wjGnU1urmv1_oVqRg#=C?e?!7DgtqojU
zWoAB($&53;TsXu^@2;8M`#z{=rPy?JqgYM0CDf4v@z=ZD|ItJ&8%_7A#K?S{wjxgd
z?xA6JdJojrWpB7fr2p_MSsU4(R7=XGS0+Eg#xR=j>`H@R9<ea9ez7LeH1EXlc5;O7
ztyW0w<FMRxhWuo2a;v&b{)6_e><EpxxqhnnP3hXmmGoW-y_ed1?&u9-%Np39lvDXS
zwf#1h1ARzZx2-}}-Q{~*8MpP6hORNjkfroq+=9v5#P(g+JNFl`x5yD$U&cDhl4|7V
zQZBh;Xw6B5KUF5~r1wPVo`qsCge>{XjwBm<mI-HNm*^V3KiPH_-{<RAX>qAiOxOL`
zt?XK-iTEOWV}f<c$uy@9)|c<;`&Ve3zDTSb!GBjJDNSifJ=LyEDrVO#x^Jk`^;`W4
zmdh78CX~tTHPw_uMY8rRK1basFF)9ndd}G@+ILMGyZH@#&esP-no*U>>Pz3H-s*>W
z4~8C&Xq25UQ^xH6H9kY_RM1$ch+%YLF72AA7^b{~VNTG}Tj#qZltz5Q=qxR`&oIlW
Nr__JTFzvMr^FKp4S3v*(

literal 959
zcmV;w13>)BkWNPp3K|Ux4GKv}L{cCiARHhdARY(?ARr(=#=hU6ARq~FNLh0rAPW*8
zAPW)!)17|rzrF9jy=F;7K~zY|l~+ql6Hyf2v+9hL(w22c(Uu8i!;Wsut_(JDV`2ou
ztQ0@RxYC4R%7!DxjZ1aphK(^%W6X*e%%UO1h~S{O3E8nj1jmrYyh1-D!kX2b(X-r+
z-j2<QCVlgsy|2u@bMKm)D%6Qp$$`n9Ak~ZBj(K>_n`c??zrF9jz3Q!%GfWA^pwyip
z!<oyg&yPgMv>V!{GXl?#I#|}T(U9J++>i`P0mFpgpsyoINW-DnzXH#X)2w?wF)!b;
zBoxGw2|-d_=&HBwoPj^&vyd5DcU}%04)4Fc@4vm!na8bP+LvX;u*0%jIP;#WiteYd
z&aK#u(1Cqp)RiqD@Vu;p!nPs8wakGsUnvYl-l^k?s%qGj#J1LhZOfV<+nP^l<Bp4G
z@4vkV&6;~WZaCSH%$?Ym?uU{RZ+#><&x_fz(7Ajh=%1_azrF9jz0|hPkUSjHs@#%3
z+paEr?6IXX*P$lSuwlix(V-6Au3}{z%#9q*gMaa+i=-4qB`tf|mfDuutJkhW$fZv1
zpQ>1C+rDGUgDiC4uT&YxlgyCszrF9jy?gVZnT#oO){<5T)~q%q#Hh%l;iQ=%>Yl&L
zfk?)Z(TF4!QWfvNy;2nKzrF9jy)h^m7C%|&h?>y8*pAJpS{m?|gM{zDz3;!hOb9Z}
zi`AMINn_TE9n+=FjK_o+L&$_OA>xIEAm6AB3fGv_q9D<SZ^VT@^0An(5IyjnhN>hb
z-MV1Wug9YsR1fo}j=s^2P)G=9%bFoQ?4W?my2O!B&$ZjT^0k|iEGkx3R@Je}n`SBk
zLmUW7>xrF3MZ}9s(U5EJzrF9jy(11a)}#>9pI|b1R3YfQy*J;d+Mmh3Y{iGrx^v02
zOz*$FRNRdhR>q;+f$6k_7V^J>o<lMf#fQa&KqbtPH!@k!l-|C3Z%W9bK-P#}2x!Z`
z4BDP%#H`n$Vbz4?gtj){m*<R#4`F=lv$n*IARt>l$%NT~*^6B_RWi`O#Ie$kT_8l)
ziph@|P*u>3+^$z;YH{*}sjk?FXWWJ>AaFe2x=~2og6*G<@4vm?s$0m1){Yz8qAuRF
z>57rsoWrmnU-OHCvVRLPD8;fKE6Jr2VnR3t;+?W#4GP$dM0PH0-M!+LsN|ir$Gy_G
h#Fp>Bz3;!h0r9ttxZ8uxp&%e2AW20|M9+d?4GJ~91WW(`

diff --git a/integration/demo-app/src/index.html b/integration/demo-app/src/index.html
index 3dc7b647..058b5ded 100644
--- a/integration/demo-app/src/index.html
+++ b/integration/demo-app/src/index.html
@@ -5,7 +5,7 @@
   <title>DemoApp</title>
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
-  <link rel="icon" type="image/x-icon" href="assets/favicon.ico">
+  <link rel="icon" type="image/x-icon" href="https://angular.dev/assets/icons/favicon.ico">
 </head>
 <body>
   <app-root></app-root>
diff --git a/integration/demo-app/src/main.server.ts b/integration/demo-app/src/main.server.ts
new file mode 100644
index 00000000..25ad97a0
--- /dev/null
+++ b/integration/demo-app/src/main.server.ts
@@ -0,0 +1,6 @@
+import 'zone.js/node';
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+import { config } from './app/app.config.server';
+
+export default () => bootstrapApplication(AppComponent, config);
diff --git a/integration/demo-app/src/main.ts b/integration/demo-app/src/main.ts
index c7b673cf..272abdb0 100644
--- a/integration/demo-app/src/main.ts
+++ b/integration/demo-app/src/main.ts
@@ -1,12 +1,20 @@
-import { enableProdMode } from '@angular/core';
-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+// import { enableProdMode } from '@angular/core';
+// import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+//
+// import { AppModule } from './app/app.module';
+// import { environment } from './environments/environment';
+//
+// if (environment.production) {
+//   enableProdMode();
+// }
+//
+// platformBrowserDynamic().bootstrapModule(AppModule)
+//   .catch(err => console.error(err));
 
-import { AppModule } from './app/app.module';
-import { environment } from './environments/environment';
+import 'zone.js';
+import { bootstrapApplication } from '@angular/platform-browser';
 
-if (environment.production) {
-  enableProdMode();
-}
+import { AppComponent } from './app/app.component';
+import { appConfig } from './app/app.config';
 
-platformBrowserDynamic().bootstrapModule(AppModule)
-  .catch(err => console.error(err));
+bootstrapApplication(AppComponent, appConfig);
diff --git a/integration/demo-app/src/polyfills.ts b/integration/demo-app/src/polyfills.ts
deleted file mode 100644
index 373f538a..00000000
--- a/integration/demo-app/src/polyfills.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * This file includes polyfills needed by Angular and is loaded before the app.
- * You can add your own extra polyfills to this file.
- *
- * This file is divided into 2 sections:
- *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
- *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
- *      file.
- *
- * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
- * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
- * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
- *
- * Learn more in https://angular.io/guide/browser-support
- */
-
-/***************************************************************************************************
- * BROWSER POLYFILLS
- */
-
-/**
- * IE11 requires the following for NgClass support on SVG elements
- */
-// import 'classlist.js';  // Run `npm install --save classlist.js`.
-
-/**
- * Web Animations `@angular/platform-browser/animations`
- * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
- * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
- */
-// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
-
-/**
- * By default, zone.js will patch all possible macroTask and DomEvents
- * user can disable parts of macroTask/DomEvents patch by setting following flags
- * because those flags need to be set before `zone.js` being loaded, and webpack
- * will put import in the top of bundle, so user need to create a separate file
- * in this directory (for example: zone-flags.ts), and put the following flags
- * into that file, and then add the following code before importing zone.js.
- * import './zone-flags';
- *
- * The flags allowed in zone-flags.ts are listed here.
- *
- * The following flags will work for all browsers.
- *
- * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
- * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
- * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
- *
- *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
- *  with the following flag, it will bypass `zone.js` patch for IE/Edge
- *
- *  (window as any).__Zone_enable_cross_context_check = true;
- *
- */
-
-/***************************************************************************************************
- * Zone JS is required by default for Angular itself.
- */
-import 'zone.js';  // Included with Angular CLI.
-
-
-/***************************************************************************************************
- * APPLICATION IMPORTS
- */
diff --git a/integration/demo-app/src/server/api/v1/hello.ts b/integration/demo-app/src/server/api/v1/hello.ts
new file mode 100644
index 00000000..594c5d71
--- /dev/null
+++ b/integration/demo-app/src/server/api/v1/hello.ts
@@ -0,0 +1,3 @@
+import { defineEventHandler } from 'h3';
+
+export default defineEventHandler(() => ({ message: 'Hello World' }));
diff --git a/integration/demo-app/tsconfig.app.json b/integration/demo-app/tsconfig.app.json
index 98303991..68d14bea 100644
--- a/integration/demo-app/tsconfig.app.json
+++ b/integration/demo-app/tsconfig.app.json
@@ -16,8 +16,9 @@
     "allowSyntheticDefaultImports": true,
     "importHelpers": true,
     "allowJs": true,
-    "target": "es2017",
-    "module": "es2020",
+    "useDefineForClassFields": true,
+    "target": "ES2022",
+    "module": "ES2022",
     "preserveSymlinks": false,
     "lib": [
       "es2018",
@@ -34,7 +35,7 @@
   },
   "files": [
     "./src/main.ts",
-    "./src/polyfills.ts"
+    "./src/main.server.ts"
   ],
   "include": [
     "./src/**/*.d.ts"
diff --git a/tsconfig.json b/tsconfig.json
index ceb7788b..af837ed3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,7 @@
     /* Basic Options */
     "target": "esnext",                             /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
     "module": "commonjs",                           /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
-    "lib": ["ESNext", "dom"],                       /* Specify library files to be included in the compilation. */
+    "lib": ["ESNext.AsyncIterable","ESNext", "dom"],                       /* Specify library files to be included in the compilation. */
     "allowJs": true,                                /* Allow javascript files to be compiled. */
 
     /* Strict Type-Checking Options */
@@ -17,7 +17,7 @@
     // "strictPropertyInitialization": true,        /* Enable strict checking of property initialization in classes. */
     // "noImplicitThis": true,                      /* Raise error on 'this' expressions with an implied 'any' type. */
     // "alwaysStrict": true,                        /* Parse in strict mode and emit "use strict" for each source file. */
-
+    "useDefineForClassFields": false,              /* Emit a define for each class field declaration. */
     /* Additional Checks */
     // "noUnusedLocals": true,                      /* Report errors on unused locals. */
     // "noUnusedParameters": true,                  /* Report errors on unused parameters. */
diff --git a/workspace.jsonc b/workspace.jsonc
index 2f0bfb35..2621aacf 100644
--- a/workspace.jsonc
+++ b/workspace.jsonc
@@ -35,32 +35,37 @@
     "packageManager": "teambit.dependencies/pnpm",
     "policy": {
       "dependencies": {
-        "@teambit/compilation.compiler-task": "1.0.2",
-        "@teambit/defender.eslint-linter": "1.0.8",
-        "@teambit/defender.jest-tester": "1.0.5",
-        "@teambit/defender.prettier-formatter": "1.0.2",
-        "@teambit/dependencies.modules.packages-excluder": "1.0.4",
+        "@clack/prompts": "^0.7.0",
+        "@teambit/compilation.compiler-task": "1.0.6",
+        "@teambit/defender.eslint-linter": "1.0.15",
+        "@teambit/defender.jest-tester": "1.0.12",
+        "@teambit/defender.prettier-formatter": "1.0.7",
+        "@teambit/dependencies.modules.packages-excluder": "1.0.8",
         "@teambit/envs.docs.env-overview-template": "0.0.2",
         "@teambit/graph.cleargraph": "^0.0.7",
-        "@teambit/react.ui.docs-app": "1.0.6",
-        "@teambit/toolbox.network.get-port": "1.0.2",
-        "@teambit/toolbox.performance.v8-cache": "0.0.29",
-        "@teambit/typescript.typescript-compiler": "2.0.7",
+        "@teambit/node.deps-detectors.detective-es6": "0.0.5",
+        "@teambit/react.ui.docs-app": "1.0.11",
+        "@teambit/toolbox.network.get-port": "1.0.4",
+        "@teambit/toolbox.performance.v8-cache": "0.0.31",
+        "@teambit/typescript.typescript-compiler": "2.0.13",
         "@teambit/ui-foundation.ui.constants.z-indexes": "0.0.504",
-        "@teambit/webpack.modules.generate-style-loaders": "1.0.2",
-        "@teambit/webpack.modules.style-regexps": "1.0.2",
-        "@teambit/webpack.webpack-bundler": "1.0.2",
+        "@teambit/webpack.modules.generate-style-loaders": "1.0.4",
+        "@teambit/webpack.modules.style-regexps": "1.0.4",
+        "@teambit/webpack.webpack-bundler": "1.0.7",
         "@types/fs-extra": "~9.0.7",
         "@types/lodash": "4.14.165",
         "@types/object-hash": "~2.1.0",
         "fs-extra": "9.1.0",
+        "json5": "^2.2.3",
         "lodash": "4.17.21",
         "object-hash": "~2.1.1",
         "prettier": "2.3.2",
         "react-dev-utils": "10.2.1",
         "remark-frontmatter": "~3.0.0",
         "remark-html": "13.0.1",
-        "remark-prism": "~1.3.6"
+        "remark-prism": "~1.3.6",
+        "replace-in-file": "^6.3.5",
+        "std-env": "^3.4.3"
       },
       "peerDependencies": {}
     },
@@ -82,7 +87,7 @@
       "bitdev.angular/envs/angular-v16-env",
       "bitdev.angular/envs/angular-v15-env",
       "bitdev.angular/envs/angular-v14-env",
-      "bitdev.angular/envs/angular-v13-env",
+      "bitdev.angular/envs/angular-v13-env"
     ]
   },
   "bitdev.angular/angular-env": {},