Skip to content

Commit

Permalink
feat: update Angular template to version 17
Browse files Browse the repository at this point in the history
This commits updates the Angular template to use Angular 17.
  • Loading branch information
alan-agius4 authored and petebacondarwin committed Oct 30, 2023
1 parent e4aff81 commit c6b4755
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 184 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-bees-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-cloudflare": minor
---

Update Angular template to use version 17
74 changes: 23 additions & 51 deletions packages/create-cloudflare/src/frameworks/angular/index.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,44 @@
import { cp, rm } from "node:fs/promises";
import { cp } from "node:fs/promises";
import { resolve } from "node:path";
import { logRaw } from "@cloudflare/cli";
import { brandColor, dim } from "@cloudflare/cli/colors";
import { spinner } from "@cloudflare/cli/interactive";
import {
installPackages,
runCommand,
runFrameworkGenerator,
} from "helpers/command";
import { installPackages, runFrameworkGenerator } from "helpers/command";
import { compatDateFlag, readFile, readJSON, writeFile } from "helpers/files";
import { detectPackageManager } from "helpers/packages";
import { getFrameworkCli } from "../index";
import type { FrameworkConfig, PagesGeneratorContext } from "types";

const { dlx, npx, npm } = detectPackageManager();
const { dlx, npm } = detectPackageManager();

const generate = async (ctx: PagesGeneratorContext) => {
const cli = getFrameworkCli(ctx);

await runFrameworkGenerator(
ctx,
`${dlx} ${cli} new ${ctx.project.name} --standalone`
);
await runFrameworkGenerator(ctx, `${dlx} ${cli} ${ctx.project.name} --ssr`);

logRaw("");
};

const configure = async (ctx: PagesGeneratorContext) => {
process.chdir(ctx.project.path);
await runCommand(`${npx} ng analytics disable`, {
silent: true,
});
await addSSRAdapter();
await installCFWorker(ctx);
await updateAppCode();
updateAngularJson(ctx);
await updateAppCode();
await installCFWorker(ctx);
};

const config: FrameworkConfig = {
generate,
configure,
displayName: "Angular",
getPackageScripts: async () => ({
process:
"node ./tools/copy-worker-files.mjs && node ./tools/copy-client-files.mjs && node ./tools/bundle.mjs",
"pages:build": `${npm} run build:ssr && ${npm} run process`,
start: `${npm} run pages:build && wrangler pages dev dist/cloudflare ${await compatDateFlag()} --experimental-local`,
process: "node ./tools/copy-files.mjs && node ./tools/alter-polyfills.mjs",
"pages:build": `ng build && ${npm} run process`,
deploy: `${npm} run pages:build && wrangler pages deploy dist/cloudflare`,
}),
deployCommand: "deploy",
devCommand: "start",
testFlags: ["--routing", "--style", "sass"],
testFlags: ["--ssr", "--style", "sass"],
};
export default config;

