refactor(@angular-devkit/build-angular): remove support for Stylus

The usage of Stylus in the CLI is minimal and this package never reached version 1.

BREAKING CHANGE:

Deprecated support for Stylus has been removed. The Stylus package has never reached a stable version and its usage in the Angular CLI is minimal. It's recommended to migrate to another CSS preprocessor that the Angular CLI supports.
This commit is contained in:
Alan Agius 2022-09-16 11:51:27 +00:00 committed by Douglas Parker
parent 12931ba8c3
commit 2ba44a433c
17 changed files with 18 additions and 143 deletions

View File

@ -8,7 +8,6 @@ digraph G {
"*.css" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer"; "*.css" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer";
"*.scss\|sass" -> "sass-loader" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer"; "*.scss\|sass" -> "sass-loader" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer";
"*.less" -> "less-loader" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer"; "*.less" -> "less-loader" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer";
"*.styl" -> "stylus-loader" -> "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer";
"postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer" -> "raw-loader, ./optimize-css-webpack-plugin.ts" [label="component style?"]; "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer" -> "raw-loader, ./optimize-css-webpack-plugin.ts" [label="component style?"];
"raw-loader" -> "./optimize-css-webpack-plugin.ts" "raw-loader" -> "./optimize-css-webpack-plugin.ts"
"postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer" -> "style-loader, ./raw-css-loader.ts, and mini-css-extract-plugin" [label="global style?"]; "postcss-loader with postcss-import, ./postcss-cli-resources.ts, autoprefixer" -> "style-loader, ./raw-css-loader.ts, and mini-css-extract-plugin" [label="global style?"];

View File

@ -54,8 +54,8 @@ This is used for conditional loading of code at build time.
Two types of stylesheets are used in the build system: global stylesheets and component stylesheets. Two types of stylesheets are used in the build system: global stylesheets and component stylesheets.
Global stylesheets are injected into the `index.html` file, while component stylesheets are loaded directly into compiled Angular components. Global stylesheets are injected into the `index.html` file, while component stylesheets are loaded directly into compiled Angular components.
The build system supports plain CSS stylesheets as well as the Sass, LESS and Stylus CSS pre-processors. The build system supports plain CSS stylesheets as well as the Sass and LESS CSS pre-processors.
Stylesheet processing functionality is provided by `sass-loader`, `less-loader`, `stylus-loader`, `postcss-loader`, `postcss-import`, augmented in the build system by custom webpack plugins. Stylesheet processing functionality is provided by `sass-loader`, `less-loader`, `postcss-loader`, `postcss-import`, augmented in the build system by custom webpack plugins.
### Assets ### Assets

View File

@ -204,8 +204,6 @@
"source-map-loader": "4.0.0", "source-map-loader": "4.0.0",
"source-map-support": "0.5.21", "source-map-support": "0.5.21",
"spdx-satisfies": "^5.0.0", "spdx-satisfies": "^5.0.0",
"stylus": "0.59.0",
"stylus-loader": "7.0.0",
"symbol-observable": "4.0.0", "symbol-observable": "4.0.0",
"tar": "^6.1.6", "tar": "^6.1.6",
"terser": "5.15.0", "terser": "5.15.0",

View File

@ -170,8 +170,6 @@ ts_library(
"@npm//semver", "@npm//semver",
"@npm//source-map-loader", "@npm//source-map-loader",
"@npm//source-map-support", "@npm//source-map-support",
"@npm//stylus",
"@npm//stylus-loader",
"@npm//terser", "@npm//terser",
"@npm//text-table", "@npm//text-table",
"@npm//tree-kill", "@npm//tree-kill",

View File

@ -57,8 +57,6 @@
"semver": "7.3.7", "semver": "7.3.7",
"source-map-loader": "4.0.0", "source-map-loader": "4.0.0",
"source-map-support": "0.5.21", "source-map-support": "0.5.21",
"stylus": "0.59.0",
"stylus-loader": "7.0.0",
"terser": "5.15.0", "terser": "5.15.0",
"text-table": "0.2.0", "text-table": "0.2.0",
"tree-kill": "1.2.2", "tree-kill": "1.2.2",

View File

@ -72,7 +72,7 @@
"input": { "input": {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
}, },
"bundleName": { "bundleName": {
"type": "string", "type": "string",
@ -91,7 +91,7 @@
{ {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
} }
] ]
} }

