xyvcard-wechat-build
Version:
基于 Vite 的小程序组件构建工具
146 lines (145 loc) • 5.15 kB
JavaScript
import { build as viteBuild } from "vite";
import * as path from "path";
import * as fs from "fs-extra";
import glob from "fast-glob";
import * as sass from "sass";
import esbuild from "rollup-plugin-esbuild";
import { getMiniprogramNpmPackages } from "./utils.js";
const IGNORE_PATTERNS = [
"node_modules",
"miniprogram_npm/**",
"pages/**",
"app.ts",
"app.scss",
"app.json",
"sitemap.json",
];
const IGNORE_SCSS = ["styles/**/*.scss"];
export async function build(options = {}) {
const ROOT_DIR = options.root || process.cwd();
const SRC_DIR = path.resolve(ROOT_DIR, "miniprogram");
const DIST_DIR = path.resolve(ROOT_DIR, options.outDir || "dist");
const EXTERNAL = [
/^@types\//,
/^miniprogram-/,
/^xyvcard-/,
/^jmash-/,
/^pages/,
];
const EXTERNAL_PACKAGES = await getMiniprogramNpmPackages(SRC_DIR);
async function buildTypeScript() {
const tsFiles = await glob("**/*.ts", {
cwd: SRC_DIR,
ignore: IGNORE_PATTERNS,
});
const input = Object.fromEntries(tsFiles.map((file) => [
path.join(path.dirname(file), path.basename(file, ".ts")),
path.resolve(SRC_DIR, file),
]));
await viteBuild({
root: ROOT_DIR,
build: {
outDir: DIST_DIR,
lib: {
entry: input,
formats: ["es"],
fileName: (format, entryName) => `${entryName}.js`,
},
rollupOptions: {
input,
external: EXTERNAL.concat(EXTERNAL_PACKAGES),
output: {
format: "es",
exports: "named",
preserveModules: true,
preserveModulesRoot: "miniprogram",
},
plugins: [
esbuild({
target: "es2020",
tsconfig: path.resolve(ROOT_DIR, "tsconfig.json"),
sourceMap: false,
minify: false,
loaders: {
".ts": "ts",
},
}),
],
},
minify: "terser",
terserOptions: {
format: {
comments: false,
},
compress: {
keep_classnames: true,
drop_console: true,
drop_debugger: true,
},
},
sourcemap: false,
emptyOutDir: false,
},
resolve: {
alias: {
"@": path.resolve(ROOT_DIR, "miniprogram"),
},
},
});
}
async function buildSass() {
const scssFiles = await glob("**/*.scss", {
cwd: SRC_DIR,
ignore: [...IGNORE_PATTERNS, ...IGNORE_SCSS],
});
await Promise.all(scssFiles.map(async (file) => {
const srcFile = path.join(SRC_DIR, file);
const distFile = path.join(DIST_DIR, file.replace(/\.scss$/, ".wxss"));
const result = sass.compile(srcFile, {
style: "compressed",
});
await fs.outputFile(distFile, result.css);
}));
}
async function copyOtherFiles() {
const patterns = ["**/*.wxml", "**/*.json", "**/*.wxs", ...IGNORE_SCSS];
const files = await glob(patterns, {
cwd: SRC_DIR,
ignore: IGNORE_PATTERNS,
});
await Promise.all(files.map((file) => fs.copy(path.join(SRC_DIR, file), path.join(DIST_DIR, file))));
}
async function generateTypes() {
const tsFiles = await glob("**/*.ts", {
cwd: SRC_DIR,
ignore: IGNORE_PATTERNS,
});
const absTsFiles = tsFiles.map((file) => path.join("miniprogram", file));
const typesConfigPath = path.join(ROOT_DIR, "tsconfig.types.json");
const typesConfig = {
extends: "./tsconfig.json",
include: absTsFiles,
compilerOptions: {
declaration: true,
emitDeclarationOnly: true,
skipLibCheck: true,
outDir: DIST_DIR,
},
};
await fs.default.writeFile(typesConfigPath, JSON.stringify(typesConfig, null, 2), "utf8");
const { execSync } = await import("child_process");
execSync(`tsc -p ${typesConfigPath}`, {
stdio: "inherit",
cwd: ROOT_DIR,
});
await fs.remove(typesConfigPath);
}
console.time("构建完成");
// 清理输出目录
await fs.remove(DIST_DIR);
// 并行执行构建任务
await Promise.all([buildTypeScript(), buildSass(), copyOtherFiles()]);
// 生成类型声明文件
await generateTypes();
console.timeEnd("构建完成");
}