@vureact/compiler-core 1.0.4 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -1
- package/README.zh.md +280 -0
- package/lib/{chunk-VWMAAVDB.esm.js → chunk-2ESB4I6I.esm.js} +326 -149
- package/lib/{chunk-6PSD2CIO.js → chunk-GWLPQNHN.js} +358 -181
- package/lib/cli.esm.js +14 -4
- package/lib/cli.js +21 -11
- package/lib/compiler-core.d.cts +92 -53
- package/lib/compiler-core.d.ts +92 -53
- package/lib/compiler-core.esm.js +2 -2
- package/lib/compiler-core.js +3 -3
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @vureact/compiler-core v1.
|
|
2
|
+
* @vureact/compiler-core v1.1.1
|
|
3
3
|
* (c) 2025-present Ruihong Zhong (Ryan John)
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
@@ -1401,14 +1401,18 @@ import less from "less";
|
|
|
1401
1401
|
import * as sass from "sass";
|
|
1402
1402
|
function resolveLessSass(source, options) {
|
|
1403
1403
|
const { lang, enabled, filename } = options;
|
|
1404
|
-
|
|
1405
|
-
if (
|
|
1406
|
-
|
|
1404
|
+
const result = { code: source, fileExt: ".css" };
|
|
1405
|
+
if (!options.enabled) {
|
|
1406
|
+
result.fileExt = `.${options.lang}`;
|
|
1407
1407
|
}
|
|
1408
|
-
if (
|
|
1409
|
-
|
|
1408
|
+
if (!enabled) return result;
|
|
1409
|
+
if (lang === "less") {
|
|
1410
|
+
result.code = resolveLessSync(source, filename);
|
|
1411
|
+
} else if (lang === "scss" || lang === "sass") {
|
|
1412
|
+
result.code = resolveSassSync(source, filename);
|
|
1410
1413
|
}
|
|
1411
|
-
|
|
1414
|
+
result.code = resolveImportExtensions(result.code);
|
|
1415
|
+
return result;
|
|
1412
1416
|
}
|
|
1413
1417
|
function resolveLessSync(source, filename) {
|
|
1414
1418
|
let result = "";
|
|
@@ -1459,6 +1463,12 @@ function resolveSassSync(source, filename) {
|
|
|
1459
1463
|
const result = sass.compileString(source, options);
|
|
1460
1464
|
return result.css;
|
|
1461
1465
|
}
|
|
1466
|
+
function resolveImportExtensions(code) {
|
|
1467
|
+
if (code.includes(".less") || code.includes(".scss") || code.includes(".sass")) {
|
|
1468
|
+
return code.replaceAll(/\.(less|scss|sass)(?=['")])/g, ".css");
|
|
1469
|
+
}
|
|
1470
|
+
return code;
|
|
1471
|
+
}
|
|
1462
1472
|
|
|
1463
1473
|
// src/core/parse/sfc/process/resolve-styles.ts
|
|
1464
1474
|
function resolveStyles(descriptor, ctx, result) {
|
|
@@ -1478,13 +1488,12 @@ function resolveStyles(descriptor, ctx, result) {
|
|
|
1478
1488
|
{ file: filename }
|
|
1479
1489
|
);
|
|
1480
1490
|
}
|
|
1481
|
-
const
|
|
1491
|
+
const { code, fileExt } = resolveLessSass(content, {
|
|
1482
1492
|
lang,
|
|
1483
1493
|
filename,
|
|
1484
1494
|
enabled: preprocessStyles
|
|
1485
1495
|
});
|
|
1486
|
-
|
|
1487
|
-
let ext = disablePreprocessing ? `.${lang}` : ".css";
|
|
1496
|
+
let ext = fileExt;
|
|
1488
1497
|
if (style.module) {
|
|
1489
1498
|
ext = `-${fileId}.module${ext}`;
|
|
1490
1499
|
styleData.moduleName = typeof style.module === "boolean" ? STYLE_MODULE_NAME : style.module;
|
|
@@ -1492,18 +1501,18 @@ function resolveStyles(descriptor, ctx, result) {
|
|
|
1492
1501
|
ext = `-${fileId}${ext}`;
|
|
1493
1502
|
}
|
|
1494
1503
|
if (style.scoped) {
|
|
1495
|
-
if (
|
|
1504
|
+
if (lang !== "css" && !preprocessStyles) {
|
|
1496
1505
|
logger.warn(
|
|
1497
1506
|
"Scoped styles are only supported for CSS. Preprocessing is disabled, so scoped styles will not be applied.",
|
|
1498
1507
|
{ file: filename }
|
|
1499
1508
|
);
|
|
1500
1509
|
return;
|
|
1501
1510
|
}
|
|
1502
|
-
const result2 = processScopedWithPostCss(
|
|
1511
|
+
const result2 = processScopedWithPostCss(code, fileId);
|
|
1503
1512
|
style.content = result2.css.trim();
|
|
1504
1513
|
styleData.scopeId = result2.scopeId;
|
|
1505
1514
|
} else {
|
|
1506
|
-
style.content =
|
|
1515
|
+
style.content = code;
|
|
1507
1516
|
}
|
|
1508
1517
|
const filePath = filename.replace(/\.vue$/i, ext);
|
|
1509
1518
|
styleData.filePath = filePath;
|
|
@@ -1591,7 +1600,8 @@ import { traverse as traverse3 } from "@babel/core";
|
|
|
1591
1600
|
// src/core/transform/sfc/script/syntax-processor/postprocess/insert-css-import.ts
|
|
1592
1601
|
import * as t16 from "@babel/types";
|
|
1593
1602
|
function insertCSSImport(ctx) {
|
|
1594
|
-
|
|
1603
|
+
const { inputType } = ctx;
|
|
1604
|
+
if (inputType !== "sfc") return;
|
|
1595
1605
|
const { filePath, moduleName } = ctx.styleData;
|
|
1596
1606
|
if (!filePath) return;
|
|
1597
1607
|
const scriptIR = getScriptIR(ctx);
|
|
@@ -1634,6 +1644,44 @@ function insertRequiredImports(ctx) {
|
|
|
1634
1644
|
const processedModules = /* @__PURE__ */ new Set();
|
|
1635
1645
|
let hasProcessedImports = false;
|
|
1636
1646
|
recordImport(ctx, PACKAGE_NAME.react, REACT_API_MAP.memo);
|
|
1647
|
+
function resolveRequiredImport(path7) {
|
|
1648
|
+
const { node } = path7;
|
|
1649
|
+
const moduleName = node.source.value.toLowerCase();
|
|
1650
|
+
const isVueLike = isVueEcosystemPackage(moduleName);
|
|
1651
|
+
mergeImports(node, ctx);
|
|
1652
|
+
if (processedModules.has(moduleName) && !path7.removed) {
|
|
1653
|
+
path7.remove();
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
processedModules.add(moduleName);
|
|
1657
|
+
if (!hasProcessedImports) {
|
|
1658
|
+
const required = createRequiredImports(ctx);
|
|
1659
|
+
if (isVueLike) {
|
|
1660
|
+
path7.replaceWithMultiple(required);
|
|
1661
|
+
} else if (moduleName === PACKAGE_NAME.react) {
|
|
1662
|
+
path7.insertAfter(required);
|
|
1663
|
+
} else {
|
|
1664
|
+
path7.insertBefore(required);
|
|
1665
|
+
}
|
|
1666
|
+
hasProcessedImports = true;
|
|
1667
|
+
}
|
|
1668
|
+
if (isVueLike && !path7.removed) {
|
|
1669
|
+
path7.remove();
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
replaceVueSuffix(ctx, node.source);
|
|
1673
|
+
}
|
|
1674
|
+
function resolveStyleFileExt(path7) {
|
|
1675
|
+
if (!ctx.preprocessStyles) return;
|
|
1676
|
+
const { node } = path7;
|
|
1677
|
+
if (!node || !node.source || !node.source.value) return;
|
|
1678
|
+
const importSource = node.source.value;
|
|
1679
|
+
if (typeof importSource !== "string") return;
|
|
1680
|
+
const styleExtRegex = /\.(less|sass|scss)$/i;
|
|
1681
|
+
if (!styleExtRegex.test(importSource)) return;
|
|
1682
|
+
const newSource = importSource.replace(styleExtRegex, ".css");
|
|
1683
|
+
node.source.value = newSource;
|
|
1684
|
+
}
|
|
1637
1685
|
return {
|
|
1638
1686
|
// 增加 Program.exit 兜底注入 required imports(处理无 ImportDeclaration 的 SFC)
|
|
1639
1687
|
Program: {
|
|
@@ -1645,31 +1693,8 @@ function insertRequiredImports(ctx) {
|
|
|
1645
1693
|
}
|
|
1646
1694
|
},
|
|
1647
1695
|
ImportDeclaration(path7) {
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
const isVueLike = isVueEcosystemPackage(moduleName);
|
|
1651
|
-
mergeImports(node, ctx);
|
|
1652
|
-
if (processedModules.has(moduleName) && !path7.removed) {
|
|
1653
|
-
path7.remove();
|
|
1654
|
-
return;
|
|
1655
|
-
}
|
|
1656
|
-
processedModules.add(moduleName);
|
|
1657
|
-
if (!hasProcessedImports) {
|
|
1658
|
-
const required = createRequiredImports(ctx);
|
|
1659
|
-
if (isVueLike) {
|
|
1660
|
-
path7.replaceWithMultiple(required);
|
|
1661
|
-
} else if (moduleName === PACKAGE_NAME.react) {
|
|
1662
|
-
path7.insertAfter(required);
|
|
1663
|
-
} else {
|
|
1664
|
-
path7.insertBefore(required);
|
|
1665
|
-
}
|
|
1666
|
-
hasProcessedImports = true;
|
|
1667
|
-
}
|
|
1668
|
-
if (isVueLike && !path7.removed) {
|
|
1669
|
-
path7.remove();
|
|
1670
|
-
return;
|
|
1671
|
-
}
|
|
1672
|
-
replaceVueSuffix(ctx, node.source);
|
|
1696
|
+
resolveRequiredImport(path7);
|
|
1697
|
+
resolveStyleFileExt(path7);
|
|
1673
1698
|
}
|
|
1674
1699
|
};
|
|
1675
1700
|
}
|
|
@@ -5076,7 +5101,7 @@ function transform(ast, ctx, options) {
|
|
|
5076
5101
|
}
|
|
5077
5102
|
|
|
5078
5103
|
// package.json
|
|
5079
|
-
var version = "1.
|
|
5104
|
+
var version = "1.1.1";
|
|
5080
5105
|
var bin = {
|
|
5081
5106
|
vureact: "./bin/vureact.js"
|
|
5082
5107
|
};
|
|
@@ -5085,6 +5110,7 @@ var bin = {
|
|
|
5085
5110
|
var CacheKey = /* @__PURE__ */ ((CacheKey2) => {
|
|
5086
5111
|
CacheKey2["SFC"] = "sfc";
|
|
5087
5112
|
CacheKey2["SCRIPT"] = "script";
|
|
5113
|
+
CacheKey2["STYLE"] = "style";
|
|
5088
5114
|
CacheKey2["ASSET"] = "copied";
|
|
5089
5115
|
return CacheKey2;
|
|
5090
5116
|
})(CacheKey || {});
|
|
@@ -5190,6 +5216,7 @@ var Helper = class {
|
|
|
5190
5216
|
"package-lock.json",
|
|
5191
5217
|
"pnpm-lock.yaml",
|
|
5192
5218
|
"index.html",
|
|
5219
|
+
"yarn-lock.",
|
|
5193
5220
|
"tsconfig.",
|
|
5194
5221
|
"vite.config.",
|
|
5195
5222
|
"eslint.config.",
|
|
@@ -5325,6 +5352,7 @@ var Helper = class {
|
|
|
5325
5352
|
source: {
|
|
5326
5353
|
["sfc" /* SFC */]: [],
|
|
5327
5354
|
["script" /* SCRIPT */]: [],
|
|
5355
|
+
["style" /* STYLE */]: [],
|
|
5328
5356
|
["copied" /* ASSET */]: []
|
|
5329
5357
|
}
|
|
5330
5358
|
};
|
|
@@ -5465,6 +5493,39 @@ var Helper = class {
|
|
|
5465
5493
|
}
|
|
5466
5494
|
};
|
|
5467
5495
|
|
|
5496
|
+
// src/core/parse/style-only.ts
|
|
5497
|
+
function parseOnlyStyle(source, ctx, options) {
|
|
5498
|
+
const { filename } = ctx;
|
|
5499
|
+
let lang = filename.split(".").pop();
|
|
5500
|
+
if (!lang) {
|
|
5501
|
+
lang = "css";
|
|
5502
|
+
logger.warn(`The style file without an extension has been fallback to .css`, {
|
|
5503
|
+
file: filename
|
|
5504
|
+
});
|
|
5505
|
+
}
|
|
5506
|
+
const { code, fileExt } = resolveLessSass(source, {
|
|
5507
|
+
filename,
|
|
5508
|
+
lang,
|
|
5509
|
+
enabled: ctx.preprocessStyles
|
|
5510
|
+
});
|
|
5511
|
+
const result = {
|
|
5512
|
+
template: null,
|
|
5513
|
+
script: null,
|
|
5514
|
+
style: {
|
|
5515
|
+
source: {
|
|
5516
|
+
type: "style",
|
|
5517
|
+
content: code,
|
|
5518
|
+
lang: fileExt.replace(".", ""),
|
|
5519
|
+
attrs: {},
|
|
5520
|
+
loc: {}
|
|
5521
|
+
},
|
|
5522
|
+
ast: void 0
|
|
5523
|
+
}
|
|
5524
|
+
};
|
|
5525
|
+
executePlugins(options?.plugins, result, ctx);
|
|
5526
|
+
return result;
|
|
5527
|
+
}
|
|
5528
|
+
|
|
5468
5529
|
// src/compiler/context/adapter.ts
|
|
5469
5530
|
import path3 from "path";
|
|
5470
5531
|
|
|
@@ -5526,19 +5587,42 @@ var CompilationAdapter = class _CompilationAdapter {
|
|
|
5526
5587
|
static createContext(input) {
|
|
5527
5588
|
const ctx = createCompilationCtx();
|
|
5528
5589
|
const inputType = _CompilationAdapter.detectInputType(input.filename);
|
|
5529
|
-
|
|
5530
|
-
ctx.data.inputType = inputType;
|
|
5590
|
+
const initTemplateData = () => {
|
|
5531
5591
|
ctx.data.templateData = {};
|
|
5592
|
+
};
|
|
5593
|
+
const initScriptData = () => {
|
|
5594
|
+
ctx.data.scriptData = {};
|
|
5595
|
+
};
|
|
5596
|
+
const initStyleData = () => {
|
|
5532
5597
|
ctx.data.styleData = {};
|
|
5598
|
+
};
|
|
5599
|
+
if (inputType.startsWith("script-")) {
|
|
5600
|
+
initTemplateData();
|
|
5601
|
+
initStyleData();
|
|
5602
|
+
} else if (inputType === "style") {
|
|
5603
|
+
initTemplateData();
|
|
5604
|
+
initScriptData();
|
|
5533
5605
|
}
|
|
5534
5606
|
ctx.init({ inputType, ...input });
|
|
5535
5607
|
return ctx;
|
|
5536
5608
|
}
|
|
5537
5609
|
static detectInputType(filename) {
|
|
5538
|
-
const ext = path3.extname(filename);
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5610
|
+
const ext = path3.extname(filename).toLowerCase();
|
|
5611
|
+
switch (ext) {
|
|
5612
|
+
case ".vue":
|
|
5613
|
+
return "sfc";
|
|
5614
|
+
case ".js":
|
|
5615
|
+
return "script-js";
|
|
5616
|
+
case ".ts":
|
|
5617
|
+
return "script-ts";
|
|
5618
|
+
case ".css":
|
|
5619
|
+
case ".less":
|
|
5620
|
+
case ".sass":
|
|
5621
|
+
case ".scss":
|
|
5622
|
+
return "style";
|
|
5623
|
+
default:
|
|
5624
|
+
return "unknow";
|
|
5625
|
+
}
|
|
5542
5626
|
}
|
|
5543
5627
|
};
|
|
5544
5628
|
|
|
@@ -5597,8 +5681,7 @@ var BaseCompiler = class extends Helper {
|
|
|
5597
5681
|
* `;
|
|
5598
5682
|
*
|
|
5599
5683
|
* const result = compiler.compile(vueCode, 'MyComponent.vue');
|
|
5600
|
-
* console.log(result
|
|
5601
|
-
* console.log(result.fileInfo.jsx.file); // 输出文件路径
|
|
5684
|
+
* console.log(result);
|
|
5602
5685
|
* ```
|
|
5603
5686
|
*
|
|
5604
5687
|
* @throws 不会直接抛出异常,错误通过日志系统记录
|
|
@@ -5610,21 +5693,29 @@ var BaseCompiler = class extends Helper {
|
|
|
5610
5693
|
compile(source, filename) {
|
|
5611
5694
|
const { plugins, preprocessStyles = true } = this.options;
|
|
5612
5695
|
const fileId = this.genHash(filename);
|
|
5613
|
-
const genOptions = this.prepareGenerateOptions(filename);
|
|
5614
5696
|
const ctx = this.createContext({
|
|
5615
5697
|
fileId,
|
|
5616
5698
|
filename,
|
|
5617
5699
|
source,
|
|
5618
5700
|
preprocessStyles
|
|
5619
5701
|
});
|
|
5620
|
-
|
|
5702
|
+
const genOptions = this.prepareGenerateOptions(filename);
|
|
5703
|
+
const resolveSFCAndScriptFile = () => {
|
|
5621
5704
|
const ast = parse(source, ctx.data, { plugins: plugins?.parser });
|
|
5622
5705
|
const ir = transform(ast, ctx.data, { plugins: plugins?.transformer });
|
|
5623
5706
|
const gen = generate(ir, ctx.data, {
|
|
5624
5707
|
...genOptions,
|
|
5625
5708
|
plugins: plugins?.codegen
|
|
5626
5709
|
});
|
|
5627
|
-
|
|
5710
|
+
return this.resolveMainResult(ir, gen, ctx.data);
|
|
5711
|
+
};
|
|
5712
|
+
const resolveStyleFile = () => {
|
|
5713
|
+
const result = parseOnlyStyle(source, ctx.data, { plugins: plugins?.parser });
|
|
5714
|
+
return this.resolveStyleResult(result, ctx.data);
|
|
5715
|
+
};
|
|
5716
|
+
try {
|
|
5717
|
+
const isStyleFile = ctx.data.inputType === "style";
|
|
5718
|
+
const result = isStyleFile ? resolveStyleFile() : resolveSFCAndScriptFile();
|
|
5628
5719
|
if (plugins) {
|
|
5629
5720
|
const { parser, transformer, codegen, ...rest } = plugins;
|
|
5630
5721
|
executePlugins(rest, result, ctx);
|
|
@@ -5634,67 +5725,6 @@ var BaseCompiler = class extends Helper {
|
|
|
5634
5725
|
ctx.clear();
|
|
5635
5726
|
}
|
|
5636
5727
|
}
|
|
5637
|
-
/**
|
|
5638
|
-
* 处理 SFC 和 Script 文件的编译结果
|
|
5639
|
-
*
|
|
5640
|
-
* 根据编译上下文中的输入类型(SFC 或 Script),整理并返回相应的编译结果。
|
|
5641
|
-
* 对于 SFC 文件,返回包含 JSX 和 CSS 信息的完整结果;
|
|
5642
|
-
* 对于 Script 文件,返回仅包含脚本信息的结果。
|
|
5643
|
-
*
|
|
5644
|
-
* 关键处理逻辑:
|
|
5645
|
-
* 1. 构建基础结果:包含文件ID、路由信息和生成的代码
|
|
5646
|
-
* 2. 确定输出路径:根据源文件路径和语言类型生成输出文件路径
|
|
5647
|
-
* 3. 区分文件类型:
|
|
5648
|
-
* - SFC 文件:生成 .tsx 扩展名,包含样式信息
|
|
5649
|
-
* - Script 文件:保持原扩展名,不包含样式信息
|
|
5650
|
-
* 4. 样式处理:提取样式文件路径、作用域ID和样式代码
|
|
5651
|
-
*
|
|
5652
|
-
* @private
|
|
5653
|
-
* @param ir - React 中间表示(IR)描述符,包含转换后的组件信息
|
|
5654
|
-
* @param gen - 代码生成结果,包含生成的代码和源码映射
|
|
5655
|
-
* @param ctxData - 编译上下文数据,包含文件信息和编译状态
|
|
5656
|
-
* @returns {CompilationResult} 整理后的编译结果
|
|
5657
|
-
*
|
|
5658
|
-
* @remarks
|
|
5659
|
-
* - 文件扩展名处理:Vue SFC 文件会转换为 .tsx 或 .jsx 文件
|
|
5660
|
-
* - 样式分离:SFC 中的样式会被提取到独立的 CSS 文件中
|
|
5661
|
-
* - 路由检测:自动检测组件是否使用路由,用于依赖注入
|
|
5662
|
-
* - 作用域样式:为 Scoped CSS 生成唯一的作用域ID
|
|
5663
|
-
*
|
|
5664
|
-
* @see {@link SFCCompilationResult} SFC 编译结果类型
|
|
5665
|
-
* @see {@link ScriptCompilationResult} Script 编译结果类型
|
|
5666
|
-
*/
|
|
5667
|
-
resolveResult(ir, gen, ctxData) {
|
|
5668
|
-
const { fileId, filename, scriptData, styleData } = ctxData;
|
|
5669
|
-
const base = {
|
|
5670
|
-
fileId,
|
|
5671
|
-
hasRoute: ctxData.route,
|
|
5672
|
-
...gen
|
|
5673
|
-
};
|
|
5674
|
-
const { lang } = scriptData;
|
|
5675
|
-
const file = this.resolveOutputPath(filename, lang);
|
|
5676
|
-
if (ctxData.inputType === "sfc") {
|
|
5677
|
-
return {
|
|
5678
|
-
fileInfo: {
|
|
5679
|
-
jsx: {
|
|
5680
|
-
file: `${file}x`,
|
|
5681
|
-
// 'xxx.ts' + 'x' => 'xxx.tsx'
|
|
5682
|
-
lang
|
|
5683
|
-
},
|
|
5684
|
-
css: {
|
|
5685
|
-
file: styleData?.filePath,
|
|
5686
|
-
hash: styleData?.scopeId,
|
|
5687
|
-
code: ir?.style
|
|
5688
|
-
}
|
|
5689
|
-
},
|
|
5690
|
-
...base
|
|
5691
|
-
};
|
|
5692
|
-
}
|
|
5693
|
-
return {
|
|
5694
|
-
fileInfo: { script: { file, lang } },
|
|
5695
|
-
...base
|
|
5696
|
-
};
|
|
5697
|
-
}
|
|
5698
5728
|
/**
|
|
5699
5729
|
* 初始化 Babel 代码生成选项
|
|
5700
5730
|
*
|
|
@@ -5759,6 +5789,87 @@ var BaseCompiler = class extends Helper {
|
|
|
5759
5789
|
}
|
|
5760
5790
|
return mergedOptions;
|
|
5761
5791
|
}
|
|
5792
|
+
/**
|
|
5793
|
+
* 处理 SFC 和 Script 文件的编译结果
|
|
5794
|
+
*
|
|
5795
|
+
* 根据编译上下文中的输入类型(SFC 或 Script),整理并返回相应的编译结果。
|
|
5796
|
+
* 对于 SFC 文件,返回包含 JSX 和 CSS 信息的完整结果;
|
|
5797
|
+
* 对于 Script 文件,返回仅包含脚本信息的结果。
|
|
5798
|
+
*
|
|
5799
|
+
* 关键处理逻辑:
|
|
5800
|
+
* 1. 构建基础结果:包含文件ID、路由信息和生成的代码
|
|
5801
|
+
* 2. 确定输出路径:根据源文件路径和语言类型生成输出文件路径
|
|
5802
|
+
* 3. 区分文件类型:
|
|
5803
|
+
* - SFC 文件:生成 .tsx 扩展名,包含样式信息
|
|
5804
|
+
* - Script 文件:保持原扩展名,不包含样式信息
|
|
5805
|
+
* 4. 样式处理:提取样式文件路径、作用域ID和样式代码
|
|
5806
|
+
*
|
|
5807
|
+
* @private
|
|
5808
|
+
* @param ir - React 中间表示(IR)描述符,包含转换后的组件信息
|
|
5809
|
+
* @param gen - 代码生成结果,包含生成的代码和源码映射
|
|
5810
|
+
* @param ctxData - 编译上下文数据,包含文件信息和编译状态
|
|
5811
|
+
* @returns {CompilationResult} 整理后的编译结果
|
|
5812
|
+
*
|
|
5813
|
+
* @remarks
|
|
5814
|
+
* - 文件扩展名处理:Vue SFC 文件会转换为 .tsx 或 .jsx 文件
|
|
5815
|
+
* - 样式分离:SFC 中的样式会被提取到独立的 CSS 文件中
|
|
5816
|
+
* - 路由检测:自动检测组件是否使用路由,用于依赖注入
|
|
5817
|
+
* - 作用域样式:为 Scoped CSS 生成唯一的作用域ID
|
|
5818
|
+
*
|
|
5819
|
+
* @see {@link SFCCompilationResult} SFC 编译结果类型
|
|
5820
|
+
* @see {@link ScriptCompilationResult} Script 编译结果类型
|
|
5821
|
+
*/
|
|
5822
|
+
resolveMainResult(ir, gen, ctxData) {
|
|
5823
|
+
const { fileId, filename, scriptData, styleData, inputType } = ctxData;
|
|
5824
|
+
const base = {
|
|
5825
|
+
fileId,
|
|
5826
|
+
hasRoute: ctxData.route,
|
|
5827
|
+
...gen
|
|
5828
|
+
};
|
|
5829
|
+
const { lang } = scriptData;
|
|
5830
|
+
const file = this.resolveOutputPath(filename, lang);
|
|
5831
|
+
if (inputType === "sfc") {
|
|
5832
|
+
return {
|
|
5833
|
+
fileInfo: {
|
|
5834
|
+
jsx: {
|
|
5835
|
+
file: `${file}x`,
|
|
5836
|
+
// 'xxx.ts' + 'x' => 'xxx.tsx'
|
|
5837
|
+
lang
|
|
5838
|
+
},
|
|
5839
|
+
css: {
|
|
5840
|
+
file: styleData?.filePath,
|
|
5841
|
+
hash: styleData?.scopeId,
|
|
5842
|
+
code: ir?.style
|
|
5843
|
+
}
|
|
5844
|
+
},
|
|
5845
|
+
...base
|
|
5846
|
+
};
|
|
5847
|
+
}
|
|
5848
|
+
return {
|
|
5849
|
+
fileInfo: { script: { file, lang } },
|
|
5850
|
+
...base
|
|
5851
|
+
};
|
|
5852
|
+
}
|
|
5853
|
+
/**
|
|
5854
|
+
* 处理 Style 文件的编译结果
|
|
5855
|
+
* @param data style 文件解析结果
|
|
5856
|
+
* @param ctxData 上下文数据
|
|
5857
|
+
*/
|
|
5858
|
+
resolveStyleResult(data, ctxData) {
|
|
5859
|
+
const { fileId, filename } = ctxData;
|
|
5860
|
+
const { lang, content = "" } = data.style.source;
|
|
5861
|
+
const file = this.resolveOutputPath(filename, lang);
|
|
5862
|
+
return {
|
|
5863
|
+
fileId,
|
|
5864
|
+
fileInfo: {
|
|
5865
|
+
style: {
|
|
5866
|
+
file,
|
|
5867
|
+
lang
|
|
5868
|
+
}
|
|
5869
|
+
},
|
|
5870
|
+
code: content
|
|
5871
|
+
};
|
|
5872
|
+
}
|
|
5762
5873
|
};
|
|
5763
5874
|
|
|
5764
5875
|
// src/utils/calc-elapsed-time.ts
|
|
@@ -5788,6 +5899,8 @@ var AssetManager = class {
|
|
|
5788
5899
|
this.fileCompiler = fileCompiler;
|
|
5789
5900
|
this.cleanupManager = cleanupManager;
|
|
5790
5901
|
}
|
|
5902
|
+
// 需要经过管线编译处理的文件类型
|
|
5903
|
+
pipelineFiles = [".js", ".ts", ".less", ".scss", ".sass"];
|
|
5791
5904
|
/**
|
|
5792
5905
|
* 运行资源文件处理管线
|
|
5793
5906
|
*/
|
|
@@ -5805,6 +5918,9 @@ var AssetManager = class {
|
|
|
5805
5918
|
if (pattern.endsWith(".")) {
|
|
5806
5919
|
return filename.startsWith(pattern);
|
|
5807
5920
|
}
|
|
5921
|
+
if (pattern.startsWith(".")) {
|
|
5922
|
+
return ext === pattern;
|
|
5923
|
+
}
|
|
5808
5924
|
return relativeToRoot === pattern || filename === pattern;
|
|
5809
5925
|
});
|
|
5810
5926
|
if (shouldExclude) {
|
|
@@ -5815,7 +5931,7 @@ var AssetManager = class {
|
|
|
5815
5931
|
}
|
|
5816
5932
|
if (ext === ".vue") return false;
|
|
5817
5933
|
const isInsideSrc = p.startsWith(inputPath + path4.sep);
|
|
5818
|
-
if (isInsideSrc && (ext
|
|
5934
|
+
if (isInsideSrc && this.pipelineFiles.includes(ext)) {
|
|
5819
5935
|
return false;
|
|
5820
5936
|
}
|
|
5821
5937
|
return true;
|
|
@@ -5975,33 +6091,47 @@ var CompilationUnitProcessor = class {
|
|
|
5975
6091
|
}
|
|
5976
6092
|
// 处理编译结果
|
|
5977
6093
|
resolveResult(result, unit, key) {
|
|
5978
|
-
const { fileId, code
|
|
6094
|
+
const { fileId, code } = result;
|
|
5979
6095
|
unit.fileId = fileId;
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
jsx
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
},
|
|
5993
|
-
css
|
|
5994
|
-
// 添加 css 文件信息
|
|
5995
|
-
};
|
|
5996
|
-
} else if (key === "script" /* SCRIPT */) {
|
|
5997
|
-
const { script } = result.fileInfo;
|
|
5998
|
-
unit.output = {
|
|
5999
|
-
script: {
|
|
6000
|
-
file: script.file,
|
|
6001
|
-
code
|
|
6096
|
+
const isSFC = key === "sfc" /* SFC */;
|
|
6097
|
+
const isScriptFile = key === "script" /* SCRIPT */;
|
|
6098
|
+
const isStyleFile = key === "style" /* STYLE */;
|
|
6099
|
+
if (isSFC || isScriptFile) {
|
|
6100
|
+
unit.hasRoute = result?.hasRoute;
|
|
6101
|
+
}
|
|
6102
|
+
const resolveFileInfo = () => {
|
|
6103
|
+
if (isSFC) {
|
|
6104
|
+
const component = result;
|
|
6105
|
+
const { jsx, css } = component.fileInfo;
|
|
6106
|
+
if (css.file) {
|
|
6107
|
+
css.file = this.fileCompiler.resolveOutputPath(css.file);
|
|
6002
6108
|
}
|
|
6003
|
-
|
|
6004
|
-
|
|
6109
|
+
unit.output = {
|
|
6110
|
+
jsx: {
|
|
6111
|
+
file: jsx.file,
|
|
6112
|
+
code
|
|
6113
|
+
},
|
|
6114
|
+
css
|
|
6115
|
+
};
|
|
6116
|
+
} else if (isScriptFile) {
|
|
6117
|
+
const { script } = result.fileInfo;
|
|
6118
|
+
unit.output = {
|
|
6119
|
+
script: {
|
|
6120
|
+
file: script?.file,
|
|
6121
|
+
code
|
|
6122
|
+
}
|
|
6123
|
+
};
|
|
6124
|
+
} else if (isStyleFile) {
|
|
6125
|
+
const { style } = result.fileInfo;
|
|
6126
|
+
unit.output = {
|
|
6127
|
+
style: {
|
|
6128
|
+
file: style.file,
|
|
6129
|
+
code
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
}
|
|
6133
|
+
};
|
|
6134
|
+
resolveFileInfo();
|
|
6005
6135
|
}
|
|
6006
6136
|
/**
|
|
6007
6137
|
* 将编译产物写入磁盘
|
|
@@ -6018,6 +6148,10 @@ var CompilationUnitProcessor = class {
|
|
|
6018
6148
|
if (css.file && css.code) {
|
|
6019
6149
|
await this.fileCompiler.writeFileWithDir(css.file, css.code);
|
|
6020
6150
|
}
|
|
6151
|
+
} else if (key === "style" /* STYLE */) {
|
|
6152
|
+
const { style } = output;
|
|
6153
|
+
file = style.file;
|
|
6154
|
+
code = style.code;
|
|
6021
6155
|
} else {
|
|
6022
6156
|
const { script } = output;
|
|
6023
6157
|
file = script.file;
|
|
@@ -6053,6 +6187,12 @@ var FileProcessor = class {
|
|
|
6053
6187
|
async processScript(filePath, existingCache) {
|
|
6054
6188
|
return this.processFile("script" /* SCRIPT */, filePath, existingCache);
|
|
6055
6189
|
}
|
|
6190
|
+
/**
|
|
6191
|
+
* Process a single style file (this method is called directly in CLI Watch mode)
|
|
6192
|
+
*/
|
|
6193
|
+
async processStyle(filePath, existingCache) {
|
|
6194
|
+
return this.processFile("style" /* STYLE */, filePath, existingCache);
|
|
6195
|
+
}
|
|
6056
6196
|
async processFile(key, filePath, existingCache) {
|
|
6057
6197
|
const absPath = this.fileCompiler.getAbsPath(filePath);
|
|
6058
6198
|
const fileMeta = await this.fileCompiler.getFileMeta(absPath);
|
|
@@ -6068,17 +6208,20 @@ var FileProcessor = class {
|
|
|
6068
6208
|
if (!source.trim()) return;
|
|
6069
6209
|
const initUnit = {
|
|
6070
6210
|
...fileMeta,
|
|
6071
|
-
file: absPath,
|
|
6072
|
-
fileId: "",
|
|
6073
6211
|
source,
|
|
6074
|
-
|
|
6075
|
-
|
|
6212
|
+
type: key,
|
|
6213
|
+
fileId: "",
|
|
6214
|
+
file: absPath,
|
|
6215
|
+
output: void 0,
|
|
6216
|
+
hash: hash || this.fileCompiler.genHash(source)
|
|
6076
6217
|
};
|
|
6077
6218
|
const processed = await this.compilationUnitProcessor.resolve(initUnit, key);
|
|
6078
6219
|
if (processed?.output) {
|
|
6079
6220
|
await this.compilationUnitProcessor.saveCompiledFiles(processed, key);
|
|
6080
|
-
if (
|
|
6081
|
-
|
|
6221
|
+
if (key === "sfc" /* SFC */ || key === "script" /* SCRIPT */) {
|
|
6222
|
+
if (processed?.hasRoute) {
|
|
6223
|
+
await this.injectVuReactRouteDep();
|
|
6224
|
+
}
|
|
6082
6225
|
}
|
|
6083
6226
|
await this.cacheManager.updateCacheIncrementally(processed, key);
|
|
6084
6227
|
}
|
|
@@ -6115,15 +6258,30 @@ var PipelineManager = class {
|
|
|
6115
6258
|
async runScriptPipeline() {
|
|
6116
6259
|
return this.runCorePipeline("script" /* SCRIPT */);
|
|
6117
6260
|
}
|
|
6261
|
+
/**
|
|
6262
|
+
* 运行 Style 编译管线
|
|
6263
|
+
*/
|
|
6264
|
+
async runStylePipeline() {
|
|
6265
|
+
return this.runCorePipeline("style" /* STYLE */);
|
|
6266
|
+
}
|
|
6118
6267
|
/**
|
|
6119
6268
|
* 核心编译管线
|
|
6120
6269
|
*/
|
|
6121
6270
|
async runCorePipeline(key) {
|
|
6122
6271
|
const inputPath = this.fileCompiler.getInputPath();
|
|
6272
|
+
const scriptExtRegex = /\.(js|ts)$/i;
|
|
6273
|
+
const styleExtRegex = /\.(css|less|sass|scss)$/i;
|
|
6123
6274
|
const files = this.fileCompiler.scanFiles(inputPath, (p) => {
|
|
6124
6275
|
const ext = path6.extname(p);
|
|
6125
|
-
if (key === "sfc" /* SFC */)
|
|
6126
|
-
|
|
6276
|
+
if (key === "sfc" /* SFC */) {
|
|
6277
|
+
return ext === ".vue";
|
|
6278
|
+
}
|
|
6279
|
+
if (key === "script" /* SCRIPT */) {
|
|
6280
|
+
return scriptExtRegex.test(ext);
|
|
6281
|
+
}
|
|
6282
|
+
if (key === "style" /* STYLE */) {
|
|
6283
|
+
return styleExtRegex.test(ext);
|
|
6284
|
+
}
|
|
6127
6285
|
return false;
|
|
6128
6286
|
});
|
|
6129
6287
|
if (!files.length) return 0;
|
|
@@ -6333,13 +6491,16 @@ var FileCompiler = class extends BaseCompiler {
|
|
|
6333
6491
|
this.spinner.start("Compiling script files...");
|
|
6334
6492
|
const scriptCount = await this.pipelineManager.runScriptPipeline();
|
|
6335
6493
|
this.spinner.stop();
|
|
6494
|
+
this.spinner.start("Compiling style files...");
|
|
6495
|
+
const styleCount = await this.pipelineManager.runStylePipeline();
|
|
6496
|
+
this.spinner.stop();
|
|
6336
6497
|
this.spinner.start("Copying assets...");
|
|
6337
6498
|
const assetCount = await this.assetManager.runAssetPipeline();
|
|
6338
6499
|
this.spinner.stop();
|
|
6339
6500
|
await this.options.onSuccess?.();
|
|
6340
6501
|
const endTime = calcElapsedTime(startTime);
|
|
6341
6502
|
this.printCoreLogs();
|
|
6342
|
-
this.showCompileStats(endTime, sfcCount, scriptCount, assetCount);
|
|
6503
|
+
this.showCompileStats(endTime, sfcCount, scriptCount, styleCount, assetCount);
|
|
6343
6504
|
} catch (error) {
|
|
6344
6505
|
this.spinner.stop();
|
|
6345
6506
|
const endTime = calcElapsedTime(startTime);
|
|
@@ -6377,6 +6538,21 @@ var FileCompiler = class extends BaseCompiler {
|
|
|
6377
6538
|
async processScript(filePath, existingCache) {
|
|
6378
6539
|
return this.fileProcessor.processScript(filePath, existingCache);
|
|
6379
6540
|
}
|
|
6541
|
+
/**
|
|
6542
|
+
* 处理单个 CSS/LESS/SCSS 样式文件
|
|
6543
|
+
*
|
|
6544
|
+
* 此方法主要用于 CLI 的 watch 模式,当检测到文件变更时调用。
|
|
6545
|
+
* 支持增量编译,如果文件未变更则跳过编译。
|
|
6546
|
+
*
|
|
6547
|
+
* @async
|
|
6548
|
+
* @param filePath - style 文件的绝对路径
|
|
6549
|
+
* @param existingCache - 可选的预加载缓存对象,用于增量编译
|
|
6550
|
+
* @returns {Promise<ScriptUnit | undefined>} 编译单元对象,如果跳过编译则返回 undefined
|
|
6551
|
+
* @see {@link FileProcessor.processStyle}
|
|
6552
|
+
*/
|
|
6553
|
+
async processStyle(filePath, existingCache) {
|
|
6554
|
+
return this.fileProcessor.processStyle(filePath, existingCache);
|
|
6555
|
+
}
|
|
6380
6556
|
/**
|
|
6381
6557
|
* 处理单个文件(Vue 或 Script)
|
|
6382
6558
|
*
|
|
@@ -6466,7 +6642,7 @@ var FileCompiler = class extends BaseCompiler {
|
|
|
6466
6642
|
* @param scriptCount - 处理的脚本文件数量
|
|
6467
6643
|
* @param assetCount - 处理的资源文件数量
|
|
6468
6644
|
*/
|
|
6469
|
-
showCompileStats(endTime, sfcCount, scriptCount, assetCount) {
|
|
6645
|
+
showCompileStats(endTime, sfcCount, scriptCount, styleCount, assetCount) {
|
|
6470
6646
|
const dir = normalizePath(this.relativePath(this.getOuputPath()));
|
|
6471
6647
|
this.spinner.succeed(`Build completed in ${endTime}`);
|
|
6472
6648
|
console.info(` Output directory: ${kleur6.dim(dir)}`);
|
|
@@ -6477,10 +6653,11 @@ var FileCompiler = class extends BaseCompiler {
|
|
|
6477
6653
|
console.info(kleur6.dim(`Skipped ${this.skippedCount} unchanged file(s)`));
|
|
6478
6654
|
this.resetSkippedCount();
|
|
6479
6655
|
}
|
|
6480
|
-
if (sfcCount || scriptCount || assetCount) {
|
|
6656
|
+
if (sfcCount || scriptCount || styleCount || assetCount) {
|
|
6481
6657
|
const stats = [];
|
|
6482
6658
|
if (sfcCount) stats.push(`${sfcCount} SFC(s)`);
|
|
6483
6659
|
if (scriptCount) stats.push(`${scriptCount} script(s)`);
|
|
6660
|
+
if (styleCount) stats.push(`${styleCount} style(s)`);
|
|
6484
6661
|
if (assetCount) stats.push(`${assetCount} asset(s)`);
|
|
6485
6662
|
console.info(kleur6.gray(`Processed ${stats.join(", ")}`));
|
|
6486
6663
|
}
|