Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/angular/build/src/builders/application/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import { getProjectRootPaths, normalizeDirectoryPath } from '../../utils/project
import { addTrailingSlash, joinUrlParts, stripLeadingSlash } from '../../utils/url';
import {
Schema as ApplicationBuilderOptions,
ExperimentalPlatform,
I18NTranslation,
OutputHashing,
OutputMode,
OutputPathClass,
Platform,
} from './schema';

/**
Expand Down Expand Up @@ -292,11 +292,11 @@ export async function normalizeOptions(
if (options.ssr === true) {
ssrOptions = {};
} else if (typeof options.ssr === 'object') {
const { entry, experimentalPlatform = ExperimentalPlatform.Node } = options.ssr;
const { entry, platform = Platform.Node } = options.ssr;

ssrOptions = {
entry: entry && path.join(workspaceRoot, entry),
platform: experimentalPlatform,
platform,
};
}

Expand Down
4 changes: 2 additions & 2 deletions packages/angular/build/src/builders/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@
"type": "string",
"description": "The server entry-point that when executed will spawn the web server."
},
"experimentalPlatform": {
"description": "Specifies the platform for which the server bundle is generated. This affects the APIs and modules available in the server-side code. \n\n- `node`: (Default) Generates a bundle optimized for Node.js environments. \n- `neutral`: Generates a platform-neutral bundle suitable for environments like edge workers, and other serverless platforms. This option avoids using Node.js-specific APIs, making the bundle more portable. \n\nPlease note that this feature does not provide polyfills for Node.js modules. Additionally, it is experimental, and the schematics may undergo changes in future versions.",
"platform": {
"description": "Specifies the platform for which the server bundle is generated. This affects the APIs and modules available in the server-side code. \n\n- `node`: (Default) Generates a bundle optimized for Node.js environments. \n- `neutral`: Generates a platform-neutral bundle suitable for environments like edge workers, and other serverless platforms. This option avoids using Node.js-specific APIs, making the bundle more portable. \n\nPlease note that this feature does not provide polyfills for Node.js modules.",
"default": "node",
"enum": ["node", "neutral"]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.dev/license
*/

