Skip to content

Commit 11dc507

Browse files
authored
[heft-sass] (BREAKING CHANGE) Use JS shims; [load-themed-styles] Support CSS Variables (#5140)
* [load-themed-styles] Support using CSS variables instead * [heft] Add `globAsync` to task run options * [heft-sass] (BREAKING CHANGE) Emit .js shims Remove `preserveSCSSExtension` option. * [heft-sass] Generalize CSS postprocess * [heft-load-themed-styles] Add new plugin for theme token conversion * (chore) Update readme * [sass] Fixup changefile * (chore) rush update * [sass] Remove unused variable * (chore) add file extensions in heft-plugin.json * [sass] Update logging, serialize writes * [sass] Remove importIncludePaths * [load-themed-styles] Fix and add unit tests * (chore) rush update * (chore) Add lib-dts and lib-esm to standard .gitignore * [load-themed-styles] Update package layout * [sass-load-styles] Minor fixes * [sass] Reorder fields * (chore) rename hook * [sass] Fix shims for non-module * [sass-test] Add snapshot tests * [sass] Fix excludeFiles * (chore) rush update * Put hooks in nested object --------- Co-authored-by: David Michon <[email protected]>
1 parent cebf263 commit 11dc507

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2442
-431
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ common/autoinstallers/*/.npmrc
110110
temp/
111111
lib/
112112
lib-amd/
113+
lib-dts/
113114
lib-es6/
115+
lib-esm/
114116
lib-esnext/
115117
lib-commonjs/
116118
lib-shim/

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ These GitHub repositories provide supplementary resources for Rush Stack:
6868
| [/heft-plugins/heft-jest-plugin](./heft-plugins/heft-jest-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin) | [changelog](./heft-plugins/heft-jest-plugin/CHANGELOG.md) | [@rushstack/heft-jest-plugin](https://www.npmjs.com/package/@rushstack/heft-jest-plugin) |
6969
| [/heft-plugins/heft-lint-plugin](./heft-plugins/heft-lint-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin) | [changelog](./heft-plugins/heft-lint-plugin/CHANGELOG.md) | [@rushstack/heft-lint-plugin](https://www.npmjs.com/package/@rushstack/heft-lint-plugin) |
7070
| [/heft-plugins/heft-localization-typings-plugin](./heft-plugins/heft-localization-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin) | [changelog](./heft-plugins/heft-localization-typings-plugin/CHANGELOG.md) | [@rushstack/heft-localization-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-localization-typings-plugin) |
71+
| [/heft-plugins/heft-sass-load-themed-styles-plugin](./heft-plugins/heft-sass-load-themed-styles-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin) | [changelog](./heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md) | [@rushstack/heft-sass-load-themed-styles-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-load-themed-styles-plugin) |
7172
| [/heft-plugins/heft-sass-plugin](./heft-plugins/heft-sass-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin) | [changelog](./heft-plugins/heft-sass-plugin/CHANGELOG.md) | [@rushstack/heft-sass-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-plugin) |
7273
| [/heft-plugins/heft-serverless-stack-plugin](./heft-plugins/heft-serverless-stack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin) | [changelog](./heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md) | [@rushstack/heft-serverless-stack-plugin](https://www.npmjs.com/package/@rushstack/heft-serverless-stack-plugin) |
7374
| [/heft-plugins/heft-storybook-plugin](./heft-plugins/heft-storybook-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin) | [changelog](./heft-plugins/heft-storybook-plugin/CHANGELOG.md) | [@rushstack/heft-storybook-plugin](https://www.npmjs.com/package/@rushstack/heft-storybook-plugin) |

apps/heft/src/operations/runners/TaskOperationRunner.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// See LICENSE in the project root for license information.
33

44
import { createHash, type Hash } from 'node:crypto';
5+
import { glob } from 'fast-glob';
56

67
import {
78
type IOperationRunner,
@@ -159,7 +160,8 @@ export class TaskOperationRunner implements IOperationRunner {
159160
async (): Promise<OperationStatus> => {
160161
// Create the options and provide a utility method to obtain paths to copy
161162
const runHookOptions: IHeftTaskRunHookOptions = {
162-
abortSignal
163+
abortSignal,
164+
globAsync: glob
163165
};
164166

165167
// Run the plugin run hook

apps/heft/src/pluginFramework/HeftTaskSession.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { HeftParameterManager, IHeftParameters } from './HeftParameterManag
1111
import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin';
1212
import type { ICopyOperation } from '../plugins/CopyFilesPlugin';
1313
import type { HeftPluginHost } from './HeftPluginHost';
14-
import type { WatchGlobFn } from '../plugins/FileGlobSpecifier';
14+
import type { GlobFn, WatchGlobFn } from '../plugins/FileGlobSpecifier';
1515
import { InternalError } from '@rushstack/node-core-library';
1616
import type { IWatchFileSystem } from '../utilities/WatchFileSystemAdapter';
1717

@@ -169,6 +169,11 @@ export interface IHeftTaskRunHookOptions {
169169
* @beta
170170
*/
171171
readonly abortSignal: AbortSignal;
172+
173+
/**
174+
* Reads the specified globs and returns the result.
175+
*/
176+
readonly globAsync: GlobFn;
172177
}
173178

