mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-24 08:06:17 +08:00
feat(@angular/build): add sass
to stylePreprocessorOptions
in application builder
This commit introduces the functionality to configure a limited number of options for Sass processing in the Angular application builder. The following options have been added to enhance the Sass integration: - **futureDeprecations**: Specifies features that are scheduled for deprecation. The compiler will treat these as active and emit warnings as necessary. - **fatalDeprecations**: Identifies Sass features that are already deprecated and will cause build failures if used. - **silenceDeprecations**: This option suppresses deprecation warnings for specified versions. Usage example: ```json "architect": { "build": { "builder": "@angular-devkit/build-angular:application", "options": { "outputHashing": "none", "namedChunks": true, "stylePreprocessorOptions": { "sass": { "futureDeprecations": ["color-functions"], "fatalDeprecations": ["color-functions"], "silenceDeprecations": ["1.77.0"] } } } } } ``` For more information about these options, please refer to the Sass documentation: https://sass-lang.com/documentation/js-api/interfaces/options/ Closes #28587
This commit is contained in:
parent
3db1d81397
commit
b6951f4482
@ -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
|
||||
|
@ -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'),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
@ -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 };
|
||||
@ -51,6 +52,7 @@ export function createStylesheetBundleOptions(
|
||||
inlineComponentData,
|
||||
tailwindConfiguration: options.tailwindConfiguration,
|
||||
postcssConfiguration: options.postcssConfiguration,
|
||||
sass: options.sass,
|
||||
},
|
||||
cache,
|
||||
);
|
||||
|
@ -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),
|
||||
@ -104,6 +105,9 @@ async function compileString(
|
||||
loadPaths: options.includePaths,
|
||||
sourceMap: options.sourcemap,
|
||||
sourceMapIncludeSources: options.sourcemap,
|
||||
silenceDeprecations,
|
||||
fatalDeprecations,
|
||||
futureDeprecations,
|
||||
quietDeps: true,
|
||||
importers: [
|
||||
{
|
||||
|
@ -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.
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user