Skip to content

Commit c5d25a7

Browse files
authored
build: Refactor styles and themes build pipeline (#1390)
Cherry-picked from #1374
1 parent 794ee5f commit c5d25a7

File tree

4 files changed

+116
-94
lines changed

4 files changed

+116
-94
lines changed

.storybook/preview.ts

+16-25
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="vite/client" />
22

3-
import { html } from 'lit';
3+
import { type CSSResult, html } from 'lit';
44
import { configureTheme } from '../src/theming/config';
55
import type { Decorator } from '@storybook/web-components';
66
import { withActions } from '@storybook/addon-actions/decorator';
@@ -11,21 +11,24 @@ configureActions({
1111
limit: 5,
1212
});
1313

14-
type ThemeImport = { default: string };
14+
type ThemeImport = { styles: CSSResult };
1515

16-
const themes = import.meta.glob<ThemeImport>('../src/styles/themes/**/*.scss', {
17-
query: '?inline',
18-
});
19-
20-
const getTheme = async ({ theme, variant }) => {
21-
const matcher = `../src/styles/themes/${variant}/${theme}.scss`;
16+
const themes = import.meta.glob<ThemeImport>(
17+
'../src/styles/themes/**/*.css.ts',
18+
{
19+
eager: true,
20+
import: 'styles',
21+
}
22+
);
2223

23-
const [_, resolver] = Object.entries(themes).find(([path]) => {
24-
return path.match(matcher);
25-
})!;
24+
const getTheme = ({ theme, variant }) => {
25+
const matcher = `../src/styles/themes/${variant}/${theme}.css.ts`;
2626

27-
const stylesheet = await resolver();
28-
return stylesheet.default;
27+
for (const [path, styles] of Object.entries(themes)) {
28+
if (path === matcher) {
29+
return styles;
30+
}
31+
}
2932
};
3033

3134
const getSize = (size: 'small' | 'medium' | 'large' | 'default') => {
@@ -81,22 +84,10 @@ export const globalTypes = {
8184
},
8285
};
8386

84-
const parser = new DOMParser();
85-
8687
export const parameters = {
8788
backgrounds: {
8889
disable: true,
8990
},
90-
docs: {
91-
source: {
92-
// Strip theme styles and wrapping container from the code preview
93-
transform: (code: string) =>
94-
parser.parseFromString(code, 'text/html').querySelector('#igc-story')
95-
?.innerHTML,
96-
format: 'html',
97-
language: 'html',
98-
},
99-
},
10091
};
10192

10293
export const loaders = [

scripts/build-styles.mjs

+2-64
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,3 @@
1-
import { mkdirSync as makeDir } from 'node:fs';
2-
import { writeFile } from 'node:fs/promises';
3-
import path from 'node:path';
4-
import { fileURLToPath } from 'node:url';
5-
import { globby } from 'globby';
6-
import * as sass from 'sass-embedded';
7-
import report from './report.mjs';
8-
import { compileSass, fromTemplate } from './sass.mjs';
1+
import { buildComponents, buildThemes } from './sass.mjs';
92

10-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
11-
const DEST_DIR = path.join.bind(null, path.resolve(__dirname, '../dist'));
12-
13-
export async function buildThemes() {
14-
const compiler = await sass.initAsyncCompiler();
15-
const paths = await globby('src/styles/themes/{light,dark}/*.scss');
16-
17-
for (const sassFile of paths) {
18-
const css = await compileSass(sassFile, compiler);
19-
20-
const outputFile = DEST_DIR(
21-
sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
22-
);
23-
makeDir(path.dirname(outputFile), { recursive: true });
24-
await writeFile(outputFile, css, 'utf-8');
25-
}
26-
27-
await compiler.dispose();
28-
}
29-
30-
(async () => {
31-
const compiler = await sass.initAsyncCompiler();
32-
const start = performance.now();
33-
34-
const paths = await globby([
35-
'src/components/**/*.base.scss',
36-
'src/components/**/*.common.scss',
37-
'src/components/**/*.shared.scss',
38-
'src/components/**/*.material.scss',
39-
'src/components/**/*.bootstrap.scss',
40-
'src/components/**/*.indigo.scss',
41-
'src/components/**/*.fluent.scss',
42-
]);
43-
44-
try {
45-
await Promise.all(
46-
paths.map(async (path) => {
47-
writeFile(
48-
path.replace(/\.scss$/, '.css.ts'),
49-
fromTemplate(await compileSass(path, compiler)),
50-
'utf8'
51-
);
52-
})
53-
);
54-
} catch (err) {
55-
await compiler.dispose();
56-
report.error(err);
57-
process.exit(1);
58-
}
59-
60-
await compiler.dispose();
61-
62-
report.success(
63-
`Styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
64-
);
65-
})();
3+
await Promise.all([buildThemes(), buildComponents()]);

scripts/build.mjs

+3-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
getVsCodeHtmlCustomData,
1010
} from 'custom-element-vs-code-integration';
1111
import customElements from '../custom-elements.json' assert { type: 'json' };
12-
import { buildThemes } from './build-styles.mjs';
1312
import report from './report.mjs';
13+
import { buildComponents, buildThemes } from './sass.mjs';
1414

1515
const exec = promisify(_exec);
1616

@@ -39,7 +39,8 @@ async function runTask(tag, cmd) {
3939

4040
(async () => {
4141
await runTask('Clean up', () => exec('npm run clean'));
42-
await runTask('Styles', () => exec('npm run build:styles'));
42+
await runTask('Component styles', () => buildComponents(true));
43+
await runTask('Themes', () => buildThemes(true));
4344

4445
// https://github.com/microsoft/TypeScript/issues/14619
4546
await runTask('Components', () =>
@@ -48,8 +49,6 @@ async function runTask(tag, cmd) {
4849
)
4950
);
5051

51-
await runTask('Themes', buildThemes);
52-
5352
await runTask('Copying release files', () =>
5453
Promise.all([
5554
copyFile('scripts/_package.json', DEST_DIR('package.json')),

scripts/sass.mjs

+95-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1-
import { readFile } from 'node:fs/promises';
1+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
2+
import path from 'node:path';
23
import { resolve } from 'node:path';
4+
import { fileURLToPath } from 'node:url';
35
import autoprefixer from 'autoprefixer';
6+
import { globby } from 'globby';
47
import postcss from 'postcss';
8+
import * as sass from 'sass-embedded';
9+
import report from './report.mjs';
10+
11+
const toDist = path.join.bind(
12+
null,
13+
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../dist')
14+
);
515

616
const stripComments = () => {
717
return {
@@ -32,3 +42,87 @@ export async function compileSass(src, compiler) {
3242
const out = _postProcessor.process(compiled.css).css;
3343
return out.charCodeAt(0) === 0xfeff ? out.slice(1) : out;
3444
}
45+
46+
export async function buildThemes(isProduction = false) {
47+
const start = performance.now();
48+
49+
const [compiler, paths] = await Promise.all([
50+
sass.initAsyncCompiler(),
51+
globby('src/styles/themes/{light,dark}/*.scss'),
52+
]);
53+
54+
try {
55+
await Promise.all(
56+
paths.map(async (sassFile) => {
57+
const outputFile = isProduction
58+
? toDist(
59+
sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
60+
)
61+
: sassFile.replace(/\.scss$/, '.css.ts');
62+
63+
if (isProduction) {
64+
await mkdir(path.dirname(outputFile), { recursive: true });
65+
writeFile(outputFile, await compileSass(sassFile, compiler), 'utf-8');
66+
} else {
67+
writeFile(
68+
outputFile,
69+
fromTemplate(await compileSass(sassFile, compiler)),
70+
'utf-8'
71+
);
72+
}
73+
})
74+
);
75+
} catch (err) {
76+
await compiler.dispose();
77+
report.error(err);
78+
process.exit(1);
79+
}
80+
81+
await compiler.dispose();
82+
83+
if (!isProduction) {
84+
report.success(
85+
`Themes generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
86+
);
87+
}
88+
}
89+
90+
export async function buildComponents(isProduction = false) {
91+
const start = performance.now();
92+
const [compiler, paths] = await Promise.all([
93+
sass.initAsyncCompiler(),
94+
globby([
95+
'src/components/**/*.base.scss',
96+
'src/components/**/*.common.scss',
97+
'src/components/**/*.shared.scss',
98+
'src/components/**/*.material.scss',
99+
'src/components/**/*.bootstrap.scss',
100+
'src/components/**/*.indigo.scss',
101+
'src/components/**/*.fluent.scss',
102+
]),
103+
]);
104+
105+
try {
106+
await Promise.all(
107+
paths.map(async (path) =>
108+
writeFile(
109+
path.replace(/\.scss$/, '.css.ts'),
110+
fromTemplate(await compileSass(path, compiler)),
111+
'utf-8'
112+
)
113+
)
114+
);
115+
} catch (err) {
116+
await compiler.dispose();
117+
report.error(err);
118+
process.exit(1);
119+
}
120+
121+
await compiler.dispose();
122+
123+
if (!isProduction) {
124+
report.success(
125+
`Component styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
126+
);
127+
}
128+
}

0 commit comments

Comments
 (0)