174179
/**

build-tests/heft-sass-test/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lib-css

build-tests/heft-sass-test/config/heft.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// TODO: Add comments
88
"phasesByName": {
99
"build": {
10-
"cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "temp"] }],
10+
"cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "lib-css", "temp"] }],
1111

1212
"tasksByName": {
1313
"set-browserslist-ignore-old-data-env-var": {
@@ -31,6 +31,12 @@
3131
"pluginPackage": "@rushstack/heft-sass-plugin"
3232
}
3333
},
34+
"sass-load-styles": {
35+
"taskDependencies": [],
36+
"taskPlugin": {
37+
"pluginPackage": "@rushstack/heft-sass-load-themed-styles-plugin"
38+
}
39+
},
3440
"typescript": {
3541
"taskDependencies": ["sass"],
3642
"taskPlugin": {

build-tests/heft-sass-test/config/rush-project.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"operationSettings": [
55
{
66
"operationName": "_phase:build",
7-
"outputFolderNames": ["lib", "dist", "temp/sass-ts"]
7+
"outputFolderNames": ["lib", "lib-css", "dist", "temp/sass-ts"]
88
},
99
{
1010
"operationName": "_phase:test",
+6-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
{
22
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",
33

4-
"cssOutputFolders": ["lib", "lib-commonjs"],
4+
"cssOutputFolders": [
5+
{ "folder": "lib", "shimModuleFormat": "esnext" },
6+
{ "folder": "lib-commonjs", "shimModuleFormat": "commonjs" },
7+
"lib-css"
8+
],
59
"secondaryGeneratedTsFolders": ["lib"],
610
"excludeFiles": ["./ignored1.scss", "ignored2.scss"],
711

8-
"silenceDeprecations": ["mixed-decls"]
12+
"silenceDeprecations": ["mixed-decls", "import", "global-builtin", "color-functions"]
913
}

build-tests/heft-sass-test/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
"@rushstack/heft-jest-plugin": "workspace:*",
1515
"@rushstack/heft-lint-plugin": "workspace:*",
1616
"@rushstack/heft-sass-plugin": "workspace:*",
17+
"@rushstack/heft-sass-load-themed-styles-plugin": "workspace:*",
1718
"@rushstack/heft-typescript-plugin": "workspace:*",
1819
"@rushstack/heft-webpack4-plugin": "workspace:*",
1920
"@rushstack/heft": "workspace:*",
2021
"@rushstack/webpack4-module-minifier-plugin": "workspace:*",
2122
"@types/heft-jest": "1.0.1",
23+
"@types/node": "20.17.19",
2224
"@types/react-dom": "17.0.25",
2325
"@types/react": "17.0.74",
2426
"@types/webpack-env": "1.18.8",

build-tests/heft-sass-test/src/stylesAltSyntax.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
// Testing SCSS syntax
7-
$marginValue: 20px;
7+
$marginValue: '[theme:normalMargin, default: 20px]';
88

99
.label {
1010
margin-bottom: $marginValue;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`SASS CJS Shims ignored1.scss: files 1`] = `Array []`;
4+
5+
exports[`SASS CJS Shims ignored2.scss: files 1`] = `Array []`;
6+
7+
exports[`SASS CJS Shims styles.sass: files 1`] = `
8+
Array [
9+
"styles.css",
10+
"styles.sass.js",
11+
]
12+
`;
13+
14+
exports[`SASS CJS Shims styles.sass: styles.css 1`] = `
15+
"/**
16+
* * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
17+
* * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
18+
* */
19+
/**
20+
* * This file is a SASS partial and therefore has no direct output file, but gets embedded into other files.
21+
* */
22+
.exampleImport {
23+
font-style: italic;
24+
color: darkcyan;
25+
}
26+
27+
html, body {
28+
margin: 0;
29+
height: 100%;
30+
background-color: #c0c0c0;
31+
font-family: Tahoma, sans-serif;
32+
}
33+
34+
.exampleApp {
35+
background-color: #ffffff;
36+
padding: 20px;
37+
border-radius: 5px;
38+
width: 400px;
39+
}
40+
41+
.exampleButton {
42+
display: inline-block;
43+
padding: 10px 20px;
44+
border: 0 solid transparent;
45+
font-size: 16px;
46+
line-height: 1.5;
47+
text-align: center;
48+
transition-duration: 0.4s;
49+
user-select: none;
50+
vertical-align: middle;
51+
transition-property: background-color, color, border-color;
52+
background-color: mediumorchid;
53+
border-color: mediumorchid;
54+
border-radius: 3px;
55+
color: #fff;
56+
}
57+
.exampleButton:not(:disabled):not([aria-disabled=true]) {
58+
cursor: pointer;
59+
}
60+
.exampleButton:hover, .exampleButton:focus {
61+
text-decoration: none;
62+
}
63+
.exampleButton:disabled, .exampleButton[aria-disabled=true] {
64+
box-shadow: none;
65+
}
66+
.exampleButton:hover {
67+
background-color: rgb(160.4485981308, 48.6878504673, 188.1121495327);
68+
border-color: rgb(160.4485981308, 48.6878504673, 188.1121495327);
69+
color: #fff;
70+
}
71+
.exampleButton:focus {
72+
outline: 2px dotted mediumorchid;
73+
outline-offset: 1px;
74+
}
75+
.exampleButton:disabled, .exampleButton[aria-disabled=true] {
76+
background-color: mediumorchid;
77+
border-color: mediumorchid;
78+
color: #fff;
79+
opacity: 0.7;
80+
}"
81+
`;
82+
83+
exports[`SASS CJS Shims styles.sass: styles.sass.js 1`] = `
84+
"module.exports = require(\\"./styles.css\\");
85+
module.exports.default = module.exports;"
86+
`;
87+
88+
exports[`SASS CJS Shims stylesAltSyntax.global.scss: files 1`] = `
89+
Array [
90+
"stylesAltSyntax.global.css",
91+
"stylesAltSyntax.global.scss.js",
92+
]
93+
`;
94+
95+
exports[`SASS CJS Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.css 1`] = `
96+
"/**
97+
* This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
98+
* Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
99+
*/
100+
.ms-label {
101+
margin-bottom: 20px;
102+
}"
103+
`;
104+
105+
exports[`SASS CJS Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.scss.js 1`] = `"require(\\"./stylesAltSyntax.global.css\\");"`;
106+
107+
exports[`SASS CJS Shims stylesAltSyntax.scss: files 1`] = `
108+
Array [
109+
"stylesAltSyntax.css",
110+
"stylesAltSyntax.global.css",
111+
"stylesAltSyntax.global.scss.js",
112+
"stylesAltSyntax.scss.js",
113+
]
114+
`;
115+
116+
exports[`SASS CJS Shims stylesAltSyntax.scss: stylesAltSyntax.css 1`] = `
117+
"/**
118+
* This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
119+
* Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
120+
*/
121+
.label {
122+
margin-bottom: var(--normalMargin, 20px);
123+
}"
124+
`;
125+
126+
exports[`SASS CJS Shims stylesAltSyntax.scss: stylesAltSyntax.global.css 1`] = `
127+
"/**
128+
* This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
129+
* Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
130+
*/
131+
.ms-label {
132+
margin-bottom: 20px;
133+
}"
134+
`;
135+
136+
exports[`SASS CJS Shims stylesAltSyntax.scss: stylesAltSyntax.global.scss.js 1`] = `"require(\\"./stylesAltSyntax.global.css\\");"`;
137+
138+
exports[`SASS CJS Shims stylesAltSyntax.scss: stylesAltSyntax.scss.js 1`] = `
139+
"module.exports = require(\\"./stylesAltSyntax.css\\");
140+
module.exports.default = module.exports;"
141+
`;
142+
143+
exports[`SASS CJS Shims stylesUseAltSyntax.scss: files 1`] = `
144+
Array [
145+
"stylesUseAltSyntax.css",
146+
"stylesUseAltSyntax.scss.js",
147+
]
148+
`;
149+
150+
exports[`SASS CJS Shims stylesUseAltSyntax.scss: stylesUseAltSyntax.css 1`] = `
151+
"/**
152+
* This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
153+
* Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
154+
*/
155+
/**
156+
* This file is a SASS partial and therefore has no direct output file,
157+
* but gets embedded into other files.
158+
*/
159+
/**
160+
* * * This file is used to verify that Sass imports using with configurable variable definition are successful.
161+
* * */
162+
:root {
163+
--list-margin-top: calc(1.25 * 1rem);
164+
}
165+
166+
.label {
167+
display: block;
168+
color: #4682ff;
169+
}
170+
171+
.exampleList {
172+
list-style-type: circle;
173+
margin-top: var(--list-margin-top);
174+
}
175+
.exampleListItem1 {
176+
color: deepskyblue;
177+
}
178+
.exampleListItem2 {
179+
background-color: dodgerblue;
180+
color: #e16f00;
181+
}
182+
.exampleListItem3 {
183+
background-color: #b7c274;
184+
color: darkslateblue;
185+
}"
186+
`;
187+
188+
exports[`SASS CJS Shims stylesUseAltSyntax.scss: stylesUseAltSyntax.scss.js 1`] = `
189+
"module.exports = require(\\"./stylesUseAltSyntax.css\\");
190+
module.exports.default = module.exports;"
191+
`;
192+
193+
exports[`SASS CJS Shims stylesUseSyntax.sass: files 1`] = `
194+
Array [
195+
"stylesUseSyntax.css",
196+
"stylesUseSyntax.sass.js",
197+
]
198+
`;
199+
200+
exports[`SASS CJS Shims stylesUseSyntax.sass: stylesUseSyntax.css 1`] = `
201+
"/**
202+
* * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder.
203+
* * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM.
204+
* */
205+
/**
206+
* This file is a SASS partial and therefore has no direct output file,
207+
* but gets embedded into other files.
208+
*/
209+
/**
210+
* * * This file is used to verify that Sass imports using with configurable variable definition are successful.
211+
* * */
212+
.exampleAnchor {
213+
display: inline-block;
214+
padding: 10px 20px;
215+
border: 0 solid transparent;
216+
font-size: 16px;
217+
line-height: 1.5;
218+
text-align: center;
219+
transition-duration: 0.4s;
220+
user-select: none;
221+
vertical-align: middle;
222+
transition-property: background-color, color, border-color;
223+
background-color: #7a717f;
224+
border-color: #7a717f;
225+
border-radius: 3px;
226+
color: #fff;
227+
}
228+
.exampleAnchor:not(:disabled):not([aria-disabled=true]) {
229+
cursor: pointer;
230+
}
231+
.exampleAnchor:hover, .exampleAnchor:focus {
232+
text-decoration: none;
233+
}
234+
.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] {
235+
box-shadow: none;
236+
}
237+
.exampleAnchor:hover {
238+
background-color: rgb(97.6, 90.4, 101.6);
239+
border-color: rgb(97.6, 90.4, 101.6);
240+
color: #fff;
241+
}
242+
.exampleAnchor:focus {
243+
outline: 2px dotted #7a717f;
244+
outline-offset: 1px;
245+
}
246+
.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] {
247+
background-color: #7a717f;
248+
border-color: #7a717f;
249+
color: #fff;
250+
opacity: 0.7;
251+
}"
252+
`;
253+
254+
exports[`SASS CJS Shims stylesUseSyntax.sass: stylesUseSyntax.sass.js 1`] = `
255+
"module.exports = require(\\"./stylesUseSyntax.css\\");
256+
module.exports.default = module.exports;"
257+
`;

0 commit comments

Comments
 (0)