Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added the ability to deploy Angular apps using [the new application-builder](https://angular.dev/tools/cli/esbuild). (#6480)
50 changes: 27 additions & 23 deletions src/frameworks/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
SupportLevel,
BUILD_TARGET_PURPOSE,
} from "../interfaces";
import { promptOnce } from "../../prompt";
import {
simpleProxy,
relativeRequire,
Expand Down Expand Up @@ -42,35 +41,24 @@ export async function discover(dir: string): Promise<Discovery | undefined> {
return { mayWantBackend: true, publicDirectory: join(dir, "src", "assets") };
}

export async function init(setup: any, config: any) {
export function init(setup: any, config: any) {
execSync(
`npx --yes -p @angular/cli@latest ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`,
{
stdio: "inherit",
cwd: config.projectDir,
}
);
const useAngularUniversal = await promptOnce({
name: "useAngularUniversal",
type: "confirm",
default: false,
message: `Would you like to setup Angular Universal?`,
});
if (useAngularUniversal) {
execSync("ng add @nguniversal/express-engine --skip-confirmation", {
stdio: "inherit",
cwd: join(config.projectDir, setup.hosting.source),
});
}
return Promise.resolve();
}

export async function build(dir: string, configuration: string): Promise<BuildResult> {
Copy link
Copy Markdown
Contributor

@9kubczas4 9kubczas4 Nov 8, 2023

Choose a reason for hiding this comment

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

Maybe we should mark useAngularUniversal in the init function as legacy?

  const useAngularUniversal = await promptOnce({
    name: "useAngularUniversal",
    type: "confirm",
    default: false,
    message: `Would you like to setup Angular Universal?`,
  });
  if (useAngularUniversal) {
    execSync("ng add @nguniversal/express-engine --skip-confirmation", {
      stdio: "inherit",
      cwd: join(config.projectDir, setup.hosting.source),
    });
  }

Cause NG CLI in v17 is asking about Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point, I should rework the bootstrap. It should be part of Angular's create routine now

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since you are using @angular/cli@latest, @nguniversal/express-engine should not be used as this is only supported for version 16 and before.

const {
targets,
serverTarget,
serveOptimizedImages,
locales,
baseHref: baseUrl,
ssr,
} = await getBuildConfig(dir, configuration);
await warnIfCustomBuildScript(dir, name, DEFAULT_BUILD_SCRIPT);
for (const target of targets) {
Expand All @@ -84,8 +72,8 @@ export async function build(dir: string, configuration: string): Promise<BuildRe
if (result.status !== 0) throw new FirebaseError(`Unable to build ${target}`);
}

const wantsBackend = !!serverTarget || serveOptimizedImages;
const rewrites = serverTarget
const wantsBackend = ssr || serveOptimizedImages;
const rewrites = ssr
? []
: [
{
Expand Down Expand Up @@ -149,8 +137,12 @@ export async function ɵcodegenPublicDirectory(
export async function getValidBuildTargets(purpose: BUILD_TARGET_PURPOSE, dir: string) {
const validTargetNames = new Set(["development", "production"]);
try {
const { workspaceProject, browserTarget, serverTarget, serveTarget } = await getContext(dir);
const { target } = ((purpose === "emulate" && serveTarget) || serverTarget || browserTarget)!;
const { workspaceProject, buildTarget, browserTarget, prerenderTarget, serveTarget } =
await getContext(dir);
const { target } = ((purpose === "emulate" && serveTarget) ||
buildTarget ||
prerenderTarget ||
browserTarget)!;
const workspaceTarget = workspaceProject.targets.get(target)!;
Object.keys(workspaceTarget.configurations || {}).forEach((it) => validTargetNames.add(it));
} catch (e) {
Expand Down Expand Up @@ -182,6 +174,7 @@ export async function ɵcodegenFunctionsDirectory(
externalDependencies,
baseHref,
serveOptimizedImages,
serverEntry,
} = await getServerConfig(sourceDir, configuration);

const dotEnv = { __NG_BROWSER_OUTPUT_PATH__: browserOutputPath };
Expand Down Expand Up @@ -232,14 +225,25 @@ exports.handle = function(req,res) {
if (localizedApps.has(locale)) {
localizedApps.get(locale)(req,res);
} else {
const app = require(\`./${serverOutputPath}/\${locale}/main.js\`).app(locale);
localizedApps.set(locale, app);
app(req,res);
${
serverEntry?.endsWith(".mjs")
? `import(\`./${serverOutputPath}/\${locale}/${serverEntry}\`)`
: `Promise.resolve(require(\`./${serverOutputPath}/\${locale}/${serverEntry}\`))`
}.then(server => {
const app = server.app(locale);
localizedApps.set(locale, app);
app(req,res);
});
}
});
};\n`;
} else if (serverOutputPath) {
bootstrapScript = `exports.handle = require('./${serverOutputPath}/main.js').app();\n`;
bootstrapScript = `const app = ${
serverEntry?.endsWith(".mjs")
? `import(\`./${serverOutputPath}/${serverEntry}\`)`
: `Promise.resolve(require('./${serverOutputPath}/${serverEntry}'))`
}.then(server => server.app());
exports.handle = (req,res) => app.then(it => it(req,res));\n`;
} else {
bootstrapScript = `exports.handle = (res, req) => req.sendStatus(404);\n`;
rewriteSource = posix.join(baseHref, "__image__");
Expand Down
Loading