Skip to content

Commit

Permalink
build: Refactor styles and themes build pipeline (#1390)
Browse files Browse the repository at this point in the history
Cherry-picked from #1374
  • Loading branch information
rkaraivanov authored Sep 18, 2024
1 parent 794ee5f commit c5d25a7
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 94 deletions.
41 changes: 16 additions & 25 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/// <reference types="vite/client" />

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

type ThemeImport = { default: string };
type ThemeImport = { styles: CSSResult };

const themes = import.meta.glob<ThemeImport>('../src/styles/themes/**/*.scss', {
query: '?inline',
});

const getTheme = async ({ theme, variant }) => {
const matcher = `../src/styles/themes/${variant}/${theme}.scss`;
const themes = import.meta.glob<ThemeImport>(
'../src/styles/themes/**/*.css.ts',
{
eager: true,
import: 'styles',
}
);

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

const stylesheet = await resolver();
return stylesheet.default;
for (const [path, styles] of Object.entries(themes)) {
if (path === matcher) {
return styles;
}
}
};

const getSize = (size: 'small' | 'medium' | 'large' | 'default') => {
Expand Down Expand Up @@ -81,22 +84,10 @@ export const globalTypes = {
},
};

const parser = new DOMParser();

export const parameters = {
backgrounds: {
disable: true,
},
docs: {
source: {
// Strip theme styles and wrapping container from the code preview
transform: (code: string) =>
parser.parseFromString(code, 'text/html').querySelector('#igc-story')
?.innerHTML,
format: 'html',
language: 'html',
},
},
};

export const loaders = [
Expand Down
66 changes: 2 additions & 64 deletions scripts/build-styles.mjs
Original file line number Diff line number Diff line change
@@ -1,65 +1,3 @@
import { mkdirSync as makeDir } from 'node:fs';
import { writeFile } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { globby } from 'globby';
import * as sass from 'sass-embedded';
import report from './report.mjs';
import { compileSass, fromTemplate } from './sass.mjs';
import { buildComponents, buildThemes } from './sass.mjs';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DEST_DIR = path.join.bind(null, path.resolve(__dirname, '../dist'));

export async function buildThemes() {
const compiler = await sass.initAsyncCompiler();
const paths = await globby('src/styles/themes/{light,dark}/*.scss');

for (const sassFile of paths) {
const css = await compileSass(sassFile, compiler);

const outputFile = DEST_DIR(
sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
);
makeDir(path.dirname(outputFile), { recursive: true });
await writeFile(outputFile, css, 'utf-8');
}

await compiler.dispose();
}

(async () => {
const compiler = await sass.initAsyncCompiler();
const start = performance.now();

const paths = await globby([
'src/components/**/*.base.scss',
'src/components/**/*.common.scss',
'src/components/**/*.shared.scss',
'src/components/**/*.material.scss',
'src/components/**/*.bootstrap.scss',
'src/components/**/*.indigo.scss',
'src/components/**/*.fluent.scss',
]);

try {
await Promise.all(
paths.map(async (path) => {
writeFile(
path.replace(/\.scss$/, '.css.ts'),
fromTemplate(await compileSass(path, compiler)),
'utf8'
);
})
);
} catch (err) {
await compiler.dispose();
report.error(err);
process.exit(1);
}

await compiler.dispose();

report.success(
`Styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
);
})();
await Promise.all([buildThemes(), buildComponents()]);
7 changes: 3 additions & 4 deletions scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {
getVsCodeHtmlCustomData,
} from 'custom-element-vs-code-integration';
import customElements from '../custom-elements.json' assert { type: 'json' };
import { buildThemes } from './build-styles.mjs';
import report from './report.mjs';
import { buildComponents, buildThemes } from './sass.mjs';

const exec = promisify(_exec);

Expand Down Expand Up @@ -39,7 +39,8 @@ async function runTask(tag, cmd) {

(async () => {
await runTask('Clean up', () => exec('npm run clean'));
await runTask('Styles', () => exec('npm run build:styles'));
await runTask('Component styles', () => buildComponents(true));
await runTask('Themes', () => buildThemes(true));

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

await runTask('Themes', buildThemes);

await runTask('Copying release files', () =>
Promise.all([
copyFile('scripts/_package.json', DEST_DIR('package.json')),
Expand Down
96 changes: 95 additions & 1 deletion scripts/sass.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { readFile } from 'node:fs/promises';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import autoprefixer from 'autoprefixer';
import { globby } from 'globby';
import postcss from 'postcss';
import * as sass from 'sass-embedded';
import report from './report.mjs';

const toDist = path.join.bind(
null,
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../dist')
);

const stripComments = () => {
return {
Expand Down Expand Up @@ -32,3 +42,87 @@ export async function compileSass(src, compiler) {
const out = _postProcessor.process(compiled.css).css;
return out.charCodeAt(0) === 0xfeff ? out.slice(1) : out;
}

export async function buildThemes(isProduction = false) {
const start = performance.now();

const [compiler, paths] = await Promise.all([
sass.initAsyncCompiler(),
globby('src/styles/themes/{light,dark}/*.scss'),
]);

try {
await Promise.all(
paths.map(async (sassFile) => {
const outputFile = isProduction
? toDist(
sassFile.replace(/\.scss$/, '.css').replace('src/styles/', '')
)
: sassFile.replace(/\.scss$/, '.css.ts');

if (isProduction) {
await mkdir(path.dirname(outputFile), { recursive: true });
writeFile(outputFile, await compileSass(sassFile, compiler), 'utf-8');
} else {
writeFile(
outputFile,
fromTemplate(await compileSass(sassFile, compiler)),
'utf-8'
);
}
})
);
} catch (err) {
await compiler.dispose();
report.error(err);
process.exit(1);
}

await compiler.dispose();

if (!isProduction) {
report.success(
`Themes generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
);
}
}

export async function buildComponents(isProduction = false) {
const start = performance.now();
const [compiler, paths] = await Promise.all([
sass.initAsyncCompiler(),
globby([
'src/components/**/*.base.scss',
'src/components/**/*.common.scss',
'src/components/**/*.shared.scss',
'src/components/**/*.material.scss',
'src/components/**/*.bootstrap.scss',
'src/components/**/*.indigo.scss',
'src/components/**/*.fluent.scss',
]),
]);

try {
await Promise.all(
paths.map(async (path) =>
writeFile(
path.replace(/\.scss$/, '.css.ts'),
fromTemplate(await compileSass(path, compiler)),
'utf-8'
)
)
);
} catch (err) {
await compiler.dispose();
report.error(err);
process.exit(1);
}

await compiler.dispose();

if (!isProduction) {
report.success(
`Component styles generated in ${((performance.now() - start) / 1000).toFixed(2)}s`
);
}
}

0 comments on commit c5d25a7

Please sign in to comment.