Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build[patch]: Add way to escape side effects within an entrypoint #6174

Merged
merged 5 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions libs/langchain-scripts/bin/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,16 +225,15 @@ async function listExternals(
export async function checkTreeShaking(options) {
const externals = await listExternals(options?.extraInternals ?? []);
const entrypoints = await listEntrypoints();
const consoleLog = console.log;
/** @type {Map<string, { log: string; hasSideEffects: boolean; }>} */
const consoleInfo = console.info;
const reportMap = new Map();

for (const entrypoint of entrypoints) {
let sideEffects = "";

console.log = function (...args) {
console.info = function (...args) {
const line = args.length ? args.join(" ") : "";
if (line.trim().startsWith("First side effect in")) {
if (line.includes("First side effect in")) {
sideEffects += `${line}\n`;
}
};
Expand All @@ -245,17 +244,26 @@ export async function checkTreeShaking(options) {
experimentalLogSideEffects: true,
});

let hasUnexpectedSideEffects = sideEffects.length > 0;
if (hasUnexpectedSideEffects) {
const entrypointContent = await fs.promises.readFile(`./dist/${entrypoint.replace(/^\.\//, "")}`);
// Allow escaping side effects strictly within code directly
// within an entrypoint
hasUnexpectedSideEffects = !entrypointContent
.toString()
.includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */");
}
reportMap.set(entrypoint, {
log: sideEffects,
hasSideEffects: sideEffects.length > 0,
hasUnexpectedSideEffects,
});
}

console.log = consoleLog;
console.info = consoleInfo;

let failed = false;
for (const [entrypoint, report] of reportMap) {
if (report.hasSideEffects) {
if (report.hasUnexpectedSideEffects) {
failed = true;
console.log("---------------------------------");
console.log(`Tree shaking failed for ${entrypoint}`);
Expand All @@ -264,7 +272,7 @@ export async function checkTreeShaking(options) {
}

if (failed) {
process.exit(1);
throw new Error("Tree shaking checks failed.");
} else {
console.log("Tree shaking checks passed!");
}
Expand Down
2 changes: 1 addition & 1 deletion libs/langchain-scripts/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@langchain/scripts",
"version": "0.0.15",
"version": "0.0.18",
"description": "Shared scripts for LangChain.js",
"type": "module",
"engines": {
Expand Down
28 changes: 20 additions & 8 deletions libs/langchain-scripts/src/build_v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,16 +441,16 @@ async function checkTreeShaking(config: LangChainConfig) {
);
const externals = listExternals(packageJson, config?.internals ?? []);
const entrypoints = listEntrypoints(packageJson);
const consoleLog = console.log;
/** @type {Map<string, { log: string; hasSideEffects: boolean; }>} */
const consoleInfo = console.info;
/** @type {Map<string, { log: string; hasUnexpectedSideEffects: boolean; }>} */
const reportMap = new Map();
jacoblee93 marked this conversation as resolved.
Show resolved Hide resolved

for (const entrypoint of entrypoints) {
let sideEffects = "";

console.log = function (...args) {
console.info = function (...args) {
const line = args.length ? args.join(" ") : "";
if (line.trim().startsWith("First side effect in")) {
if (line.includes("First side effect in")) {
sideEffects += `${line}\n`;
}
};
Expand All @@ -461,17 +461,28 @@ async function checkTreeShaking(config: LangChainConfig) {
experimentalLogSideEffects: true,
});

let hasUnexpectedSideEffects = sideEffects.length > 0;
if (hasUnexpectedSideEffects) {
const entrypointContent = await fs.promises.readFile(
`./dist/${entrypoint.replace(/^\.\//, "")}`
);
// Allow escaping side effects strictly within code directly
// within an entrypoint
hasUnexpectedSideEffects = !entrypointContent
.toString()
.includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */");
}
reportMap.set(entrypoint, {
log: sideEffects,
hasSideEffects: sideEffects.length > 0,
hasUnexpectedSideEffects,
});
}

console.log = consoleLog;
console.info = consoleInfo;

let failed = false;
for (const [entrypoint, report] of reportMap) {
if (report.hasSideEffects) {
if (report.hasUnexpectedSideEffects) {
failed = true;
console.log("---------------------------------");
console.log(`Tree shaking failed for ${entrypoint}`);
Expand All @@ -480,7 +491,8 @@ async function checkTreeShaking(config: LangChainConfig) {
}

if (failed) {
process.exit(1);
// TODO: Throw a hard error here
console.log("Tree shaking checks failed.");
} else {
console.log("Tree shaking checks passed!");
}
Expand Down
27 changes: 19 additions & 8 deletions libs/langchain-scripts/src/check-tree-shaking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,21 @@ async function listExternals(
export async function checkTreeShaking(options?: TreeShakingArgs) {
const externals = await listExternals(options?.extraInternals ?? []);
const entrypoints = await listEntrypoints();
const consoleLog = console.log;
const consoleInfo = console.info;
const reportMap: Map<
string,
{
log: string;
hasSideEffects: boolean;
hasUnexpectedSideEffects: boolean;
}
> = new Map();

for (const entrypoint of entrypoints) {
let sideEffects = "";

console.log = function (...args) {
console.info = function (...args) {
const line = args.length ? args.join(" ") : "";
if (line.trim().startsWith("First side effect in")) {
if (line.includes("First side effect in")) {
sideEffects += `${line}\n`;
}
};
Expand All @@ -85,17 +85,28 @@ export async function checkTreeShaking(options?: TreeShakingArgs) {
experimentalLogSideEffects: true,
});

let hasUnexpectedSideEffects = sideEffects.length > 0;
if (hasUnexpectedSideEffects) {
const entrypointContent = await fs.readFile(
`./dist/${entrypoint.replace(/^\.\//, "")}`
);
// Allow escaping side effects strictly within code directly
// within an entrypoint
hasUnexpectedSideEffects = !entrypointContent
.toString()
.includes("/* __LC_ALLOW_ENTRYPOINT_SIDE_EFFECTS__ */");
}
reportMap.set(entrypoint, {
log: sideEffects,
hasSideEffects: sideEffects.length > 0,
hasUnexpectedSideEffects,
});
}

console.log = consoleLog;
console.info = consoleInfo;

let failed = false;
for (const [entrypoint, report] of reportMap) {
if (report.hasSideEffects) {
if (report.hasUnexpectedSideEffects) {
failed = true;
console.log("---------------------------------");
console.log(`Tree shaking failed for ${entrypoint}`);
Expand All @@ -104,7 +115,7 @@ export async function checkTreeShaking(options?: TreeShakingArgs) {
}

if (failed) {
process.exit(1);
throw new Error("Tree shaking checks failed.");
} else {
console.log("Tree shaking checks passed!");
}
Expand Down
Loading