svelte-scoped-uno
Version:
Use UnoCSS utility styles in a modular fashion in Svelte, with styles being stored only where needed.
622 lines (592 loc) • 27.8 kB
JavaScript
;
const unocss = require('unocss');
const config = require('@unocss/config');
const MagicString = require('magic-string');
const cssTree = require('css-tree');
const node_fs = require('node:fs');
const node_path = require('node:path');
const node_url = require('node:url');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
const NOT_PRECEEDED_BY_DIGIT_OR_OPEN_PARENTHESIS_RE = /(?<![\d(])/;
const SELECTOR_STARTING_WITH_BRACKET_OR_PERIOD_RE = /([[\.][\S\s]+?)/;
const STYLES_RE = /({[\S\s]+?})/;
const EXTRACT_SELECTOR_RE = new RegExp(NOT_PRECEEDED_BY_DIGIT_OR_OPEN_PARENTHESIS_RE.source + SELECTOR_STARTING_WITH_BRACKET_OR_PERIOD_RE.source + STYLES_RE.source, "g");
function wrapSelectorsWithGlobal(css) {
return css.replace(EXTRACT_SELECTOR_RE, ":global($1)$2");
}
const classesRE$1 = /class=(["'\`])([\S\s]*?)\1/g;
const classDirectivesRE = /class:([\S]+?)={/g;
const classDirectivesShorthandRE = /class:([^=>\s/]+)[{>\s/]/g;
function findClasses(code) {
const matchedClasses = [...code.matchAll(classesRE$1)];
const matchedClassDirectives = [...code.matchAll(classDirectivesRE)];
const matchedClassDirectivesShorthand = [...code.matchAll(classDirectivesShorthandRE)];
const classes = parseMatches(matchedClasses, "regular", 'class="'.length);
const classDirectives = parseMatches(matchedClassDirectives, "directive", "class:".length);
const classDirectivesShorthand = parseMatches(matchedClassDirectivesShorthand, "directiveShorthand", "class:".length);
return [...classes, ...classDirectives, ...classDirectivesShorthand];
}
function parseMatches(matches, type, prefixLength) {
return matches.map((match) => {
const body = match[type === "regular" ? 2 : 1];
const start = match.index + prefixLength;
return {
body: body.trim(),
start,
end: start + body.length,
type
};
}).filter(hasBody);
}
function hasBody(foundClass) {
return foundClass.body;
}
const notInCommentRE = /(?<!<!--\s*)/;
const stylesTagWithCapturedDirectivesRE = /<style([^>]*)>[\s\S]*?<\/style\s*>/;
const actualStylesTagWithCapturedDirectivesRE = new RegExp(notInCommentRE.source + stylesTagWithCapturedDirectivesRE.source, "g");
const captureOpeningStyleTagWithAttributesRE = /(<style[^>]*>)/;
function addGeneratedStylesIntoStyleBlock(code, styles) {
const preExistingStylesTag = code.match(actualStylesTagWithCapturedDirectivesRE);
if (preExistingStylesTag)
return code.replace(captureOpeningStyleTagWithAttributesRE, `$1${styles}`);
return `${code}
<style>${styles}</style>`;
}
async function needsGenerated(token, uno) {
const inSafelist = uno.config.safelist.includes(token);
if (inSafelist)
return false;
const result = await uno.parseToken(token);
return !!result;
}
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 generateClassName(body, options, filename) {
const {
classPrefix = "uno-",
combine = true,
hashFn = hash
} = options;
if (combine) {
const classPlusFilenameHash = hashFn(body + filename);
return `${classPrefix}${classPlusFilenameHash}`;
} else {
const filenameHash = hashFn(filename);
return `_${body}_${filenameHash}`;
}
}
function isShortcut(token, shortcuts) {
return shortcuts.some((s) => s[0] === token);
}
async function processDirective({ body: token, start, end, type }, options, uno, filename) {
const isShortcutOrUtility = isShortcut(token, uno.config.shortcuts) || await needsGenerated(token, uno);
if (!isShortcutOrUtility)
return;
const generatedClassName = generateClassName(token, options, filename);
const content = type === "directiveShorthand" ? `${generatedClassName}={${token}}` : generatedClassName;
return {
rulesToGenerate: { [generatedClassName]: [token] },
codeUpdate: { content, start, end }
};
}
async function sortClassesIntoCategories(body, options, uno, filename) {
const { combine = true } = options;
const rulesToGenerate = {};
const ignore = [];
const classes = body.trim().split(/\s+/);
const knownClassesToCombine = [];
for (const token of classes) {
const isShortcutOrUtility = isShortcut(token, uno.config.shortcuts) || await needsGenerated(token, uno);
if (!isShortcutOrUtility) {
ignore.push(token);
continue;
}
if (combine) {
knownClassesToCombine.push(token);
} else {
const generatedClassName = generateClassName(token, options, filename);
rulesToGenerate[generatedClassName] = [token];
}
}
if (knownClassesToCombine.length) {
const generatedClassName = generateClassName(knownClassesToCombine.join(" "), options, filename);
rulesToGenerate[generatedClassName] = knownClassesToCombine;
}
return { rulesToGenerate, ignore };
}
const expressionsRE = /{[^{}]+?}/g;
const classesRE = /(["'\`])([\S\s]+?)\1/g;
async function processExpressions(body, options, uno, filename) {
const rulesToGenerate = {};
const updatedExpressions = [];
let restOfBody = body;
const expressions = [...body.matchAll(expressionsRE)];
for (let [expression] of expressions) {
restOfBody = restOfBody.replace(expression, "").trim();
const classes = [...expression.matchAll(classesRE)];
for (const [withQuotes, quoteMark, withoutQuotes] of classes) {
const { rulesToGenerate: rulesFromExpression, ignore } = await sortClassesIntoCategories(withoutQuotes, options, uno, filename);
Object.assign(rulesToGenerate, rulesFromExpression);
const updatedClasses = Object.keys(rulesFromExpression).concat(ignore).join(" ");
expression = expression.replace(withQuotes, quoteMark + updatedClasses + quoteMark);
}
updatedExpressions.push(expression);
}
return { rulesToGenerate, updatedExpressions, restOfBody };
}
async function processClassBody({ body, start, end }, options, uno, filename) {
const expandedBody = unocss.expandVariantGroup(body);
const { rulesToGenerate: rulesFromExpressions, restOfBody, updatedExpressions } = await processExpressions(expandedBody, options, uno, filename);
const { rulesToGenerate: rulesFromRegularClasses, ignore } = await sortClassesIntoCategories(restOfBody, options, uno, filename);
const rulesToGenerate = { ...rulesFromExpressions, ...rulesFromRegularClasses };
if (!Object.keys(rulesToGenerate).length)
return {};
const content = Object.keys(rulesFromRegularClasses).concat(ignore).concat(updatedExpressions).join(" ");
const codeUpdate = {
content,
start,
end
};
return { rulesToGenerate, codeUpdate };
}
async function processClasses(classes, options, uno, filename) {
const result = {
rulesToGenerate: {},
codeUpdates: []
};
for (const foundClass of classes) {
if (foundClass.type === "regular") {
const { rulesToGenerate, codeUpdate } = await processClassBody(foundClass, options, uno, filename);
if (rulesToGenerate)
Object.assign(result.rulesToGenerate, rulesToGenerate);
if (codeUpdate)
result.codeUpdates.push(codeUpdate);
} else {
const { rulesToGenerate, codeUpdate } = await processDirective(foundClass, options, uno, filename) || {};
if (rulesToGenerate)
Object.assign(result.rulesToGenerate, rulesToGenerate);
if (codeUpdate)
result.codeUpdates.push(codeUpdate);
}
}
return result;
}
async function transformClasses({ content, filename, uno, options }) {
const classesToProcess = findClasses(content);
if (!classesToProcess.length)
return;
const { rulesToGenerate, codeUpdates } = await processClasses(classesToProcess, options, uno, filename);
if (!Object.keys(rulesToGenerate).length)
return;
const { map, code } = updateTemplateCodeIfNeeded(codeUpdates, content, filename);
const generatedStyles = await generateStyles(rulesToGenerate, uno);
const codeWithGeneratedStyles = addGeneratedStylesIntoStyleBlock(code, generatedStyles);
return {
code: codeWithGeneratedStyles,
map
};
}
function updateTemplateCodeIfNeeded(codeUpdates, source, filename) {
if (!codeUpdates.length)
return { code: source, map: void 0 };
const s = new MagicString__default(source);
for (const { start, end, content } of codeUpdates)
s.overwrite(start, end, content);
return {
code: s.toString(),
map: s.generateMap({ hires: true, source: filename })
};
}
const removeCommentsToMakeGlobalWrappingEasy = true;
async function generateStyles(rulesToGenerate, uno) {
const originalShortcuts = uno.config.shortcuts;
const shortcutsForThisComponent = Object.entries(rulesToGenerate);
uno.config.shortcuts = [...originalShortcuts, ...shortcutsForThisComponent];
const selectorsToGenerate = Object.keys(rulesToGenerate);
const { css } = await uno.generate(
selectorsToGenerate,
{
preflights: false,
safelist: false,
minify: removeCommentsToMakeGlobalWrappingEasy
}
);
uno.config.shortcuts = originalShortcuts;
const cssPreparedForSvelteCompiler = wrapSelectorsWithGlobal(css);
return cssPreparedForSvelteCompiler;
}
function removeOuterQuotes(input) {
if (!input)
return "";
const match = input.match(/^(['"]).*\1$/);
return match ? input.slice(1, -1) : input;
}
function writeUtilStyles([, selector, body, parent], s, node, childNode) {
if (!selector)
return;
const selectorChanged = selector !== ".\\-";
if (!parent && !selectorChanged)
return s.appendRight(childNode.loc.end.offset, body);
const originalSelector = cssTree.generate(node.prelude);
if (parent && !selectorChanged) {
const css2 = `${parent}{${originalSelector}{${body}}}`;
return s.appendLeft(node.loc.end.offset, css2);
}
const utilSelector = selector.replace(unocss.regexScopePlaceholder, " ");
const updatedSelector = generateUpdatedSelector(utilSelector, node.prelude);
const svelteCompilerReadySelector = surroundAllButOriginalSelectorWithGlobal(originalSelector, updatedSelector);
const rule = `${svelteCompilerReadySelector}{${body}}`;
const css = parent ? `${parent}{${rule}}` : rule;
s.appendLeft(node.loc.end.offset, css);
}
function generateUpdatedSelector(selector, _prelude) {
const selectorAST = cssTree.parse(selector, {
context: "selector"
});
const prelude = cssTree.clone(_prelude);
prelude.children.forEach((child) => {
const parentSelectorAst = cssTree.clone(selectorAST);
parentSelectorAst.children.forEach((i) => {
if (i.type === "ClassSelector" && i.name === "\\-")
Object.assign(i, cssTree.clone(child));
});
Object.assign(child, parentSelectorAst);
});
return cssTree.generate(prelude);
}
function surroundAllButOriginalSelectorWithGlobal(originalSelector, updatedSelector) {
const wrapWithGlobal = (str) => `:global(${str})`;
const originalSelectors = originalSelector.split(",").map((s) => s.trim());
const updatedSelectors = updatedSelector.split(",").map((s) => s.trim());
const resultSelectors = originalSelectors.map((original, index) => {
const updated = updatedSelectors[index];
const [prefix, suffix] = updated.split(original).map((s) => s.trim());
const wrappedPrefix = prefix ? wrapWithGlobal(prefix) : "";
if (!suffix)
return `${wrappedPrefix} ${original}`.trim();
const indexOfFirstCombinator = findFirstCombinatorIndex(suffix);
if (indexOfFirstCombinator === -1)
return `${wrappedPrefix} ${original}${suffix}`.trim();
const pseudo = suffix.substring(0, indexOfFirstCombinator).trim();
const siblingsOrDescendants = suffix.substring(indexOfFirstCombinator).trim();
return `${wrappedPrefix} ${original}${pseudo} ${wrapWithGlobal(siblingsOrDescendants)}`.trim();
});
return resultSelectors.join(", ");
}
function findFirstCombinatorIndex(input) {
const combinators = [" ", ">", "~", "+"];
for (const c of combinators) {
const indexOfFirstCombinator = input.indexOf(c);
if (indexOfFirstCombinator !== -1)
return indexOfFirstCombinator;
}
return -1;
}
async function getUtils(body, uno) {
const classNames = unocss.expandVariantGroup(body).split(/\s+/g).map((className) => className.trim().replace(/\\/, ""));
const utils = await parseUtils(classNames, uno);
const sortedByRankIndex = utils.sort(([aIndex], [bIndex]) => aIndex - bIndex);
const sortedByParentOrders = sortedByRankIndex.sort(([, , , aParent], [, , , bParent]) => (aParent ? uno.parentOrders.get(aParent) ?? 0 : 0) - (bParent ? uno.parentOrders.get(bParent) ?? 0 : 0));
return sortedByParentOrders.reduce((acc, item) => {
const [, selector, body2, parent] = item;
const sibling = acc.find(([, targetSelector, , targetParent]) => targetSelector === selector && targetParent === parent);
if (sibling)
sibling[2] += body2;
else
acc.push([...item]);
return acc;
}, []);
}
async function parseUtils(classNames, uno) {
const foundUtils = [];
for (const token of classNames) {
const util = await uno.parseToken(token, "-");
if (util)
foundUtils.push(util);
else
unocss.warnOnce(`'${token}' not found. You have a typo or need to add a preset.`);
}
return foundUtils.flat();
}
const DEFAULT_APPLY_VARIABLES = ["--at-apply"];
async function transformApply({ content, uno, prepend, applyVariables, filename }) {
applyVariables = unocss.toArray(applyVariables || DEFAULT_APPLY_VARIABLES);
const hasApply = content.includes("@apply") || applyVariables.some((v) => content.includes(v));
if (!hasApply)
return;
const s = new MagicString__default(content);
await walkCss({ s, uno, applyVariables });
if (!s.hasChanged())
return;
if (prepend)
s.prepend(prepend);
return {
code: s.toString(),
map: s.generateMap({ hires: true, source: filename || "" })
};
}
async function walkCss(ctx) {
const ast = cssTree.parse(ctx.s.original, {
parseAtrulePrelude: false,
positions: true
});
if (ast.type !== "StyleSheet")
return;
const stack = [];
cssTree.walk(ast, (node) => {
if (node.type === "Rule")
stack.push(handleApply(ctx, node));
});
await Promise.all(stack);
}
async function handleApply(ctx, node) {
const parsePromises = node.block.children.map(async (childNode) => {
await parseApply(ctx, node, childNode);
});
await Promise.all(parsePromises);
}
async function parseApply({ s, uno, applyVariables }, node, childNode) {
const body = getChildNodeValue(childNode, applyVariables);
if (!body)
return;
const utils = await getUtils(body, uno);
if (!utils.length)
return;
for (const util of utils)
writeUtilStyles(util, s, node, childNode);
s.remove(childNode.loc.start.offset, childNode.loc.end.offset);
}
function getChildNodeValue(childNode, applyVariables) {
if (childNode.type === "Atrule" && childNode.name === "apply" && childNode.prelude && childNode.prelude.type === "Raw")
return childNode.prelude.value.trim();
if (childNode.type === "Declaration" && applyVariables.includes(childNode.property) && childNode.value.type === "Raw")
return removeOuterQuotes(childNode.value.value.trim());
}
function UnocssSveltePreprocess(options = {}, unoContextFromVite) {
if (!options.classPrefix)
options.classPrefix = "spu-";
let uno;
return {
markup: async ({ content, filename }) => {
if (!uno)
uno = await getGenerator(options.configOrPath, unoContextFromVite);
return await transformClasses({ content, filename: filename || "", uno, options });
},
style: async ({ content, attributes, filename }) => {
const addPreflights = !!attributes["uno:preflights"];
const addSafelist = !!attributes["uno:safelist"];
const checkForApply = options.applyVariables !== false;
const changeNeeded = addPreflights || addSafelist || checkForApply;
if (!changeNeeded)
return;
if (!uno)
uno = await getGenerator(options.configOrPath);
let preflightsSafelistCss = "";
if (addPreflights || addSafelist) {
if (unoContextFromVite)
unocss.warnOnce("Do not place preflights or safelist within an individual component as they already placed in your global styles injected into the head tag. These options are only for component libraries.");
const { css } = await uno.generate([], { preflights: addPreflights, safelist: addSafelist, minify: true });
preflightsSafelistCss = css;
}
if (checkForApply) {
return await transformApply({
content,
prepend: preflightsSafelistCss,
uno,
applyVariables: options.applyVariables,
filename
});
}
if (preflightsSafelistCss)
return { code: preflightsSafelistCss };
}
};
}
async function getGenerator(configOrPath, unoContextFromVite) {
if (unoContextFromVite) {
await unoContextFromVite.ready;
return unoContextFromVite.uno;
}
const defaults = {
presets: [
unocss.presetUno()
]
};
const { config: config$1 } = await config.loadConfig(process.cwd(), configOrPath);
return unocss.createGenerator(config$1, defaults);
}
function PassPreprocessToSveltePlugin(options = {}, ctx) {
return {
name: "svelte-scoped-uno:pass-preprocess",
enforce: "pre",
configResolved(viteConfig) {
options = { ...options, combine: viteConfig.command === "build" };
},
api: {
sveltePreprocess: UnocssSveltePreprocess(options, ctx)
}
};
}
const GLOBAL_STYLES_PLACEHOLDER = "svelte_scoped_uno_global_styles";
const PLACEHOLDER_USER_SETS_IN_INDEX_HTML = "%svelte-scoped-uno.global%";
const DEV_GLOBAL_STYLES_DATA_TITLE = "svelte-scoped-uno global styles";
const tempTailwindFallbackReset = '*,::after,::before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}';
const _dirname = typeof __dirname !== "undefined" ? __dirname : node_path.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (document.currentScript && document.currentScript.src || new URL('index.cjs', document.baseURI).href))));
function getReset(injectReset) {
if (injectReset.startsWith("@unocss/reset")) {
const resolvedPNPM = node_path.resolve(node_path.resolve(_dirname, `../node_modules/${injectReset}`));
if (isFile(resolvedPNPM))
return node_fs.readFileSync(resolvedPNPM, "utf-8");
const resolvedNPM = node_path.resolve(process.cwd(), "node_modules", injectReset);
if (isFile(resolvedNPM))
return node_fs.readFileSync(resolvedNPM, "utf-8");
if (injectReset === "@unocss/reset/tailwind.css") {
console.log("Using tailwind reset fallback. Please file a bug report as this means there is an issue with the reset module resolving with this environment or package manager.");
return tempTailwindFallbackReset;
}
throw new Error(`"${injectReset}" given as your injectReset value is not found. Please check to make sure it is one of the five supported @unocss/reset options. If it is file a bug report detailing your environment and package manager`);
}
if (injectReset.startsWith(".")) {
const resolved = node_path.resolve(process.cwd(), injectReset);
if (!isFile(resolved))
throw new Error(`"${injectReset}" given as your injectReset value is not a valid file path relative to the root of your project, where your vite config file sits. To give an example, if you placed a reset.css in your src directory, "./src/reset.css" would work.`);
return node_fs.readFileSync(resolved, "utf-8");
}
if (injectReset.startsWith("/"))
throw new Error(`Your injectReset value: "${injectReset}" is not a valid file path. To give an example, if you placed a reset.css in your src directory, "./src/reset.css" would work.`);
const resolvedFromNodeModules = node_path.resolve(process.cwd(), "node_modules", injectReset);
if (!isFile(resolvedFromNodeModules))
throw new Error(`"${injectReset}" given as your injectReset value is not a valid file path relative to your project's node_modules folder. Can you confirm that you've installed "${injectReset}"?`);
return node_fs.readFileSync(resolvedFromNodeModules, "utf-8");
}
function isFile(path) {
return node_fs.existsSync(path) && node_fs.statSync(path).isFile();
}
function isServerHooksFile(path) {
return path.includes("hooks") && path.includes("server");
}
function replaceGlobalStylesPlaceholder(code, stylesTag) {
const captureQuoteMark = "([\"'`])";
const matchCapturedQuoteMark = "\\1";
const QUOTES_WITH_PLACEHOLDER_RE = new RegExp(captureQuoteMark + GLOBAL_STYLES_PLACEHOLDER + matchCapturedQuoteMark);
const escapedStylesTag = stylesTag.replaceAll(/`/g, "\\`");
return code.replace(QUOTES_WITH_PLACEHOLDER_RE, `\`${escapedStylesTag}\``);
}
async function generateGlobalCss(uno, injectReset) {
const { css } = await uno.generate("", { preflights: true, safelist: true, minify: true });
const reset = injectReset ? getReset(injectReset) : "";
return reset + css;
}
const SVELTE_ERROR = `[unocss] You have not setup the svelte-scoped global styles correctly. You must place '${PLACEHOLDER_USER_SETS_IN_INDEX_HTML}' in your index.html file.
`;
const SVELTE_KIT_ERROR = `[unocss] You have not setup the svelte-scoped global styles correctly. You must place '${PLACEHOLDER_USER_SETS_IN_INDEX_HTML}' in your app.html file. You also need to have a transformPageChunk hook in your server hooks file with: \`html.replace('${PLACEHOLDER_USER_SETS_IN_INDEX_HTML}', '${GLOBAL_STYLES_PLACEHOLDER}')\`. You can see an example of the usage at https://github.com/jacob-8/svelte-scoped-uno/tree/main/examples/sveltekit-vite-plugin.`;
function checkTransformPageChunkHook(server, isSvelteKit) {
server.middlewares.use((req, res, next) => {
const originalWrite = res.write;
res.write = function(chunk, ...rest) {
const str = chunk instanceof Buffer ? chunk.toString() : Array.isArray(chunk) || "at" in chunk ? Buffer.from(chunk).toString() : `${chunk}`;
if (str.includes("<head>") && !str.includes(DEV_GLOBAL_STYLES_DATA_TITLE))
server.config.logger.error(isSvelteKit ? SVELTE_KIT_ERROR : SVELTE_ERROR, { timestamp: true });
return originalWrite.call(this, chunk, ...rest);
};
next();
});
}
function GlobalStylesPlugin({ ready, uno }, injectReset) {
let isSvelteKit;
let viteConfig;
let unoCssFileReferenceId;
let unoCssHashedLinkTag;
return {
name: "unocss:svelte-scoped:global-styles",
async configResolved(_viteConfig) {
viteConfig = _viteConfig;
await ready;
isSvelteKit = viteConfig.plugins.some((p) => p.name.includes("sveltekit"));
},
// serve
configureServer: (server) => checkTransformPageChunkHook(server, isSvelteKit),
// serve
async transform(code, id) {
if (isSvelteKit && viteConfig.command === "serve" && isServerHooksFile(id)) {
const css = await generateGlobalCss(uno, injectReset);
return {
code: replaceGlobalStylesPlaceholder(code, `<style type="text/css" data-title="${DEV_GLOBAL_STYLES_DATA_TITLE}">${css}</style>`)
};
}
},
// build
async buildStart() {
if (viteConfig.command === "build") {
const css = await generateGlobalCss(uno, injectReset);
unoCssFileReferenceId = this.emitFile({
type: "asset",
name: "unocss-svelte-scoped-global.css",
source: css
});
}
},
// build
renderStart() {
const unoCssFileName = this.getFileName(unoCssFileReferenceId);
const base = viteConfig.base ?? "/";
unoCssHashedLinkTag = `<link href="${base}${unoCssFileName}" rel="stylesheet" />`;
},
// build
renderChunk(code, chunk) {
if (isSvelteKit && chunk.moduleIds.some((id) => isServerHooksFile(id)))
return replaceGlobalStylesPlaceholder(code, unoCssHashedLinkTag);
},
// serve and build
async transformIndexHtml(html) {
if (!isSvelteKit) {
if (viteConfig.command === "build")
return html.replace(PLACEHOLDER_USER_SETS_IN_INDEX_HTML, unoCssHashedLinkTag);
if (viteConfig.command === "serve") {
const css = await generateGlobalCss(uno, injectReset);
return html.replace(PLACEHOLDER_USER_SETS_IN_INDEX_HTML, `<style type="text/css" data-title="${DEV_GLOBAL_STYLES_DATA_TITLE}">${css}</style>`);
}
}
}
};
}
function UnocssSvelteScopedVite(options = {}) {
if (!options.injectReset && options.addReset) {
options.injectReset = "@unocss/reset/tailwind.css";
console.warn('[svelte-scoped-uno] `addReset` is deprecated, please use `injectReset: "@unocss/reset/tailwind.css"` instead.');
}
const context = createSvelteScopedContext(options.configOrPath);
const plugins = [
GlobalStylesPlugin(context, options.injectReset)
];
if (!options.onlyGlobal)
plugins.push(PassPreprocessToSveltePlugin(options, context));
return plugins;
}
function createSvelteScopedContext(configOrPath) {
const uno = unocss.createGenerator();
const ready = reloadConfig();
async function reloadConfig() {
const { config: config$1 } = await config.loadConfig(process.cwd(), configOrPath);
uno.setConfig(config$1);
return config$1;
}
return {
uno,
ready
};
}
exports.PreprocessUnocss = UnocssSveltePreprocess;
exports.SvelteScopedUno = UnocssSvelteScopedVite;
Object.keys(unocss).forEach(function (k) {
if (k !== 'default' && !exports.hasOwnProperty(k)) exports[k] = unocss[k];
});