Skip to content

Commit

Permalink
Merge pull request #59 from mr150/refactor/jit-api
Browse files Browse the repository at this point in the history
Refactor/jit api
  • Loading branch information
mr150 committed Jun 18, 2024
2 parents 00b7359 + b4721bc commit a48c1f3
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 81 deletions.
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"stylelint": "^13.13.1",
"stylelint-order": "^4.0.0",
"ts-node": "^10.9.2",
"typescript": "~5.3.3",
"typescript": "^4.8.0",
"vinyl-ftp": "^0.6.1"
}
}
12 changes: 6 additions & 6 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mlut/core",
"version": "1.0.0",
"version": "2.0.0",
"description": "Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity",
"author": "mr150",
"type": "module",
Expand All @@ -27,10 +27,10 @@
"url": "https://github.com/mr150/mlut/issues"
},
"exports": {
".": {
"default": "./dist/index.js"
}
},
".": {
"default": "./dist/index.js"
}
},
"scripts": {
"build": "rm -rf dist && tsc && cp src/sass dist/ -r"
},
Expand All @@ -43,6 +43,6 @@
"@types/node": "^20.10.5",
"sass-embedded": "^1.71.0",
"sass": "^1.71.0",
"typescript": "^5.3.3"
"typescript": "^4.8.0"
}
}
79 changes: 38 additions & 41 deletions packages/core/src/jit/JitEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ const __dirname = new URL('.', import.meta.url).pathname;