Expand All @@ -66,67 +54,51 @@ async function installCFWorker(ctx: PagesGeneratorContext) {
s.stop(`${brandColor("copied")} ${dim("adapter code")}`);

await installPackages(
[
"@cloudflare/workers-types",
"@esbuild-plugins/node-globals-polyfill",
"@esbuild-plugins/node-modules-polyfill",
"@miniflare/tre@next",
"esbuild",
"fast-glob",
"wrangler@beta",
],
["@cloudflare/workers-types", "@miniflare/tre@next", "wrangler@beta"],
{
dev: true,
startText: "Installing adapter dependencies",
doneText: `${brandColor("installed")} ${dim(`via \`${npm} install\``)}`,
}
);
}

async function addSSRAdapter() {
const cmd = `${npx} ng add @nguniversal/express-engine`;

await runCommand(`${cmd} --skip-confirmation`, {
silent: true,
startText: "Installing Angular SSR",
doneText: `${brandColor("installed")} ${dim(`via \`${cmd}\``)}`,
});
}

async function updateAppCode() {
const s = spinner();
s.start(`Updating application code`);

// Update an app config file to:
// - add the `provideClientHydration()` provider to enable hydration
// - add the `provideHttpClient(withFetch())` call to enable `fetch` usage in `HttpClient`
const appConfigPath = "src/app/app.config.ts";
const appConfig = readFile(resolve(appConfigPath));
const newAppConfig =
"import { provideClientHydration } from '@angular/platform-browser';\n" +
"import { provideHttpClient, withFetch } from '@angular/common/http';\n" +
appConfig.replace(
"providers: [",
"providers: [provideHttpClient(withFetch()), provideClientHydration(), "
"providers: [provideHttpClient(withFetch()), "
);
writeFile(resolve(appConfigPath), newAppConfig);
s.stop(`${brandColor(`updated`)} ${dim(appConfigPath)}`);

// Remove the unwanted node.js server entry-point
await rm(resolve("server.ts"));
// Remove unwanted dependencies
s.start(`Updating package.json`);
const packageJsonPath = resolve("package.json");
const packageManifest = readJSON(packageJsonPath);

s.stop(`${brandColor(`updated`)} ${dim(appConfigPath)}`);
delete packageManifest["dependencies"]["@angular/ssr"];
delete packageManifest["dependencies"]["express"];

writeFile(packageJsonPath, JSON.stringify(packageManifest, null, 2));
s.stop(`${brandColor(`updated`)} ${dim(`\`package.json\``)}`);
}

function updateAngularJson(ctx: PagesGeneratorContext) {
const s = spinner();
s.start(`Updating angular.json config`);
const angularJson = readJSON(resolve("angular.json"));
// Update builder
const architectSection = angularJson.projects[ctx.project.name].architect;
architectSection.build.options.outputPath = "dist/browser";
architectSection.build.options.outputPath = "dist";
architectSection.build.options.assets.push("src/_routes.json");
architectSection.server.options.outputPath = "dist/server";
architectSection.server.options.main = "src/main.server.ts";
delete architectSection["serve-ssr"];

writeFile(resolve("angular.json"), JSON.stringify(angularJson, null, 2));
s.stop(`${brandColor(`updated`)} ${dim(`\`angular.json\``)}`);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { renderApplication } from '@angular/platform-server';
import bootstrap from './src/main.server';

interface Env {
ASSETS: { fetch: typeof fetch };
}

// We attach the Cloudflare `fetch()` handler to the global scope
// so that we can export it when we process the Angular output.
// See tools/bundle.mjs
async function workerFetchHandler(request: Request, env: Env) {
const url = new URL(request.url);
console.log('render SSR', url.href);

// Get the root `index.html` content.
const indexUrl = new URL('/', url);
const indexResponse = await env.ASSETS.fetch(new Request(indexUrl));
const document = await indexResponse.text();

const content = await renderApplication(bootstrap, {
document,
url: url.pathname,
});

// console.log("rendered SSR", content);
return new Response(content, indexResponse);
}

export default {
fetch: (request: Request, env: Env) =>
(globalThis as any)['__zone_symbol__Promise'].resolve(
workerFetchHandler(request, env)
),
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { EOL } from "node:os";
import fs from "node:fs";
import { join } from "node:path";
import { worker } from "./paths.mjs";

/**
* Split by lines and comment the banner
* ```
* import { createRequire } from 'node:module';
* globalThis['require'] ??= createRequire(import.meta.url);
* ```
*/
const serverPolyfillsFile = join(worker, "polyfills.server.mjs");
const serverPolyfillsData = fs
.readFileSync(serverPolyfillsFile, "utf8")
.split(EOL);

for (let index = 0; index < 2; index++) {
if (serverPolyfillsData[index].includes("createRequire")) {
serverPolyfillsData[index] = "// " + serverPolyfillsData[index];
}
}

// Add needed polyfills
serverPolyfillsData.unshift(
`globalThis['process'] = {};`,
`globalThis['global'] = globalThis;`,
// Needed as performance.mark is not a function in worker.
`performance.mark = () => {};`,
);

fs.writeFileSync(serverPolyfillsFile, serverPolyfillsData.join(EOL));

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copy the files over so that they can be uploaded by the pages publish command.
import fs from "node:fs";
import { join } from "node:path";
import { client, cloudflare, worker, ssr } from "./paths.mjs";

fs.cpSync(client, cloudflare, { recursive: true });
fs.cpSync(ssr, worker, { recursive: true });

fs.renameSync(join(worker, "server.mjs"), join(worker, "index.js"));

This file was deleted.

This file was deleted.

4 changes: 2 additions & 2 deletions packages/create-cloudflare/src/frameworks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"additionally it also contains a map that maps frameworks to their respective clis"
],
"dependencies": {
"@angular/cli": "16.2.2",
"create-astro": "4.4.1",
"@angular/create": "17.0.0-rc.1",
"create-docusaurus": "2.4.3",
"create-hono": "0.3.2",
"create-next-app": "13.4.19",
Expand All @@ -21,7 +21,7 @@
"nuxi": "3.9.0"
},
"frameworkCliMap": {
"angular": "@angular/cli",
"angular": "@angular/create",
"astro": "create-astro",
"docusaurus": "create-docusaurus",
"gatsby": "gatsby",
Expand Down

0 comments on commit c6b4755

Please sign in to comment.