View File

@ -72,7 +72,7 @@
"input": { "input": {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
}, },
"bundleName": { "bundleName": {
"type": "string", "type": "string",
@ -91,7 +91,7 @@
{ {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
} }
] ]
} }

View File

@ -13,8 +13,8 @@ import { dirname } from 'path';
import { browserBuild, createArchitect, host } from '../../../testing/test-utils'; import { browserBuild, createArchitect, host } from '../../../testing/test-utils';
describe('Browser Builder styles', () => { describe('Browser Builder styles', () => {
const extensionsWithImportSupport = ['css', 'scss', 'less', 'styl']; const extensionsWithImportSupport = ['css', 'scss', 'less'];
const extensionsWithVariableSupport = ['scss', 'less', 'styl']; const extensionsWithVariableSupport = ['scss', 'less'];
const imgSvg = ` const imgSvg = `
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" /> <circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
@ -223,9 +223,6 @@ describe('Browser Builder styles', () => {
if (ext === 'scss') { if (ext === 'scss') {
variableAssignment = '$primary-color:'; variableAssignment = '$primary-color:';
variablereference = '$primary-color'; variablereference = '$primary-color';
} else if (ext === 'styl') {
variableAssignment = '$primary-color =';
variablereference = '$primary-color';
} else if (ext === 'less') { } else if (ext === 'less') {
variableAssignment = '@primary-color:'; variableAssignment = '@primary-color:';
variablereference = '@primary-color'; variablereference = '@primary-color';

View File

@ -13,7 +13,7 @@ import { Type } from '../../schema';
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup'; import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup';
describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => { describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
const CSS_EXTENSIONS = ['css', 'scss', 'less', 'styl']; const CSS_EXTENSIONS = ['css', 'scss', 'less'];
const BUDGET_NOT_MET_REGEXP = /Budget .+ was not met by/; const BUDGET_NOT_MET_REGEXP = /Budget .+ was not met by/;
describe('Option: "bundleBudgets"', () => { describe('Option: "bundleBudgets"', () => {

View File

@ -58,29 +58,6 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
harness.expectFile('dist/main.js').content.toContain('color: green'); harness.expectFile('dist/main.js').content.toContain('color: green');
}); });
// Stylus currently does not function due to the sourcemap logic within the `stylus-loader`
// which tries to read each stylesheet directly from disk. In this case, each stylesheet is
// virtual and cannot be read from disk. This issue affects data URIs in general.
// xit('supports Stylus inline component styles when set to "stylus"', async () => {
// harness.useTarget('build', {
// ...BASE_OPTIONS,
// inlineStyleLanguage: InlineStyleLanguage.Stylus,
// aot,
// });
// await harness.modifyFile('src/app/app.component.ts', (content) =>
// content.replace(
// '__STYLE_MARKER__',
// '$primary = green;\\nh1 { color: $primary; }',
// ),
// );
// const { result } = await harness.executeOnce();
// expect(result?.success).toBe(true);
// harness.expectFile('dist/main.js').content.toContain('color: green');
// });
it('supports Less inline component styles when set to "less"', async () => { it('supports Less inline component styles when set to "less"', async () => {
harness.useTarget('build', { harness.useTarget('build', {
...BASE_OPTIONS, ...BASE_OPTIONS,

View File

@ -224,7 +224,7 @@ export async function execute(
module: { module: {
rules: [ rules: [
{ {
test: /\.(css|scss|sass|styl|less)$/, test: /\.(css|scss|sass|less)$/,
loader: require.resolve('./empty-loader'), loader: require.resolve('./empty-loader'),
}, },
], ],

View File

@ -76,7 +76,7 @@
"input": { "input": {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
}, },
"bundleName": { "bundleName": {
"type": "string", "type": "string",
@ -95,7 +95,7 @@
{ {
"type": "string", "type": "string",
"description": "The file to include.", "description": "The file to include.",
"pattern": "\\.(?:css|scss|sass|less|styl)$" "pattern": "\\.(?:css|scss|sass|less)$"
} }
] ]
} }

View File

@ -101,13 +101,6 @@ export function getStylesConfig(wco: WebpackConfigOptions): Configuration {
extraPlugins.push(new RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat })); extraPlugins.push(new RemoveHashPlugin({ chunkNames: noInjectNames, hashFormat }));
} }
if (globalStylePaths.some((p) => p.endsWith('.styl'))) {
wco.logger.warn(
'Stylus usage is deprecated and will be removed in a future major version. ' +
'To opt-out of the deprecated behaviour, please migrate to another stylesheet language.',
);
}
const sassImplementation = new SassWorkerImplementation(); const sassImplementation = new SassWorkerImplementation();
const sassTildeUsageMessage = new Set<string>(); const sassTildeUsageMessage = new Set<string>();
@ -366,22 +359,6 @@ export function getStylesConfig(wco: WebpackConfigOptions): Configuration {
}, },
], ],
}, },
{
extensions: ['styl'],
use: [
{
loader: require.resolve('stylus-loader'),
options: {
sourceMap: cssSourceMap,
stylusOptions: {
compress: false,
sourceMap: { comment: false },
paths: includePaths,
},
},
},
],
},
]; ];
return { return {

View File

@ -47,7 +47,7 @@ export class AnyComponentStyleBudgetChecker {
return; return;
} }
const cssExtensions = ['.css', '.scss', '.less', '.styl', '.sass']; const cssExtensions = ['.css', '.scss', '.less', '.sass'];
const componentStyles = Object.keys(compilation.assets) const componentStyles = Object.keys(compilation.assets)
.filter((name) => cssExtensions.includes(path.extname(name))) .filter((name) => cssExtensions.includes(path.extname(name)))

View File

@ -52,7 +52,7 @@ export class CssOptimizerPlugin {
logger.time('optimize css assets'); logger.time('optimize css assets');
for (const assetName of Object.keys(compilationAssets)) { for (const assetName of Object.keys(compilationAssets)) {
if (!/\.(?:css|scss|sass|less|styl)$/.test(assetName)) { if (!/\.(?:css|scss|sass|less)$/.test(assetName)) {
continue; continue;
} }

View File

@ -18,17 +18,6 @@ export default async function () {
@import 'variables'; @import 'variables';
h2 { background-color: $primary-color; } h2 { background-color: $primary-color; }
`, `,
'src/style-paths/variables.styl': '$primary-color = green',
'src/styles.styl': `
@import 'variables'
h3
color: $primary-color
`,
'src/app/app.component.styl': `
@import 'variables'
h4
background-color: $primary-color
`,
'src/style-paths/variables.less': '@primary-color: #ADDADD;', 'src/style-paths/variables.less': '@primary-color: #ADDADD;',
'src/styles.less': ` 'src/styles.less': `
@import 'variables'; @import 'variables';
@ -43,17 +32,14 @@ export default async function () {
await replaceInFile( await replaceInFile(
'src/app/app.component.ts', 'src/app/app.component.ts',
`'./app.component.css\'`, `'./app.component.css\'`,
`'./app.component.scss'` + (esbuild ? '' : `, './app.component.styl', './app.component.less'`), `'./app.component.scss'` + (esbuild ? '' : `, './app.component.less'`),
); );
await updateJsonFile('angular.json', (workspaceJson) => { await updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect; const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.scss' }]; appArchitect.build.options.styles = [{ input: 'src/styles.scss' }];
if (!esbuild) { if (!esbuild) {
appArchitect.build.options.styles.push( appArchitect.build.options.styles.push({ input: 'src/styles.less' });
{ input: 'src/styles.styl' },
{ input: 'src/styles.less' },
);
} }
appArchitect.build.options.stylePreprocessorOptions = { appArchitect.build.options.stylePreprocessorOptions = {
includePaths: ['src/style-paths'], includePaths: ['src/style-paths'],
@ -64,9 +50,7 @@ export default async function () {
await expectFileToMatch('dist/test-project/styles.css', /h1\s*{\s*color: red;\s*}/); await expectFileToMatch('dist/test-project/styles.css', /h1\s*{\s*color: red;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h2.*{.*color: red;.*}/); await expectFileToMatch('dist/test-project/main.js', /h2.*{.*color: red;.*}/);
if (!esbuild) { if (!esbuild) {
// These checks are for the less and stylus files // These checks are for the less files
await expectFileToMatch('dist/test-project/styles.css', /h3\s*{\s*color: #008000;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h4.*{.*color: #008000;.*}/);
await expectFileToMatch('dist/test-project/styles.css', /h5\s*{\s*color: #ADDADD;\s*}/); await expectFileToMatch('dist/test-project/styles.css', /h5\s*{\s*color: #ADDADD;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h6.*{.*color: #ADDADD;.*}/); await expectFileToMatch('dist/test-project/main.js', /h6.*{.*color: #ADDADD;.*}/);
} }
@ -77,8 +61,6 @@ export default async function () {
await expectFileToMatch('dist/test-project/styles.css', /h1\s*{\s*color: red;\s*}/); await expectFileToMatch('dist/test-project/styles.css', /h1\s*{\s*color: red;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h2.*{.*color: red;.*}/); await expectFileToMatch('dist/test-project/main.js', /h2.*{.*color: red;.*}/);
await expectFileToMatch('dist/test-project/styles.css', /h3\s*{\s*color: #008000;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h4.*{.*color: #008000;.*}/);
await expectFileToMatch('dist/test-project/styles.css', /h5\s*{\s*color: #ADDADD;\s*}/); await expectFileToMatch('dist/test-project/styles.css', /h5\s*{\s*color: #ADDADD;\s*}/);
await expectFileToMatch('dist/test-project/main.js', /h6.*{.*color: #ADDADD;.*}/); await expectFileToMatch('dist/test-project/main.js', /h6.*{.*color: #ADDADD;.*}/);
} }

View File

@ -1,51 +0,0 @@
import {
writeMultipleFiles,
deleteFile,
expectFileToMatch,
replaceInFile,
} from '../../../utils/fs';
import { expectToFail } from '../../../utils/utils';
import { ng } from '../../../utils/process';
import { updateJsonFile } from '../../../utils/project';
export default function () {
// TODO(architect): Delete this test. It is now in devkit/build-angular.
return writeMultipleFiles({
'src/styles.styl': `
@import './imported-styles.styl';
body { background-color: blue; }
`,
'src/imported-styles.styl': 'p { background-color: red; }',
'src/app/app.component.styl': `
.outer {
.inner {
background: #fff;
}
}
`,
})
.then(() => deleteFile('src/app/app.component.css'))
.then(() =>
updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.styl' }];
}),
)
.then(() =>
replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.styl'),
)
.then(() => ng('build', '--source-map', '--configuration=development'))
.then(() =>
expectFileToMatch('dist/test-project/styles.css', /body\s*{\s*background-color: #00f;\s*}/),
)
.then(() =>
expectFileToMatch('dist/test-project/styles.css', /p\s*{\s*background-color: #f00;\s*}/),
)
.then(() =>
expectToFail(() => expectFileToMatch('dist/test-project/styles.css', '"mappings":""')),
)
.then(() =>
expectFileToMatch('dist/test-project/main.js', /.outer.*.inner.*background:\s*#[fF]+/),
);
}