import type { BuildOptions, PartialMessage, Plugin } from 'esbuild';
import type { BuildOptions, Plugin } from 'esbuild';
import assert from 'node:assert';
import { createHash } from 'node:crypto';
import { extname, relative } from 'node:path';
import type { NormalizedApplicationBuildOptions } from '../../builders/application/options';
import { ExperimentalPlatform } from '../../builders/application/schema';
import { Platform } from '../../builders/application/schema';
import { allowMangle } from '../../utils/environment-options';
import { toPosixPath } from '../../utils/path';
import {
Expand Down Expand Up @@ -158,7 +158,7 @@ export function createServerPolyfillBundleOptions(
): BundlerOptionsFactory | undefined {
const serverPolyfills: string[] = [];
const polyfillsFromConfig = new Set(options.polyfills);
const isNodePlatform = options.ssrOptions?.platform !== ExperimentalPlatform.Neutral;
const isNodePlatform = options.ssrOptions?.platform !== Platform.Neutral;

if (!isZonelessApp(options.polyfills)) {
serverPolyfills.push(isNodePlatform ? 'zone.js/node' : 'zone.js');
Expand Down Expand Up @@ -295,7 +295,7 @@ export function createServerMainCodeBundleOptions(

// Mark manifest and polyfills file as external as these are generated by a different bundle step.
(buildOptions.external ??= []).push(...SERVER_GENERATED_EXTERNALS);
const isNodePlatform = options.ssrOptions?.platform !== ExperimentalPlatform.Neutral;
const isNodePlatform = options.ssrOptions?.platform !== Platform.Neutral;

if (!isNodePlatform) {
// `@angular/platform-server` lazily depends on `xhr2` for XHR usage with the HTTP client.
Expand Down Expand Up @@ -387,7 +387,7 @@ export function createSsrEntryCodeBundleOptions(
const pluginOptions = createCompilerPluginOptions(options, sourceFileCache, loadResultCache);
const ssrEntryNamespace = 'angular:ssr-entry';
const ssrInjectManifestNamespace = 'angular:ssr-entry-inject-manifest';
const isNodePlatform = options.ssrOptions?.platform !== ExperimentalPlatform.Neutral;
const isNodePlatform = options.ssrOptions?.platform !== Platform.Neutral;

const jsBanner: string[] = [];
if (options.externalDependencies?.length) {
Expand Down Expand Up @@ -505,7 +505,7 @@ export function createSsrEntryCodeBundleOptions(
}

function getEsBuildServerCommonOptions(options: NormalizedApplicationBuildOptions): BuildOptions {
const isNodePlatform = options.ssrOptions?.platform !== ExperimentalPlatform.Neutral;
const isNodePlatform = options.ssrOptions?.platform !== Platform.Neutral;

const commonOptions = getEsBuildCommonOptions(options);
commonOptions.define ??= {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"encapsulation": false,
"schematics": {
"use-application-builder": {
"version": "21.0.0",
"version": "22.0.0",
"factory": "./use-application-builder/migration",
"description": "Migrate application projects to the new build system. Application projects that are using the '@angular-devkit/build-angular' package's 'browser' and/or 'browser-esbuild' builders will be migrated to use the new 'application' builder. You can read more about this, including known issues and limitations, here: https://angular.dev/tools/cli/build-system-migration",
"optional": true,
Expand All @@ -13,6 +13,11 @@
"version": "21.0.0",
"factory": "./karma/migration",
"description": "Remove any karma configuration files that only contain the default content. The default configuration is automatically available without a specific project file."
},
"update-workspace-config": {
"version": "22.0.0",
"factory": "./update-workspace-config/migration",
"description": "Update the angular workspace configuration."
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import { isJsonObject } from '@angular-devkit/core';
import { Rule } from '@angular-devkit/schematics';
import { allTargetOptions, updateWorkspace } from '../../utility/workspace';
import { Builders, ProjectType } from '../../utility/workspace-models';

/**
* Migration to update the angular workspace configuration.
*/
export default function (): Rule {
return updateWorkspace((workspace) => {
for (const project of workspace.projects.values()) {
if (project.extensions['projectType'] !== ProjectType.Application) {
continue;
}

for (const target of project.targets.values()) {
if (
target.builder !== Builders.Application &&
target.builder !== Builders.BuildApplication
) {
continue;
}

for (const [, options] of allTargetOptions(target)) {
const ssr = options['ssr'];
if (!ssr || !isJsonObject(ssr)) {
continue;
}

const platform = ssr['experimentalPlatform'];
if (platform) {
ssr['platform'] = platform;
delete ssr['experimentalPlatform'];
}
}
}
}
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

import { EmptyTree } from '@angular-devkit/schematics';
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import { Builders, ProjectType } from '../../utility/workspace-models';

describe('Migration to update the angular workspace configuration', () => {
const schematicName = 'update-workspace-config';
const schematicRunner = new SchematicTestRunner(
'migrations',
require.resolve('../migration-collection.json'),
);

let tree: UnitTestTree;
beforeEach(() => {
tree = new UnitTestTree(new EmptyTree());
});

it('should rename experimentalPlatform to platform in application builder', async () => {
const angularConfig = {
version: 1,
projects: {
app: {
root: '',
sourceRoot: 'src',
projectType: ProjectType.Application,
prefix: 'app',
architect: {
build: {
builder: Builders.Application,
options: {
ssr: {
entry: 'src/server.ts',
experimentalPlatform: 'neutral',
},
},
configurations: {
production: {
ssr: {
experimentalPlatform: 'node',
},
},
},
},
},
},
},
};

tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));

const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const config = newTree.readJson('/angular.json') as any;
const options = config.projects.app.architect.build.options;
const prodOptions = config.projects.app.architect.build.configurations.production;

expect(options.ssr.platform).toBe('neutral');
expect(options.ssr.experimentalPlatform).toBeUndefined();
expect(prodOptions.ssr.platform).toBe('node');
expect(prodOptions.ssr.experimentalPlatform).toBeUndefined();
});

it('should not change other builders', async () => {
const angularConfig = {
version: 1,
projects: {
app: {
root: '',
sourceRoot: 'src',
projectType: ProjectType.Application,
prefix: 'app',
architect: {
build: {
builder: Builders.Browser,
options: {
ssr: {
experimentalPlatform: 'neutral',
},
},
},
},
},
},
};

tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));

const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const config = newTree.readJson('/angular.json') as any;
const options = config.projects.app.architect.build.options;

expect(options.ssr.experimentalPlatform).toBe('neutral');
expect(options.ssr.platform).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default async function () {
await updateJsonFile('angular.json', (json) => {
const buildTarget = json['projects']['test-project']['architect']['build'];
const options = buildTarget['options'];
options['ssr']['experimentalPlatform'] = 'neutral';
options['ssr']['platform'] = 'neutral';
options['outputMode'] = 'server';
options['security'] ??= {};
options['security']['allowedHosts'] = ['localhost'];
Expand Down
Loading