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
28 changes: 28 additions & 0 deletions packages/angular/build/src/builders/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,34 @@
"type": "string"
},
"default": []
},
"sass": {
"description": "Options to pass to the sass preprocessor.",
"type": "object",
"properties": {
"fatalDeprecations": {
"description": "A set of deprecations to treat as fatal. If a deprecation warning of any provided type is encountered during compilation, the compiler will error instead. If a Version is provided, then all deprecations that were active in that compiler version will be treated as fatal.",
"type": "array",
"items": {
"type": "string"
}
},
"silenceDeprecations": {
"description": " A set of active deprecations to ignore. If a deprecation warning of any provided type is encountered during compilation, the compiler will ignore it instead.",
"type": "array",
"items": {
"type": "string"
}
},
"futureDeprecations": {
"description": "A set of future deprecations to opt into early. Future deprecations passed here will be treated as active by the compiler, emitting warnings as necessary.",
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* @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 { buildApplication } from '../../index';
import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup';
import { logging } from '@angular-devkit/core';

describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
describe('Option: "stylePreprocessorOptions.sass"', () => {
it('should cause the build to fail when using `fatalDeprecations` in global styles', async () => {
await harness.writeFile('src/styles.scss', 'p { color: darken(red, 10%) }');

harness.useTarget('build', {
...BASE_OPTIONS,
styles: ['src/styles.scss'],
stylePreprocessorOptions: {
sass: {
fatalDeprecations: ['color-functions'],
},
},
});

const { result, logs } = await harness.executeOnce({ outputLogsOnFailure: false });

expect(result?.success).toBeFalse();
expect(logs).not.toContain(
jasmine.objectContaining<logging.LogEntry>({
message: jasmine.stringMatching('darken() is deprecated'),
}),
);
});

it('should succeed without `fatalDeprecations` despite using deprecated color functions', async () => {
await harness.writeFiles({
'src/styles.scss': 'p { color: darken(red, 10%) }',
'src/app/app.component.scss': 'p { color: darken(red, 10%) }',
});

await harness.modifyFile('src/app/app.component.ts', (content) => {
return content.replace('./app.component.css', 'app.component.scss');
});

harness.useTarget('build', {
...BASE_OPTIONS,
styles: ['src/styles.scss'],
stylePreprocessorOptions: {
sass: {},
},
});

const { result } = await harness.executeOnce();

expect(result?.success).toBeTrue();
});

it('should cause the build to fail when using `fatalDeprecations` in component styles', async () => {
await harness.modifyFile('src/app/app.component.ts', (content) => {
return content.replace('./app.component.css', 'app.component.scss');
});

await harness.writeFile('src/app/app.component.scss', 'p { color: darken(red, 10%) }');

harness.useTarget('build', {
...BASE_OPTIONS,
stylePreprocessorOptions: {
sass: {
fatalDeprecations: ['color-functions'],
},
},
});

const { result, logs } = await harness.executeOnce({
outputLogsOnFailure: false,
});

expect(result?.success).toBeFalse();
expect(logs).not.toContain(
jasmine.objectContaining<logging.LogEntry>({
message: jasmine.stringMatching('darken() is deprecated'),
}),
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ export function createCompilerPluginOptions(
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
outputNames,
includePaths: stylePreprocessorOptions?.includePaths,
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sass: stylePreprocessorOptions?.sass as any,
externalDependencies,
target,
inlineStyleLanguage,
Expand Down
3 changes: 3 additions & 0 deletions packages/angular/build/src/tools/esbuild/global-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ export function createGlobalStylesBundleOptions(
bundles: '[name]',
},
includePaths: stylePreprocessorOptions?.includePaths,
// string[] | undefined' is not assignable to type '(Version | DeprecationOrId)[] | undefined'.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sass: stylePreprocessorOptions?.sass as any,
tailwindConfiguration,
postcssConfiguration,
cacheOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { CssStylesheetLanguage } from './css-language';
import { createCssResourcePlugin } from './css-resource-plugin';
import { LessStylesheetLanguage } from './less-language';
import { SassStylesheetLanguage } from './sass-language';
import { StylesheetPluginFactory } from './stylesheet-plugin-factory';
import { StylesheetPluginFactory, StylesheetPluginsass } from './stylesheet-plugin-factory';

export interface BundleStylesheetOptions {
workspaceRoot: string;
Expand All @@ -26,6 +26,7 @@ export interface BundleStylesheetOptions {
sourcemap: boolean | 'external' | 'inline' | 'linked';
outputNames: { bundles: string; media: string };
includePaths?: string[];
sass?: StylesheetPluginsass;
externalDependencies?: string[];
target: string[];
tailwindConfiguration?: { file: string; package: string };
Expand All @@ -51,6 +52,7 @@ export function createStylesheetBundleOptions(
inlineComponentData,
tailwindConfiguration: options.tailwindConfiguration,
postcssConfiguration: options.postcssConfiguration,
sass: options.sass,
},
cache,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ async function compileString(
// failing resolution attempts.
const resolutionCache = new MemoryCache<URL | null>();
const packageRootCache = new MemoryCache<string | null>();

const warnings: PartialMessage[] = [];
const { silenceDeprecations, futureDeprecations, fatalDeprecations } = options.sass ?? {};

try {
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
url: pathToFileURL(filePath),
Expand All @@ -104,6 +105,9 @@ async function compileString(
loadPaths: options.includePaths,
sourceMap: options.sourcemap,
sourceMapIncludeSources: options.sourcemap,
silenceDeprecations,
fatalDeprecations,
futureDeprecations,
quietDeps: true,
importers: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@ import glob from 'fast-glob';
import assert from 'node:assert';
import { readFile } from 'node:fs/promises';
import { extname } from 'node:path';
import type { Options } from 'sass';
import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
import { LoadResultCache, createCachedLoad } from '../load-result-cache';

/**
* Configuration options for handling Sass-specific deprecations in a stylesheet plugin.
*/
export type StylesheetPluginsass = Pick<
Options<'async'>,
'futureDeprecations' | 'fatalDeprecations' | 'silenceDeprecations'
>;

/**
* Convenience type for a postcss processor.
*/
Expand Down Expand Up @@ -60,6 +69,11 @@ export interface StylesheetPluginOptions {
* and any tailwind usage must be manually configured in the custom postcss usage.
*/
postcssConfiguration?: PostcssConfiguration;

/**
* Optional Options for configuring Sass behavior.
*/
sass?: StylesheetPluginsass;
}

/**
Expand Down