mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-24 16:16:27 +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"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"default": []
|
"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
|
"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,
|
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
|
||||||
outputNames,
|
outputNames,
|
||||||
includePaths: stylePreprocessorOptions?.includePaths,
|
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,
|
externalDependencies,
|
||||||
target,
|
target,
|
||||||
inlineStyleLanguage,
|
inlineStyleLanguage,
|
||||||
|
@ -63,6 +63,9 @@ export function createGlobalStylesBundleOptions(
|
|||||||
bundles: '[name]',
|
bundles: '[name]',
|
||||||
},
|
},
|
||||||
includePaths: stylePreprocessorOptions?.includePaths,
|
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,
|
tailwindConfiguration,
|
||||||
postcssConfiguration,
|
postcssConfiguration,
|
||||||
cacheOptions,
|
cacheOptions,
|
||||||
|
@ -16,7 +16,7 @@ import { CssStylesheetLanguage } from './css-language';
|
|||||||
import { createCssResourcePlugin } from './css-resource-plugin';
|
import { createCssResourcePlugin } from './css-resource-plugin';
|
||||||
import { LessStylesheetLanguage } from './less-language';
|
import { LessStylesheetLanguage } from './less-language';
|
||||||
import { SassStylesheetLanguage } from './sass-language';
|
import { SassStylesheetLanguage } from './sass-language';
|
||||||
import { StylesheetPluginFactory } from './stylesheet-plugin-factory';
|
import { StylesheetPluginFactory, StylesheetPluginsass } from './stylesheet-plugin-factory';
|
||||||
|
|
||||||
export interface BundleStylesheetOptions {
|
export interface BundleStylesheetOptions {
|
||||||
workspaceRoot: string;
|
workspaceRoot: string;
|
||||||
@ -26,6 +26,7 @@ export interface BundleStylesheetOptions {
|
|||||||
sourcemap: boolean | 'external' | 'inline' | 'linked';
|
sourcemap: boolean | 'external' | 'inline' | 'linked';
|
||||||
outputNames: { bundles: string; media: string };
|
outputNames: { bundles: string; media: string };
|
||||||
includePaths?: string[];
|
includePaths?: string[];
|
||||||
|
sass?: StylesheetPluginsass;
|
||||||
externalDependencies?: string[];
|
externalDependencies?: string[];
|
||||||
target: string[];
|
target: string[];
|
||||||
tailwindConfiguration?: { file: string; package: string };
|
tailwindConfiguration?: { file: string; package: string };
|
||||||
@ -51,6 +52,7 @@ export function createStylesheetBundleOptions(
|
|||||||
inlineComponentData,
|
inlineComponentData,
|
||||||
tailwindConfiguration: options.tailwindConfiguration,
|
tailwindConfiguration: options.tailwindConfiguration,
|
||||||
postcssConfiguration: options.postcssConfiguration,
|
postcssConfiguration: options.postcssConfiguration,
|
||||||
|
sass: options.sass,
|
||||||
},
|
},
|
||||||
cache,
|
cache,
|
||||||
);
|
);
|
||||||
|
@ -94,8 +94,9 @@ async function compileString(
|
|||||||
// failing resolution attempts.
|
// failing resolution attempts.
|
||||||
const resolutionCache = new MemoryCache<URL | null>();
|
const resolutionCache = new MemoryCache<URL | null>();
|
||||||
const packageRootCache = new MemoryCache<string | null>();
|
const packageRootCache = new MemoryCache<string | null>();
|
||||||
|
|
||||||
const warnings: PartialMessage[] = [];
|
const warnings: PartialMessage[] = [];
|
||||||
|
const { silenceDeprecations, futureDeprecations, fatalDeprecations } = options.sass ?? {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
|
const { css, sourceMap, loadedUrls } = await sassWorkerPool.compileStringAsync(data, {
|
||||||
url: pathToFileURL(filePath),
|
url: pathToFileURL(filePath),
|
||||||
@ -104,6 +105,9 @@ async function compileString(
|
|||||||
loadPaths: options.includePaths,
|
loadPaths: options.includePaths,
|
||||||
sourceMap: options.sourcemap,
|
sourceMap: options.sourcemap,
|
||||||
sourceMapIncludeSources: options.sourcemap,
|
sourceMapIncludeSources: options.sourcemap,
|
||||||
|
silenceDeprecations,
|
||||||
|
fatalDeprecations,
|
||||||
|
futureDeprecations,
|
||||||
quietDeps: true,
|
quietDeps: true,
|
||||||
importers: [
|
importers: [
|
||||||
{
|
{
|
||||||
|
@ -11,9 +11,18 @@ import glob from 'fast-glob';
|
|||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { readFile } from 'node:fs/promises';
|
import { readFile } from 'node:fs/promises';
|
||||||
import { extname } from 'node:path';
|
import { extname } from 'node:path';
|
||||||
|
import type { Options } from 'sass';
|
||||||
import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
import type { PostcssConfiguration } from '../../../utils/postcss-configuration';
|
||||||
import { LoadResultCache, createCachedLoad } from '../load-result-cache';
|
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.
|
* 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.
|
* and any tailwind usage must be manually configured in the custom postcss usage.
|
||||||
*/
|
*/
|
||||||
postcssConfiguration?: PostcssConfiguration;
|
postcssConfiguration?: PostcssConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional Options for configuring Sass behavior.
|
||||||
|
*/
|
||||||
|
sass?: StylesheetPluginsass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user