Skip to content

Commit 4d16b19

Browse files
committed
fix(sass): @use
close: #10
1 parent 9713847 commit 4d16b19

File tree

5 files changed

+177
-12
lines changed

5 files changed

+177
-12
lines changed

src/sassCompiler.ts

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,95 @@ export async function sassCompiler(
99
) {
1010
if (typeof window !== 'undefined')
1111
throw new Error('sassCompiler is not supported in this browser')
12-
let result = globalCss
13-
? `${globalCss.replace(/@(?:include|import)\s+["']([^"']*)['"]/g, (_, v) =>
14-
_.replace(v, Url.pathToFileURL(path.resolve(process.cwd(), v)) as any))}${css}`
15-
: css
12+
13+
const baseDir = filepath ? path.dirname(filepath) : process.cwd()
14+
15+
// 辅助函数:处理路径转换
16+
const processPathInContent = (content: string) => {
17+
let processed = content
18+
19+
// 处理基本的 @use, @forward, @include, @import 指令
20+
processed = processed.replace(
21+
/@(?:use|forward|include|import)\s+["']([^"']*)['"]/g,
22+
(match, filePath) => {
23+
// 跳过内置 Sass 模块 (sass:*, pkg:* 等)
24+
if (filePath.includes(':')) {
25+
return match
26+
}
27+
const resolvedPath = path.resolve(baseDir, filePath)
28+
return match.replace(filePath, Url.pathToFileURL(resolvedPath) as any)
29+
},
30+
)
31+
32+
// 处理 @use 的扩展语法:@use "path" as namespace 或 @use "path" with (...)
33+
processed = processed.replace(
34+
/@use\s+["']([^"']*)['"]\s+(?:as\s+\w+\*?|with\s*\([^)]*\))/g,
35+
(match, filePath) => {
36+
// 跳过内置 Sass 模块
37+
if (filePath.includes(':')) {
38+
return match
39+
}
40+
const resolvedPath = path.resolve(baseDir, filePath)
41+
return match.replace(filePath, Url.pathToFileURL(resolvedPath) as any)
42+
},
43+
)
44+
45+
// 处理 @forward 的扩展语法:@forward "path" show/hide/as
46+
processed = processed.replace(
47+
/@forward\s+["']([^"']*)['"]\s*(?:show\s+[^;]+|hide\s+[^;]+|as\s+[^;]+)/g,
48+
(match, filePath) => {
49+
// 跳过内置 Sass 模块
50+
if (filePath.includes(':')) {
51+
return match
52+
}
53+
const resolvedPath = path.resolve(baseDir, filePath)
54+
return match.replace(filePath, Url.pathToFileURL(resolvedPath) as any)
55+
},
56+
)
57+
58+
return processed
59+
}
60+
61+
// 处理 globalCss 和当前 CSS
62+
let result = ''
63+
if (globalCss) {
64+
result += processPathInContent(globalCss)
65+
}
66+
result += processPathInContent(css)
1667
try {
17-
result = (await import('sass')).default.compileString(
68+
const sass = await import('sass')
69+
result = sass.compileString(
1870
result,
1971
filepath
2072
? {
2173
importers: [
2274
{
2375
findFileUrl(url) {
24-
if (!url.startsWith('~'))
25-
return new URL(url, Url.pathToFileURL(filepath) as URL)
26-
return new URL(
27-
url.slice(1),
28-
Url.pathToFileURL(filepath) as URL,
29-
)
76+
// 处理波浪号路径 (~)
77+
if (url.startsWith('~')) {
78+
return new URL(
79+
url.slice(1),
80+
Url.pathToFileURL(baseDir) as URL,
81+
)
82+
}
83+
// 处理相对路径
84+
if (!url.startsWith('/') && !url.includes('://')) {
85+
return new URL(url, Url.pathToFileURL(baseDir) as URL)
86+
}
87+
// 处理绝对路径
88+
return new URL(url, Url.pathToFileURL(baseDir) as URL)
3089
},
3190
},
3291
],
92+
// 启用现代 Sass API
93+
syntax: 'scss',
94+
// 支持 @use 和 @forward
95+
loadPaths: [baseDir, process.cwd()],
3396
}
34-
: {},
97+
: {
98+
syntax: 'scss',
99+
loadPaths: [process.cwd()],
100+
},
35101
).css
36102
return result
37103
}

test/__snapshots__/transformCode.test.ts.snap

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,6 +1918,23 @@ export default defineComponent({
19181918
",
19191919
"
19201920
1921+
----- sass-builtin-test.vue -------
1922+
1923+
<template>
1924+
<div class="sass-builtin-test">
1925+
Built-in Sass module test
1926+
</div>
1927+
</template>
1928+
1929+
<style>
1930+
.sass-builtin-test {
1931+
width: 50px;
1932+
color: #ff3333;
1933+
}
1934+
</style>
1935+
",
1936+
"
1937+
19211938
----- sass.vue -------
19221939
19231940
<script setup lang="ts">
@@ -2132,6 +2149,33 @@ onMounted(async () => {
21322149
",
21332150
"
21342151
2152+
----- use-syntax-test.vue -------
2153+
2154+
<template>
2155+
<div class="test-use-syntax">
2156+
<div class="basic-use">Basic @use test</div>
2157+
<div class="use-as-namespace">@use with namespace test</div>
2158+
<div class="use-with-config">@use with configuration test</div>
2159+
</div>
2160+
</template>
2161+
2162+
<style>
2163+
.test-use-syntax .basic-use {
2164+
color: blue;
2165+
font-size: 20px;
2166+
}
2167+
.test-use-syntax .use-as-namespace {
2168+
color: #ff0000;
2169+
font-size: 16px;
2170+
}
2171+
.test-use-syntax .use-with-config {
2172+
color: blue;
2173+
font-size: 18px;
2174+
}
2175+
</style>
2176+
",
2177+
"
2178+
21352179
----- vue.tsx -------
21362180
21372181
import { defineComponent, ref } from 'vue'

test/demo/sass-builtin-test.vue

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<template>
2+
<div class="sass-builtin-test">
3+
Built-in Sass module test
4+
</div>
5+
</template>
6+
7+
<style lang="scss">
8+
@use "sass:math";
9+
@use "sass:color";
10+
@use "./variables.scss" as vars;
11+
12+
.sass-builtin-test {
13+
width: math.div(100px, 2);
14+
color: color.adjust(vars.$primary-color, $lightness: 10%);
15+
}
16+
</style>

test/demo/use-syntax-test.vue

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<template>
2+
<div class="test-use-syntax">
3+
<div class="basic-use">Basic @use test</div>
4+
<div class="use-as-namespace">@use with namespace test</div>
5+
<div class="use-with-config">@use with configuration test</div>
6+
</div>
7+
</template>
8+
9+
<style lang="scss">
10+
// 基本 @use 语法
11+
@use './use-syntax.scss';
12+
13+
// @use 带命名空间
14+
@use './variables.scss' as vars;
15+
16+
.test-use-syntax {
17+
.basic-use {
18+
@include use-syntax.test-mixin();
19+
}
20+
21+
.use-as-namespace {
22+
color: vars.$primary-color;
23+
font-size: vars.$font-size;
24+
}
25+
26+
.use-with-config {
27+
color: blue;
28+
font-size: 18px;
29+
}
30+
}
31+
</style>

test/demo/use-syntax.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Test file for @use syntax
2+
$test-color: blue;
3+
$test-size: 20px;
4+
5+
@mixin test-mixin() {
6+
color: $test-color;
7+
font-size: $test-size;
8+
}

0 commit comments

Comments
 (0)