@embeddable.com/sdk-core
Version:
Core Embeddable SDK module responsible for web-components bundling and publishing.
170 lines (142 loc) • 4.88 kB
text/typescript
import { findFiles, loadJson } from "@embeddable.com/sdk-utils";
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { getSDKVersions, hrtimeToISO8601 } from "./utils";
import { ResolvedEmbeddableConfig } from "./defineConfig";
export default async (ctx: ResolvedEmbeddableConfig) => {
await extractBuild(ctx);
await removeObsoleteDir(ctx.client.buildDir);
await moveBuildTOBuildDir(ctx);
};
type ManifestArgs = {
ctx: ResolvedEmbeddableConfig;
typesFileName: string;
metaFileName: string;
editorsMetaFileName: string;
stencilWrapperFileName: string;
};
export async function createManifest({
ctx,
typesFileName,
metaFileName,
editorsMetaFileName,
stencilWrapperFileName,
}: ManifestArgs) {
const sdkVersions = await getSDKVersions();
// identify user's package manager and its version
let packageManager = "npm";
if (process.env.npm_config_user_agent?.includes("yarn")) {
packageManager = "yarn";
}
if (process.env.npm_config_user_agent?.includes("pnpm")) {
packageManager = "pnpm";
}
const packageManagerVersion =
process.env.npm_config_user_agent?.match(/(\d+\.\d+\.\d+)/)?.[0] ||
"unknown";
const globalHooks = await loadJson(
path.resolve(ctx.client.buildDir, "globalHooks.json"),
);
// write manifest file with files with hash
const manifest = {
entryFiles: {
"embeddable-types.js": typesFileName,
"embeddable-components-meta.js": metaFileName,
"embeddable-editors-meta.js": editorsMetaFileName,
"embeddable-wrapper.esm.js": stencilWrapperFileName,
},
metadata: {
nodeVersion: process.version,
platform: process.platform,
bundleHash: ctx.client.bundleHash,
previews: ctx.client.componentsWithPreview,
sdkVersions,
packageManager,
packageManagerVersion,
globalHooks,
metrics: {
buildTime: hrtimeToISO8601(ctx.buildTime),
},
origin: ctx.dev?.watch ? "dev" : "push",
},
};
await fs.writeFile(
path.join(ctx.client.tmpDir, "embeddable-manifest.json"),
JSON.stringify(manifest),
);
}
async function extractBuild(ctx: ResolvedEmbeddableConfig) {
// Ensure tmpDir is removed before attempting to rename a directory to it.
// This helps prevent EPERM errors on Windows if tmpDir already exists and is non-empty
// from a previous failed run or other reasons.
await fs.rm(ctx.client.tmpDir, { recursive: true, force: true });
const stencilBuildFiles = await findFiles(
ctx.client.stencilBuild,
/embeddable-wrapper.esm-[a-z0-9]+\.js/,
);
const [[, stencilWrapperFilePath]] = stencilBuildFiles || [];
const stencilWrapperFileName = path.basename(stencilWrapperFilePath);
await fs.rename(
path.resolve(ctx.client.buildDir, ctx.client.stencilBuild),
ctx.client.tmpDir,
);
const typesBuildFiles = await findFiles(
ctx.client.buildDir,
/embeddable-types-[a-z0-9]+\.js/,
);
const [[, typesFilePath]] = typesBuildFiles || [];
const typesFileName = path.basename(typesFilePath);
await fs.rename(typesFilePath, path.join(ctx.client.tmpDir, typesFileName));
const metaBuildFiles = await findFiles(
ctx.client.buildDir,
/embeddable-components-meta-[a-z0-9]+\.js/,
);
const [[, metaFilePath]] = metaBuildFiles || [];
const metaFileName = path.basename(metaFilePath);
await fs.rename(metaFilePath, path.join(ctx.client.tmpDir, metaFileName));
const editorsMetaBuildFiles = await findFiles(
ctx.client.buildDir,
/embeddable-editors-meta-[a-z0-9]+\.js/,
);
const [[, editorsMetaFilePath]] = editorsMetaBuildFiles || [];
const editorsMetaFileName = path.basename(editorsMetaFilePath);
await fs.rename(
editorsMetaFilePath,
path.join(ctx.client.tmpDir, editorsMetaFileName),
);
const themeFile =
(await findFiles(ctx.client.buildDir, /embeddable-theme-[0-9a-f]+\.js/)) ||
[];
for (const [, themeFilePath] of themeFile) {
const themeFilePathFileName = path.basename(themeFilePath);
await fs.rename(
themeFilePath,
path.join(ctx.client.tmpDir, themeFilePathFileName),
);
}
const lifecycleFiles =
(await findFiles(
ctx.client.buildDir,
/embeddable-lifecycle(?:-[0-9a-f]+)?\.js/,
)) || [];
for (const [, lifecycleFilePath] of lifecycleFiles) {
const lifecycleFilePathFileName = path.basename(lifecycleFilePath);
await fs.rename(
lifecycleFilePath,
path.join(ctx.client.tmpDir, lifecycleFilePathFileName),
);
}
await createManifest({
ctx,
typesFileName,
metaFileName,
editorsMetaFileName,
stencilWrapperFileName,
});
}
async function removeObsoleteDir(dir: string) {
await fs.rm(dir, { recursive: true });
}
async function moveBuildTOBuildDir(ctx: ResolvedEmbeddableConfig) {
await fs.rename(ctx.client.tmpDir, ctx.client.buildDir);
}