diff --git a/apps/browser/package.json b/apps/browser/package.json
index 3cfc4377227..a30131063bf 100644
--- a/apps/browser/package.json
+++ b/apps/browser/package.json
@@ -3,7 +3,9 @@
"version": "2025.8.2",
"scripts": {
"build": "npm run build:chrome",
+ "build:bit": "npm run build:bit:chrome",
"build:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
+ "build:bit:chrome": "cross-env BROWSER=chrome MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack -c ../../bitwarden_license/bit-browser/webpack.config.js",
"build:edge": "cross-env BROWSER=edge MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
"build:firefox": "cross-env BROWSER=firefox NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
"build:opera": "cross-env BROWSER=opera MANIFEST_VERSION=3 NODE_OPTIONS=\"--max-old-space-size=8192\" webpack",
diff --git a/apps/browser/src/popup/app.component.html b/apps/browser/src/popup/app.component.html
new file mode 100644
index 00000000000..3d81354ca35
--- /dev/null
+++ b/apps/browser/src/popup/app.component.html
@@ -0,0 +1,20 @@
+@if (showSdkWarning | async) {
+
+} @else {
+
+
+
+
+}
diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts
index ee75dbaf7af..4f46f889eaa 100644
--- a/apps/browser/src/popup/app.component.ts
+++ b/apps/browser/src/popup/app.component.ts
@@ -57,28 +57,7 @@ import { DesktopSyncVerificationDialogComponent } from "./components/desktop-syn
selector: "app-root",
styles: [],
animations: [routerTransition],
- template: `
- @if (showSdkWarning | async) {
-
- } @else {
-
-
-
-
- }
- `,
+ templateUrl: "app.component.html",
standalone: false,
})
export class AppComponent implements OnInit, OnDestroy {
diff --git a/apps/browser/webpack.config.js b/apps/browser/webpack.config.js
index e62f90354d2..1378a341251 100644
--- a/apps/browser/webpack.config.js
+++ b/apps/browser/webpack.config.js
@@ -151,11 +151,6 @@ const plugins = [
filename: "[name].css",
chunkFilename: "chunk-[id].css",
}),
- new AngularWebpackPlugin({
- tsConfigPath: "tsconfig.json",
- entryModule: "src/popup/app.module#AppModule",
- sourceMap: true,
- }),
new webpack.ProvidePlugin({
process: "process/browser.js",
}),
@@ -164,6 +159,11 @@ const plugins = [
filename: "[file].map",
}),
...requiredPlugins,
+ new AngularWebpackPlugin({
+ tsConfigPath: "tsconfig.json",
+ entryModule: "src/popup/app.module#AppModule",
+ sourceMap: true,
+ }),
];
/**
diff --git a/bitwarden_license/bit-browser/jest.config.js b/bitwarden_license/bit-browser/jest.config.js
new file mode 100644
index 00000000000..5451c15e47c
--- /dev/null
+++ b/bitwarden_license/bit-browser/jest.config.js
@@ -0,0 +1,22 @@
+const { pathsToModuleNameMapper } = require("ts-jest");
+
+const { compilerOptions } = require("../../tsconfig.base");
+
+const sharedConfig = require("../../libs/shared/jest.config.angular");
+
+/** @type {import('jest').Config} */
+module.exports = {
+ ...sharedConfig,
+ setupFilesAfterEnv: ["../../apps/browser/test.setup.ts"],
+ moduleNameMapper: pathsToModuleNameMapper(
+ {
+ "@bitwarden/common/spec": ["libs/common/spec"],
+ "@bitwarden/common": ["libs/common/src/*"],
+ "@bitwarden/admin-console/common": ["libs/admin-console/src/common"],
+ ...(compilerOptions?.paths ?? {}),
+ },
+ {
+ prefix: "/../../",
+ },
+ ),
+};
diff --git a/bitwarden_license/bit-browser/src/background/main.background.ts b/bitwarden_license/bit-browser/src/background/main.background.ts
new file mode 100644
index 00000000000..48efc8099e6
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/background/main.background.ts
@@ -0,0 +1,9 @@
+import OssMainBackground from "@bitwarden/browser/background/main.background";
+
+export default class MainBackground {
+ private ossMain = new OssMainBackground();
+
+ async bootstrap() {
+ await this.ossMain.bootstrap();
+ }
+}
diff --git a/bitwarden_license/bit-browser/src/platform/background.ts b/bitwarden_license/bit-browser/src/platform/background.ts
new file mode 100644
index 00000000000..0cd9b3285e6
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/platform/background.ts
@@ -0,0 +1,7 @@
+import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
+
+import MainBackground from "../background/main.background";
+
+const logService = new ConsoleLogService(false);
+const bitwardenMain = ((self as any).bitwardenMain = new MainBackground());
+bitwardenMain.bootstrap().catch((error) => logService.error(error));
diff --git a/bitwarden_license/bit-browser/src/popup/app-routing.module.ts b/bitwarden_license/bit-browser/src/popup/app-routing.module.ts
new file mode 100644
index 00000000000..7cabfb68e8d
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/popup/app-routing.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from "@angular/core";
+import { RouterModule, Routes } from "@angular/router";
+
+const routes: Routes = [];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule],
+})
+export class AppRoutingModule {}
diff --git a/bitwarden_license/bit-browser/src/popup/app.component.ts b/bitwarden_license/bit-browser/src/popup/app.component.ts
new file mode 100644
index 00000000000..339681d66da
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/popup/app.component.ts
@@ -0,0 +1,14 @@
+import { Component, OnInit } from "@angular/core";
+
+import { AppComponent as BaseAppComponent } from "@bitwarden/browser/popup/app.component";
+
+@Component({
+ selector: "app-root",
+ templateUrl: "../../../../apps/browser/src/popup/app.component.html",
+ standalone: false,
+})
+export class AppComponent extends BaseAppComponent implements OnInit {
+ ngOnInit() {
+ return super.ngOnInit();
+ }
+}
diff --git a/bitwarden_license/bit-browser/src/popup/app.module.ts b/bitwarden_license/bit-browser/src/popup/app.module.ts
new file mode 100644
index 00000000000..589d7794724
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/popup/app.module.ts
@@ -0,0 +1,39 @@
+import { OverlayModule } from "@angular/cdk/overlay";
+import { CommonModule } from "@angular/common";
+import { NgModule } from "@angular/core";
+import { RouterModule } from "@angular/router";
+
+import { JslibModule } from "@bitwarden/angular/jslib.module";
+// import { AppRoutingAnimationsModule } from "@bitwarden/browser/popup/app-routing-animations";
+import { AppRoutingModule as OssRoutingModule } from "@bitwarden/browser/popup/app-routing.module";
+import { AppModule as OssModule } from "@bitwarden/browser/popup/app.module";
+// import { WildcardRoutingModule } from "@bitwarden/browser/popup/wildcard-routing.module";
+
+import { AppRoutingModule } from "./app-routing.module";
+import { AppComponent } from "./app.component";
+/**
+ * This is the AppModule for the commercial version of Bitwarden.
+ * `apps/browser/app.module.ts` contains the OSS version.
+ *
+ * You probably do not want to modify this file. Consider editing `oss.module.ts` instead.
+ */
+@NgModule({
+ imports: [
+ CommonModule,
+ OverlayModule,
+ OssModule,
+ JslibModule,
+ // BrowserAnimationsModule,
+ // FormsModule,
+ // ReactiveFormsModule,
+ // CoreModule,
+ // DragDropModule,
+ AppRoutingModule,
+ OssRoutingModule,
+ RouterModule,
+ // WildcardRoutingModule, // Needs to be last to catch all non-existing routes
+ ],
+ declarations: [AppComponent],
+ bootstrap: [AppComponent],
+})
+export class AppModule {}
diff --git a/bitwarden_license/bit-browser/src/popup/main.ts b/bitwarden_license/bit-browser/src/popup/main.ts
new file mode 100644
index 00000000000..3aae5c451e1
--- /dev/null
+++ b/bitwarden_license/bit-browser/src/popup/main.ts
@@ -0,0 +1,29 @@
+import { enableProdMode } from "@angular/core";
+import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
+
+import { PopupSizeService } from "@bitwarden/browser/platform/popup/layout/popup-size.service";
+import { BrowserPlatformUtilsService } from "@bitwarden/browser/platform/services/platform-utils/browser-platform-utils.service";
+
+// // eslint-disable-next-line @typescript-eslint/no-require-imports
+// require("./scss/popup.scss");
+// // eslint-disable-next-line @typescript-eslint/no-require-imports
+// require("./scss/tailwind.css");
+
+import { AppModule } from "./app.module";
+
+// We put these first to minimize the delay in window changing.
+PopupSizeService.initBodyWidthFromLocalStorage();
+// Should be removed once we deprecate support for Safari 16.0 and older. See Jira ticket [PM-1861]
+if (BrowserPlatformUtilsService.shouldApplySafariHeightFix(window)) {
+ document.documentElement.classList.add("safari_height_fix");
+}
+
+if (process.env.ENV === "production") {
+ enableProdMode();
+}
+
+function init() {
+ void platformBrowserDynamic().bootstrapModule(AppModule);
+}
+
+init();
diff --git a/bitwarden_license/bit-browser/tsconfig.json b/bitwarden_license/bit-browser/tsconfig.json
new file mode 100644
index 00000000000..15be9b717fd
--- /dev/null
+++ b/bitwarden_license/bit-browser/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../apps/browser/tsconfig",
+ "files": [],
+ "include": [
+ "src",
+ "../../apps/browser/src/**/*.d.ts",
+ "../../libs/common/src/autofill/constants",
+ "../../libs/common/custom-matchers.d.ts"
+ ]
+}
diff --git a/bitwarden_license/bit-browser/tsconfig.spec.json b/bitwarden_license/bit-browser/tsconfig.spec.json
new file mode 100644
index 00000000000..968309bca6a
--- /dev/null
+++ b/bitwarden_license/bit-browser/tsconfig.spec.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "isolatedModules": true,
+ "emitDecoratorMetadata": false
+ },
+ "files": ["../../apps/browser/test.setup.ts"]
+}
diff --git a/bitwarden_license/bit-browser/webpack.config.js b/bitwarden_license/bit-browser/webpack.config.js
new file mode 100644
index 00000000000..aa3270c2e29
--- /dev/null
+++ b/bitwarden_license/bit-browser/webpack.config.js
@@ -0,0 +1,17 @@
+const { AngularWebpackPlugin } = require("@ngtools/webpack");
+
+const webpackConfig = require("../../apps/browser/webpack.config");
+
+const mainConfig = webpackConfig[0];
+const backgroundConfig = webpackConfig[1];
+
+mainConfig.entry["app/main"] = "../../bitwarden_license/bit-browser/src/popup/main.ts";
+mainConfig.plugins[mainConfig.plugins.length - 1] = new AngularWebpackPlugin({
+ tsconfig: "../../bitwarden_license/bit-browser/tsconfig.json",
+ entryModule: "bitwarden_license/bit-browser/src/popup/app.module#AppModule",
+ sourceMap: true,
+});
+
+backgroundConfig.entry = "./src/platform/background.ts";
+
+module.exports = webpackConfig;
diff --git a/jest.config.js b/jest.config.js
index 3e4fb665a8c..9be54e99995 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -20,9 +20,10 @@ module.exports = {
"/apps/cli/jest.config.js",
"/apps/desktop/jest.config.js",
"/apps/web/jest.config.js",
- "/bitwarden_license/bit-web/jest.config.js",
+ "/bitwarden_license/bit-browser/jest.config.js",
"/bitwarden_license/bit-cli/jest.config.js",
"/bitwarden_license/bit-common/jest.config.js",
+ "/bitwarden_license/bit-web/jest.config.js",
"/libs/admin-console/jest.config.js",
"/libs/angular/jest.config.js",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 3d38f0f8210..3d1d2915f67 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -26,6 +26,7 @@
"@bitwarden/auth/common": ["./libs/auth/src/common"],
"@bitwarden/billing": ["./libs/billing/src"],
"@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"],
+ "@bitwarden/browser/*": ["./apps/browser/src/*"],
"@bitwarden/cli/*": ["./apps/cli/src/*"],
"@bitwarden/client-type": ["libs/client-type/src/index.ts"],
"@bitwarden/common/*": ["./libs/common/src/*"],