export class JitEngine {
private utils = new Set<string>();
private inputFilePath = '';
private inputFileDir = __dirname;
private sassModuleName = 'tools';
private inputFileCache = '@use "../sass/tools";';
private generationDebounce: NodeJS.Timeout | undefined;
private readonly defaultSassConfig =
'@use "sass:map";\n @use "../sass/tools/settings" as ml;';
private readonly utilsByFile = new Map<string, string[]>();
Expand All @@ -39,59 +37,58 @@ export class JitEngine {
let sassConfig: string | undefined = this.defaultSassConfig;

if (inputPath && inputContent) {
this.inputFilePath = path.join(process.cwd(), inputPath);
this.inputFileDir = path.dirname(this.inputFilePath);
this.inputFileDir = path.dirname(path.resolve(process.cwd(), inputPath));
this.inputFileCache = inputContent;
sassConfig = this.extractUserSassConfig(inputContent);
}

await this.loadUtils(sassConfig);
}

async putAndGenerateCss(id: string, content: string): Promise<string | undefined> {
putContent(id: string, content: string | undefined) {
if (!content) {
return;
}

this.utilsByFile.set(id, this.extractUtils(content));
}

deleteContent(id: string): boolean {
return this.utilsByFile.delete(id);
}

async updateSassConfig(content: string): Promise<void> {
this.inputFileCache = content;
const sassConfig = this.extractUserSassConfig(content);

if (sassConfig) {
await this.loadUtils(sassConfig);
}
}

async generateCss(): Promise<string> {
if (this.utils.size === 0) {
logger.warn('Config with utilities is not loaded!');
return '';
}

if (id === this.inputFilePath) {
this.inputFileCache = content;
const sassConfig = this.extractUserSassConfig(content);

if (sassConfig) {
await this.loadUtils(sassConfig);
}
} else if (content) {
this.utilsByFile.set(id, this.extractUtils(content));
} else {
this.utilsByFile.delete(id);
if (this.utilsByFile.size === 0) {
logger.warn('No content to generate CSS was found!');
return '';
}

return new Promise((resolve) => {
//eslint-disable-next-line
let timeout: NodeJS.Timeout | undefined;
clearTimeout(this.generationDebounce);

this.generationDebounce = setTimeout(async () => {
clearTimeout(timeout);
const allUniqueUtils = [...new Set([...this.utilsByFile.values()].flat())];
const applyStr =
`\n@include ${this.sassModuleName}.apply(${JSON.stringify(allUniqueUtils)},(),true);`;

// `compileStringAsync` is almost always faster than `compile` in sass-embedded
const css = await sass.compileStringAsync(
this.inputFileCache + applyStr,
{ loadPaths: [ this.inputFileDir, 'node_modules' ] }
).then(
({ css }) => css,
(e) => (logger.error('Sass compilation error.', e), undefined),
);

resolve(css);
}, 100);

timeout = setTimeout(() => resolve(undefined), 300);
});
const allUniqueUtils = [...new Set([...this.utilsByFile.values()].flat())];
const applyStr =
`\n@include ${this.sassModuleName}.apply(${JSON.stringify(allUniqueUtils)},(),true);`;

// `compileStringAsync` is almost always faster than `compile` in sass-embedded
return sass.compileStringAsync(
this.inputFileCache + applyStr,
{ loadPaths: [ this.inputFileDir, 'node_modules' ] }
).then(
({ css }) => css,
(e) => (logger.error('Sass compilation error.', e), ''),
);
}

private extractUtils(content: string): string[] {
Expand Down
6 changes: 3 additions & 3 deletions packages/mlut/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mlut",
"version": "7.0.0",
"version": "7.0.1",
"description": "Atomic CSS toolkit with Sass and ergonomics for creating styles of any complexity",
"author": "mr150",
"type": "module",
Expand Down Expand Up @@ -45,10 +45,10 @@
"devDependencies": {
"@types/csso": "^5.0.4",
"@types/node": "^20.10.5",
"typescript": "^5.3.3"
"typescript": "^4.8.0"
},
"dependencies": {
"@mlut/core": "^1.0.0",
"@mlut/core": "^2.0.0",
"arg": "^5.0.2",
"csso": "^5.0.5",
"fast-glob": "^3.3.2",
Expand Down
37 changes: 19 additions & 18 deletions packages/mlut/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env node

import fs from 'node:fs';
import path from 'node:path';
import arg from 'arg';
import { minify } from 'csso';
import fg from 'fast-glob';
Expand Down Expand Up @@ -43,7 +44,7 @@ Options:
process.exit(0);
}

const inputPath = args['--input'];
const inputPath = args['--input'] && path.resolve(process.cwd(), args['--input']);
let inputContent = '';

if (inputPath) {
Expand Down Expand Up @@ -99,35 +100,35 @@ if (isWatch) {

void buildStyles(targetFiles, 'add');

async function generateStyles(path: string, content: string) {
const css = await jitEngine.putAndGenerateCss(path, content).then((css) => {
if (isMinify && css) {
return minify(css, { forceMediaMerge: isMergeMq }).css;
}

return css;
});

if (css !== undefined) {
return fs.promises.writeFile(outputPath, css)
.catch((e) => logger.error('Failed to write the output file.', e));
}
}

async function buildStyles(files: string[], event: TargetEvent) {
logger.info('Rebuilding styles...');
const startTime = Date.now();

await Promise.all(files.map(async (path) => {
if (event === 'unlink') {
return generateStyles(path, '');
return jitEngine.deleteContent(path);
}

return fs.promises.readFile(path)
.then((data) => generateStyles(path, data.toString()))
.then((data) => (
path === inputPath ?
jitEngine.updateSassConfig(data.toString()) :
jitEngine.putContent(path, data.toString())
))
.catch((e) => logger.error('Failed to read a content file.', e));
}));

const css = await jitEngine.generateCss().then((css) => {
if (isMinify && css) {
return minify(css, { forceMediaMerge: isMergeMq }).css;
}

return css;
});

await fs.promises.writeFile(outputPath, css)
.catch((e) => logger.error('Failed to write the output file.', e));

logger.info('Completed in', formatTime(Date.now() - startTime));
}

Expand Down
5 changes: 3 additions & 2 deletions test/jit/JitEngine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,11 @@ const wrapperCss = "M1u -Myvar12 Ps d-g";
}`;
/* eslint-enable */

void jit.putAndGenerateCss(htmlPath0, htmlContent0);
jit.putContent(htmlPath0, htmlContent0);
jit.putContent(htmlPath1, htmlContent1);

assert.equal(
await jit.putAndGenerateCss(htmlPath1, htmlContent1),
await jit.generateCss(),
cssOutput,
);
});
Expand Down

0 comments on commit a48c1f3

Please sign in to comment.