A pluggable CSS preprocessor compile facade: a single function turns SCSS / LESS / CSS source (or file) into CSS, routing to swappable backend engines.
Dependencies
对外名 precss;import 路径用下划线 conglinyizhi/precss (MoonBit 包名含连字符会让 _test.mbt/README 的 auto-import alias 失效,故标识收成下划线)。
moon add conglinyizhi/precss///|
test {
// 自动识别格式编译
inspect(
@precss.compile("$c: red; body { color: $c; }"),
content=(
#|body {
#| color: red;
#|}
#|
),
)
}///|
test {
// SCSS 变量 + 嵌套
inspect(
@precss.compile_scss("$gap: 8px; a { margin: $gap; b { padding: $gap; } }"),
content=(
#|a {
#| margin: 8px;
#|}
#|a b {
#| padding: 8px;
#|}
#|
),
)
}///|
test {
// LESS:变量 + 类 mixin(含参数默认值)
inspect(
@precss.compile_less(".pad(@p: 8px) { padding: @p; }\n.x { .pad(); }"),
content=(
#|.x {
#| padding: 8px;
#|}
#|
#|
),
)
}///|
test {
// 显式指定为 CSS(透传)
inspect(
@precss.compile_css("body { color: red; }"),
content="body { color: red; }",
)
}///|
test {
let read = fn(p : String) -> String raise @core.CompileError {
if p == "a.scss" {
"$c: blue; .x { color: $c; }"
} else {
raise @core.CompileError::EngineFailed(
engine="test",
message="missing: " + p,
)
}
}
inspect(
@precss.compile_many(
[
@core.Input::Source("body { color: red; }"),
@core.Input::File("a.scss"), // read 读取,内容里的 @import 也会内联
@core.Input::Source(".y { width: 1px; }"),
],
read,
),
content=(
#|body {
#| color: red;
#|}
#|
#|.x {
#| color: blue;
#|}
#|
#|.y {
#| width: 1px;
#|}
#|
),
)
}less 曾用「转换级适配」(less_to_scss 转成 scss 再复用 SCSS 引擎),但 less 与 scss 语义独立(lazy 作用域 / 类 mixin / 去重),转换级存在 82% 天花板(深层嵌套/变量作用域必然失配),因此拆为独立引擎。
moon run cmd/cli -- help # 用法
moon run cmd/cli -- compile # 批量编译 SCSS(stdin 以 NUL 分隔输入/输出,差分 harness 协议)
moon run cmd/cli -- compile-less # 批量编译 LESS
moon run cmd/cli -- format # 源码格式化(自动探测糖类型;可 --type/--css)
moon run cmd/cli -- diagnose # 重复属性检查(自动探测糖类型)
cat style.scss | moon run cmd/cli -- compile
echo 'a{color:red;font:bold}' | moon run cmd/cli -- format# 构建 native CLI、运行 release profile,并生成 JSON
pnpm run bench:releasemoon test --target native
node scripts/diff.mjs # scss/sass 自带 cases
node scripts/diff.mjs test/sass-spec/spec/variables
node scripts/less_diff.mjs # less 自带 cases// 在 rabbit 项目(后端 cmd/server 或独立构建工具)里
let read = fn(p : String) -> String raise @core.CompileError {
// 从构建期 scss 源码 map 读,或从文件系统读(读文件用 @fs,见下方坑)
scss_sources.get(p) or raise @core.CompileError::EngineFailed(engine="reader", message="missing: " + p)
}
let css = @precss.compile_many(
[@core.Input::File("app.scss"),
@core.Input::File("partials/_button.scss"),
@core.Input::Source("$z: 10; .top { z-index: $z; }")],
read,
)cd site && moon run cmd/ssg # 读 styles/tailwind.scss → 本库编译出 out/tailwind.css;rabbit 渲染 out/index.htmltest {
inspect(compile("body { color: red; }"), content="body { color: red; }")
}fn compile_file(path : String, read : (String) -> String raise CompileError) -> String raise CompileErrorfn compile_many(inputs : Array[Input], read : (String) -> String raise CompileError) -> String raise CompileErrorfn generate_types(source : String) -> Stringfn minify_css(css : String) -> StringInstall
Download zipA pluggable CSS preprocessor compile facade: a single function turns SCSS / LESS / CSS source (or file) into CSS, routing to swappable backend engines.
Dependencies