feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+2
View File
@@ -0,0 +1,2 @@
export { }
+2
View File
@@ -0,0 +1,2 @@
export { }
+45
View File
@@ -0,0 +1,45 @@
import process from 'node:process';
import { loadConfig } from '@unocss/config';
import { toArray } from '@unocss/core';
import { cac } from 'cac';
import { b as build, v as version, h as handleError } from './shared/cli.CIZMnhm9.mjs';
import 'node:fs';
import 'colorette';
import 'consola';
import 'pathe';
import 'perfect-debounce';
import 'tinyglobby';
import '@rollup/pluginutils';
import '@ampproject/remapping';
import 'magic-string';
import '@unocss/preset-uno';
async function startCli(cwd = process.cwd(), argv = process.argv, options = {}) {
const cli = cac("unocss");
cli.command("[...patterns]", "Glob patterns", {
ignoreOptionDefaultValue: true
}).option("-o, --out-file <file>", "Output file", {
default: cwd
}).option("--stdout", "Output to STDOUT", {
default: false
}).option("-c, --config [file]", "Config file").option("-w, --watch", "Watch for file changes").option("--write-transformed", "Update source files with transformed utilities", { default: false }).option("--preflights", "Enable preflights", { default: true }).option("-m, --minify", "Minify generated CSS", { default: false }).action(async (patterns, flags) => {
Object.assign(options, {
cwd,
...flags
});
if (patterns)
options.patterns = patterns;
const { config } = await loadConfig(cwd, options.config);
const entries = toArray(config.cli?.entry || options);
await Promise.all(entries.map((entry) => build({
...options,
...entry
})));
});
cli.help();
cli.version(version);
cli.parse(argv, { run: false });
await cli.runMatchedCommand();
}
startCli().catch(handleError);
+19
View File
@@ -0,0 +1,19 @@
/** Mark some properties as required, leaving others unchanged */
declare type MarkRequired<T, RK extends keyof T> = Exclude<T, RK> & Required<Pick<T, RK>>;
interface CliOptions {
cwd?: string;
patterns?: Array<string>;
outFile?: string;
watch?: boolean;
config?: string;
stdout?: boolean;
writeTransformed?: boolean;
preflights?: boolean;
minify?: boolean;
}
type ResolvedCliOptions = MarkRequired<CliOptions, 'patterns'>;
declare function resolveOptions(options: CliOptions): Promise<ResolvedCliOptions>;
declare function build(_options: CliOptions): Promise<void>;
export { build, resolveOptions };
+19
View File
@@ -0,0 +1,19 @@
/** Mark some properties as required, leaving others unchanged */
declare type MarkRequired<T, RK extends keyof T> = Exclude<T, RK> & Required<Pick<T, RK>>;
interface CliOptions {
cwd?: string;
patterns?: Array<string>;
outFile?: string;
watch?: boolean;
config?: string;
stdout?: boolean;
writeTransformed?: boolean;
preflights?: boolean;
minify?: boolean;
}
type ResolvedCliOptions = MarkRequired<CliOptions, 'patterns'>;
declare function resolveOptions(options: CliOptions): Promise<ResolvedCliOptions>;
declare function build(_options: CliOptions): Promise<void>;
export { build, resolveOptions };
+14
View File
@@ -0,0 +1,14 @@
import 'node:fs';
import 'node:process';
import '@unocss/core';
import 'colorette';
import 'consola';
import 'pathe';
import 'perfect-debounce';
import 'tinyglobby';
export { b as build, r as resolveOptions } from './shared/cli.CIZMnhm9.mjs';
import '@rollup/pluginutils';
import '@unocss/config';
import '@ampproject/remapping';
import 'magic-string';
import '@unocss/preset-uno';
+389
View File
@@ -0,0 +1,389 @@
import { promises, existsSync } from 'node:fs';
import process$1 from 'node:process';
import { cssIdRE, createGenerator, BetterMap, toArray } from '@unocss/core';
import { cyan, green, dim } from 'colorette';
import { consola } from 'consola';
import { resolve, dirname, relative, normalize, basename } from 'pathe';
import { debounce } from 'perfect-debounce';
import { glob } from 'tinyglobby';
import { createFilter } from '@rollup/pluginutils';
import { createRecoveryConfigLoader } from '@unocss/config';
import remapping from '@ampproject/remapping';
import MagicString from 'magic-string';
import presetUno from '@unocss/preset-uno';
const INCLUDE_COMMENT = "@unocss-include";
const IGNORE_COMMENT = "@unocss-ignore";
const CSS_PLACEHOLDER = "@unocss-placeholder";
const SKIP_START_COMMENT = "@unocss-skip-start";
const SKIP_END_COMMENT = "@unocss-skip-end";
const SKIP_COMMENT_RE = new RegExp(`(//\\s*?${SKIP_START_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_START_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_START_COMMENT}\\s*?-->)[\\s\\S]*?(//\\s*?${SKIP_END_COMMENT}\\s*?|\\/\\*\\s*?${SKIP_END_COMMENT}\\s*?\\*\\/|<!--\\s*?${SKIP_END_COMMENT}\\s*?-->)`, "g");
const defaultPipelineExclude = [cssIdRE];
const defaultPipelineInclude = [/\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/];
function deprecationCheck(config) {
let warned = false;
function warn(msg) {
warned = true;
console.warn(`[unocss] ${msg}`);
}
if (config.include)
warn("`include` option is deprecated, use `content.pipeline.include` instead.");
if (config.exclude)
warn("`exclude` option is deprecated, use `content.pipeline.exclude` instead.");
if (config.extraContent)
warn("`extraContent` option is deprecated, use `content` instead.");
if (config.content?.plain)
warn("`content.plain` option is renamed to `content.inline`.");
if (warned && typeof process !== "undefined" && process.env.CI)
throw new Error("deprecation warning");
}
function createContext(configOrPath, defaults = {}, extraConfigSources = [], resolveConfigResult = () => {
}) {
let root = process$1.cwd();
let rawConfig = {};
let configFileList = [];
let uno;
const _uno = createGenerator(rawConfig, defaults).then((r) => {
uno = r;
return r;
});
let rollupFilter = createFilter(
defaultPipelineInclude,
defaultPipelineExclude,
{ resolve: typeof configOrPath === "string" ? configOrPath : root }
);
const invalidations = [];
const reloadListeners = [];
const modules = new BetterMap();
const tokens = /* @__PURE__ */ new Set();
const tasks = [];
const affectedModules = /* @__PURE__ */ new Set();
const loadConfig = createRecoveryConfigLoader();
let ready = reloadConfig();
async function reloadConfig() {
await _uno;
const result = await loadConfig(root, configOrPath, extraConfigSources, defaults);
resolveConfigResult(result);
deprecationCheck(result.config);
rawConfig = result.config;
configFileList = result.sources;
await uno.setConfig(rawConfig);
uno.config.envMode = "dev";
rollupFilter = rawConfig.content?.pipeline === false ? () => false : createFilter(
rawConfig.content?.pipeline?.include || rawConfig.include || defaultPipelineInclude,
rawConfig.content?.pipeline?.exclude || rawConfig.exclude || defaultPipelineExclude,
{ resolve: typeof configOrPath === "string" ? configOrPath : root }
);
tokens.clear();
await Promise.all(modules.map((code, id) => uno.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens)));
invalidate();
dispatchReload();
return result;
}
async function updateRoot(newRoot) {
if (newRoot !== root) {
root = newRoot;
ready = reloadConfig();
}
return await ready;
}
function invalidate() {
invalidations.forEach((cb) => cb());
}
function dispatchReload() {
reloadListeners.forEach((cb) => cb());
}
async function extract(code, id) {
const uno2 = await _uno;
if (id)
modules.set(id, code);
const len = tokens.size;
await uno2.applyExtractors(code.replace(SKIP_COMMENT_RE, ""), id, tokens);
if (tokens.size > len)
invalidate();
}
function filter(code, id) {
if (code.includes(IGNORE_COMMENT))
return false;
return code.includes(INCLUDE_COMMENT) || code.includes(CSS_PLACEHOLDER) || rollupFilter(id.replace(/\?v=\w+$/, ""));
}
async function getConfig() {
await ready;
return rawConfig;
}
async function flushTasks() {
const _tasks = [...tasks];
await Promise.all(_tasks);
if (tasks[0] === _tasks[0])
tasks.splice(0, _tasks.length);
}
return {
get ready() {
return ready;
},
tokens,
modules,
affectedModules,
tasks,
flushTasks,
invalidate,
onInvalidate(fn) {
invalidations.push(fn);
},
filter,
reloadConfig,
onReload(fn) {
reloadListeners.push(fn);
},
get uno() {
if (!uno)
throw new Error("Run `await context.ready` before accessing `context.uno`");
return uno;
},
extract,
getConfig,
get root() {
return root;
},
updateRoot,
getConfigFileList: () => configFileList
};
}
function hash(str) {
let i;
let l;
let hval = 2166136261;
for (i = 0, l = str.length; i < l; i++) {
hval ^= str.charCodeAt(i);
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
}
return `00000${(hval >>> 0).toString(36)}`.slice(-6);
}
function transformSkipCode(code, map, SKIP_RULES_RE, keyFlag) {
for (const item of Array.from(code.matchAll(SKIP_RULES_RE))) {
if (item != null) {
const matched = item[0];
const withHashKey = `${keyFlag}${hash(matched)}`;
map.set(withHashKey, matched);
code = code.replace(matched, withHashKey);
}
}
return code;
}
function restoreSkipCode(code, map) {
for (const [withHashKey, matched] of map.entries())
code = code.replaceAll(withHashKey, matched);
return code;
}
async function applyTransformers(ctx, original, id, enforce = "default") {
if (original.includes(IGNORE_COMMENT))
return;
const transformers = (ctx.uno.config.transformers || []).filter((i) => (i.enforce || "default") === enforce);
if (!transformers.length)
return;
const skipMap = /* @__PURE__ */ new Map();
let code = original;
let s = new MagicString(transformSkipCode(code, skipMap, SKIP_COMMENT_RE, "@unocss-skip-placeholder-"));
const maps = [];
for (const t of transformers) {
if (t.idFilter) {
if (!t.idFilter(id))
continue;
} else if (!ctx.filter(code, id)) {
continue;
}
await t.transform(s, id, ctx);
if (s.hasChanged()) {
code = restoreSkipCode(s.toString(), skipMap);
maps.push(s.generateMap({ hires: true, source: id }));
s = new MagicString(code);
}
}
if (code !== original) {
return {
code,
map: remapping(maps, (_, ctx2) => {
ctx2.content = code;
return null;
})
};
}
}
const version = "0.65.4";
const defaultConfig = {
envMode: "build",
presets: [
presetUno()
]
};
class PrettyError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
if (typeof Error.captureStackTrace === "function")
Error.captureStackTrace(this, this.constructor);
else
this.stack = new Error(message).stack;
}
}
function handleError(error) {
if (error instanceof PrettyError)
consola.error(error.message);
process$1.exitCode = 1;
}
let watcher;
async function getWatcher(options) {
if (watcher && !options)
return watcher;
const { watch } = await import('chokidar');
const ignored = ["**/{.git,node_modules}/**"];
const newWatcher = watch(options?.patterns, {
ignoreInitial: true,
ignorePermissionErrors: true,
ignored,
cwd: options?.cwd || process$1.cwd()
});
watcher = newWatcher;
return newWatcher;
}
const name = "unocss";
async function resolveOptions(options) {
if (!options.patterns?.length) {
throw new PrettyError(
`No glob patterns, try ${cyan(`${name} <path/to/**/*>`)}`
);
}
return options;
}
async function build(_options) {
const fileCache = /* @__PURE__ */ new Map();
const cwd = _options.cwd || process$1.cwd();
const options = await resolveOptions(_options);
async function loadConfig() {
const ctx2 = createContext(options.config, defaultConfig);
const configSources2 = (await ctx2.updateRoot(cwd)).sources.map((i) => normalize(i));
return { ctx: ctx2, configSources: configSources2 };
}
const { ctx, configSources } = await loadConfig();
const files = await glob(options.patterns, { cwd, absolute: true, expandDirectories: false });
await Promise.all(
files.map(async (file) => {
fileCache.set(file, await promises.readFile(file, "utf8"));
})
);
if (options.stdout && options.outFile) {
consola.fatal(`Cannot use --stdout and --out-file at the same time`);
return;
}
consola.log(green(`${name} v${version}`));
if (options.watch)
consola.start("UnoCSS in watch mode...");
else
consola.start("UnoCSS for production...");
const debouncedBuild = debounce(
async () => {
generate(options).catch(handleError);
},
100
);
const startWatcher = async () => {
if (!options.watch)
return;
const { patterns } = options;
const watcher = await getWatcher(options);
if (configSources.length)
watcher.add(configSources);
watcher.on("all", async (type, file) => {
const absolutePath = resolve(cwd, file);
if (configSources.includes(absolutePath)) {
await ctx.reloadConfig();
if (configSources.length)
watcher.add(configSources);
consola.info(`${cyan(basename(file))} changed, setting new config`);
} else {
consola.log(`${green(type)} ${dim(file)}`);
if (type.startsWith("unlink"))
fileCache.delete(absolutePath);
else
fileCache.set(absolutePath, await promises.readFile(absolutePath, "utf8"));
}
debouncedBuild();
});
consola.info(
`Watching for changes in ${toArray(patterns).map((i) => cyan(i)).join(", ")}`
);
};
await generate(options);
await startWatcher().catch(handleError);
function transformFiles(sources, enforce = "default") {
return Promise.all(
sources.map(({ id, code, transformedCode }) => new Promise((resolve2) => {
applyTransformers(ctx, code, id, enforce).then((transformsRes) => {
resolve2({ id, code, transformedCode: transformsRes?.code || transformedCode });
});
}))
);
}
async function generate(options2) {
const sourceCache = Array.from(fileCache).map(([id, code]) => ({ id, code }));
const afterPreTrans = await transformFiles(sourceCache, "pre");
const afterDefaultTrans = await transformFiles(afterPreTrans);
const afterPostTrans = await transformFiles(afterDefaultTrans, "post");
if (options2.writeTransformed) {
await Promise.all(
afterPostTrans.filter(({ transformedCode }) => !!transformedCode).map(async ({ transformedCode, id }) => {
if (existsSync(id))
await promises.writeFile(id, transformedCode, "utf-8");
})
);
}
const tokens = /* @__PURE__ */ new Set();
for (const file of afterPostTrans) {
const { matched: matched2 } = await ctx.uno.generate(
(file.transformedCode || file.code).replace(SKIP_COMMENT_RE, ""),
{
preflights: false,
minify: true,
id: file.id
}
);
matched2.forEach((i) => tokens.add(i));
}
const { css, matched } = await ctx.uno.generate(
tokens,
{
preflights: options2.preflights,
minify: options2.minify
}
);
if (options2.stdout) {
process$1.stdout.write(css);
return;
}
const outFile = resolve(options2.cwd || process$1.cwd(), options2.outFile ?? "uno.css");
const dir = dirname(outFile);
if (!existsSync(dir))
await promises.mkdir(dir, { recursive: true });
await promises.writeFile(outFile, css, "utf-8");
if (!options2.watch) {
consola.success(
`${[...matched].length} utilities generated to ${cyan(
relative(process$1.cwd(), outFile)
)}
`
);
}
}
}
export { build as b, handleError as h, resolveOptions as r, version as v };