Skip to content

Commit

Permalink
feat(@angular-devkit/build-angular): support deploy URL option for `b…
Browse files Browse the repository at this point in the history
…rowser-esbuild` builder

The `browser-esbuild` builder now provides support for using the `deployUrl` option when building
applications.  This option is still considered deprecated which is the same status as with the
Webpack-based `browser` application builder. This option is only available with the `browser-esbuild`
builder and not other esbuild-based builders. The `browser-esbuild` builder is primarily intended
to be used as a compatibility builder with the `browser` builder that requires only minimal changes
to use.
  • Loading branch information
clydin authored and alan-agius4 committed Oct 10, 2023
1 parent b5a8174 commit 771e036
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 3 deletions.
Expand Up @@ -47,6 +47,11 @@ interface InternalOptions {
* This is only used by the development server which currently only supports a single locale per build.
*/
forceI18nFlatOutput?: boolean;

/**
* Allows for usage of the deprecated `deployUrl` option with the compatibility builder `browser-esbuild`.
*/
deployUrl?: string;
}

/** Full set of options for `application` builder. */
Expand Down Expand Up @@ -239,6 +244,7 @@ export async function normalizeOptions(
deleteOutputPath,
namedChunks,
budgets,
deployUrl,
} = options;

// Return all the normalized options
Expand Down Expand Up @@ -288,6 +294,7 @@ export async function normalizeOptions(
i18nOptions,
namedChunks,
budgets: budgets?.length ? budgets : undefined,
publicPath: deployUrl ? deployUrl : undefined,
};
}

Expand Down
Expand Up @@ -10,9 +10,6 @@ import { BuilderContext } from '@angular-devkit/architect';
import { Schema as BrowserBuilderOptions } from './schema';

const UNSUPPORTED_OPTIONS: Array<keyof BrowserBuilderOptions> = [
// * Deprecated
'deployUrl',

// * Always enabled with esbuild
// 'commonChunk',

Expand Down
@@ -0,0 +1,82 @@
/**
* @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.io/license
*/

import { buildEsbuildBrowser } from '../../index';
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup';

describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => {
describe('Option: "deployUrl"', () => {
beforeEach(async () => {
// Application code is not needed for asset tests
await harness.writeFile('src/main.ts', 'console.log("TEST");');

// Add a global stylesheet to test link elements
await harness.writeFile('src/styles.css', '/* Global styles */');

// Reduce the input index HTML to a single line to simplify comparing
await harness.writeFile(
'src/index.html',
'<html><head><base href="/"></head><body><app-root></app-root></body></html>',
);
});

it('should update script src and link href attributes when option is set to relative URL', async () => {
harness.useTarget('build', {
...BASE_OPTIONS,
styles: ['src/styles.css'],
deployUrl: 'deployUrl/',
});

const { result } = await harness.executeOnce();
expect(result?.success).toBe(true);
harness
.expectFile('dist/index.html')
.content.toEqual(
`<html><head><base href="/"><link rel="stylesheet" href="deployUrl/styles.css"></head>` +
`<body><app-root></app-root>` +
`<script src="deployUrl/main.js" type="module"></script></body></html>`,
);
});

it('should update script src and link href attributes when option is set to absolute URL', async () => {
harness.useTarget('build', {
...BASE_OPTIONS,
styles: ['src/styles.css'],
deployUrl: 'https://example.com/some/path/',
});

const { result } = await harness.executeOnce();
expect(result?.success).toBe(true);
harness
.expectFile('dist/index.html')
.content.toEqual(
`<html><head><base href="/"><link rel="stylesheet" href="https://example.com/some/path/styles.css"></head>` +
`<body><app-root></app-root>` +
`<script src="https://example.com/some/path/main.js" type="module"></script></body></html>`,
);
});

it('should update dynamic import statements when option is set', async () => {
harness.useTarget('build', {
...BASE_OPTIONS,
styles: ['src/styles.css'],
deployUrl: 'https://example.com/some/path/',
namedChunks: true,
});

await harness.writeFile('src/main.ts', 'console.log("TEST");\nimport("./a");\nexport {}');
await harness.writeFile('src/a.ts', 'console.log("A");\nexport {}');

const { result } = await harness.executeOnce();
expect(result?.success).toBe(true);
harness
.expectFile('dist/main.js')
.content.toContain('import("https://example.com/some/path/a');
});
});
});
Expand Up @@ -405,5 +405,6 @@ function getEsBuildCommonOptions(options: NormalizedApplicationBuildOptions): Bu
'ngJitMode': jit ? 'true' : 'false',
},
footer,
publicPath: options.publicPath,
};
}
Expand Up @@ -64,6 +64,7 @@ export function createCompilerPluginOptions(
inlineStyleLanguage,
preserveSymlinks,
tailwindConfiguration,
publicPath: options.publicPath,
},
};
}
Expand Up @@ -62,6 +62,7 @@ export function createGlobalStylesBundleOptions(
},
includePaths: stylePreprocessorOptions?.includePaths,
tailwindConfiguration,
publicPath: options.publicPath,
},
cache,
);
Expand Down
Expand Up @@ -82,6 +82,7 @@ export async function generateIndexHtml(
},
},
crossOrigin: crossOrigin,
deployUrl: buildOptions.publicPath,
});

indexHtmlGenerator.readAsset = readAsset;
Expand Down
Expand Up @@ -25,6 +25,7 @@ export interface BundleStylesheetOptions {
externalDependencies?: string[];
target: string[];
tailwindConfiguration?: { file: string; package: string };
publicPath?: string;
}

export function createStylesheetBundleOptions(
Expand Down Expand Up @@ -62,6 +63,7 @@ export function createStylesheetBundleOptions(
target: options.target,
preserveSymlinks: options.preserveSymlinks,
external: options.externalDependencies,
publicPath: options.publicPath,
conditions: ['style', 'sass'],
mainFields: ['style', 'sass'],
plugins: [
Expand Down

0 comments on commit 771e036

Please sign in to comment.