UNPKG

beesbuild

Version:

构建工具链

214 lines (213 loc) 7.13 kB
import path from "path"; import * as compiler from "@vue/compiler-sfc"; import chalk from "chalk-unified"; import { consola, parseManifest } from "@beesbuild/utils"; import { copy, existsSync, readFileSync } from "fs-extra"; import { Project } from "ts-morph"; import glob from "fast-glob"; import { defu } from "defu"; import { BUILD_CACHE_DIR } from "../variables.mjs"; import { handleTypeOption } from "./utils.mjs"; import { vueTsc } from "./vue-tsc.mjs"; import { parse } from "./parseSfc.mjs"; function compileVueFile(file, flag = true) { var _a, _b, _c; const result = { lang: "js" }; try { const errors = []; const content = readFileSync(path.join(file), "utf-8"); const hasTsNoCheck = content.includes("@ts-nocheck"); const sfc = flag ? compiler.parse(content, { templateParseOptions: { // there are no components at SFC parsing level isNativeTag: () => true, // preserve all whitespaces isPreTag: () => true, parseMode: "sfc", onError: (e) => { errors.push(e); }, comments: true } }) : parse(content); const { script, scriptSetup } = sfc.descriptor; if (script || scriptSetup) { result.content = (hasTsNoCheck ? "// @ts-nocheck\n" : "") + ((_a = script == null ? void 0 : script.content) != null ? _a : ""); const lang = (_c = (_b = scriptSetup == null ? void 0 : scriptSetup.lang) != null ? _b : script == null ? void 0 : script.lang) != null ? _c : "js"; if (scriptSetup) { const compiled = compiler.compileScript(sfc.descriptor, { id: "xxx", isProd: true }); result.content += compiled.content; result.imports = compiled.imports; } result.lang = lang; } } catch (e) { handleCatch(e); } function handleCatch(e) { console.error(path.basename(file), "error:compileVueFile"); console.error(e, "error:compileVueFile"); } return result; } function createTypesProject(ctx) { const { compilerOptions, tsConfigFilePath, rootDir, entries, output, typesCacheDir, entryFilepath, isVue } = handleTypeOption(ctx); const options = { compilerOptions, // 是否跳过添加指定 tsconfig.json 中的源文件。 skipAddingFilesFromTsConfig: true // 提供 ts 配置文件路径并从 tsconfig 添加文件时,跳过解析文件依赖项。 // skipFileDependencyResolution: true, // 跳过加载 lib 文件。与编译器 API 不同,ts-morph 不会从 node_modules 文件夹加载它们,而是从其他一些 JS 代码加载它们,并使用假路径来表示它们的存在。如果您想使用自定义 lib 文件文件夹路径,请使用 libFolderPath 选项提供一个路径。 // skipLoadingLibFiles: true, // 用于加载 lib 文件的文件夹。 // libFolderPath: undefined, // 是否使用内存文件系统。 // useInMemoryFileSystem: false, // 创建解析主机以指定自定义模块和/或类型引用指令解析。 // resolutionHost: undefined, }; if (existsSync(tsConfigFilePath)) { options.tsConfigFilePath = tsConfigFilePath; } const project = new Project(options); function addSourceFiles() { if (isVue) return []; const typingsDtsPath = path.resolve(rootDir, "typings", "env.d.ts"); if (existsSync(typingsDtsPath)) project.addSourceFileAtPath(typingsDtsPath); const extIncludes = ["jsx", "js", "tsx", "ts", "dts"]; const sourceFiles = []; for (const { input: filePath } of entries) { const { ext } = parseManifest(filePath, rootDir); if (ext === "vue") { const { lang, content } = compileVueFile(filePath); if (content) { const createFilePath = path.join(`${path.relative(rootDir, filePath)}.${lang}`); const sourceFile = project.createSourceFile(createFilePath, content); sourceFiles.push(sourceFile); } } else if (extIncludes.includes(ext)) { const sourceFile = project.addSourceFileAtPath(filePath); sourceFiles.push(sourceFile); } } return sourceFiles; } function typeCheck(check) { var _a; if (check !== true && ((_a = ctx.argv) == null ? void 0 : _a.debug)) return; if (isVue) { try { vueTsc(ctx, { noEmit: true }); } catch (e) { consola.error(e); const err = new Error(`\u751F\u6210dts\u5931\u8D25\u3002${ctx.options.stub}`); consola.error(err); } return; } const diagnostics = project.getPreEmitDiagnostics().filter((diagnostic) => { const code = diagnostic.getCode(); let message = diagnostic.getMessageText(); if (typeof message !== "string") { message = message.getMessageText(); } return !(code === 6307 && message.includes("Projects must list all files or use an 'include' pattern")); }); if (diagnostics.length > 0) { const aaa = project.formatDiagnosticsWithColorAndContext(diagnostics); consola.error(aaa); const err = new Error(`\u751F\u6210dts\u5931\u8D25\u3002${ctx.options.stub}`); consola.error(err); } } function generate(options2) { var _a; if (isVue) return vueTsc(ctx); const emitOptions = defu( { emitOnlyDtsFiles: true, customTransformers: {} }, options2 ); const result = project.emitToMemory(emitOptions); if ((_a = ctx.argv) == null ? void 0 : _a.debug) { for (const file of result.getFiles()) { const p = path.relative(rootDir, file.filePath); consola.success(chalk.green(`Definition for file: ${chalk.bold(p)} generated`)); } } return result.saveFiles(); } function copyFiles() { let src = path.resolve(rootDir, ".", BUILD_CACHE_DIR, output.name); const files = glob.sync(`./*.d.ts`, { cwd: src, onlyFiles: true, deep: 1, absolute: true }); const directories = glob.sync(`./*`, { cwd: src, onlyDirectories: true, deep: 1, absolute: true }); if (files.length === 0 && directories.length === 1) { src = directories[0]; } consola.info(chalk.cyan(`Start for copy types file: ${path.relative(rootDir, src)} generated`)); return copy(src, output.path, { overwrite: true }); } return { typesCacheDir, entryFilepath, output, options, project, addSourceFiles, typeCheck, generate, copy: copyFiles, isVue }; } const typesBuild = async (ctx) => { const types = createTypesProject(ctx); types.addSourceFiles(); consola.success("Added source types files"); if (!types.isVue) { types.typeCheck(); consola.success("Type check passed!"); } try { await types.generate(); consola.success(chalk.green("Generate types files success")); } catch (e) { consola.error(chalk.green("Generate types files fail")); consola.error(e); } finally { await types.copy(); consola.success(chalk.green("Copy types files success")); } return types; }; export { createTypesProject, typesBuild };