Skip to content
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
5 changes: 5 additions & 0 deletions .changeset/big-pillows-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@swc/cli": patch
---

Revert "fix(cli): Fix configuration reuse issue in swcDir() by deep clone"
14 changes: 5 additions & 9 deletions packages/cli/src/swc/dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { stderr } from "process";
import { format } from "util";
import { CompileStatus } from "./constants";
import { Callbacks, CliOptions } from "./options";
import { exists, getDest, mapTsExt, deepClone } from "./util";
import { exists, getDest, mapTsExt } from "./util";
import handleCompile from "./dirWorker";
import {
globSources,
Expand Down Expand Up @@ -401,16 +401,12 @@ export default async function dir({
swcOptions: Options;
callbacks?: Callbacks;
}) {
// Deep clone the options to ensure full isolation between multiple calls
const clonedCliOptions = deepClone(cliOptions);
const clonedSwcOptions = deepClone(swcOptions);
const { watch } = cliOptions;

const { watch } = clonedCliOptions;

await beforeStartCompilation(clonedCliOptions);
await initialCompilation(clonedCliOptions, clonedSwcOptions, callbacks);
await beforeStartCompilation(cliOptions);
await initialCompilation(cliOptions, swcOptions, callbacks);

if (watch) {
await watchCompilation(clonedCliOptions, clonedSwcOptions, callbacks);
await watchCompilation(cliOptions, swcOptions, callbacks);
}
}
42 changes: 13 additions & 29 deletions packages/cli/src/swc/dirWorker.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import slash from "slash";
import { dirname, relative } from "path";
import { CompileStatus } from "./constants";
import { compile, getDest, mapDtsExt, mapTsExt, deepClone } from "./util";
import { compile, getDest, mapDtsExt, mapTsExt } from "./util";
import { outputResult } from "./compile";

import type { Options } from "@swc/core";
Expand All @@ -15,45 +15,29 @@ export default async function handleCompile(opts: {
swcOptions: Options;
outFileExtension?: string;
}) {
// Create a deep clone of the options to prevent shared references
const clonedOpts = deepClone(opts);

const dest = getDest(
clonedOpts.filename,
clonedOpts.outDir,
clonedOpts.cliOptions.stripLeadingPaths,
`.${clonedOpts.outFileExtension ?? mapTsExt(clonedOpts.filename)}`
opts.filename,
opts.outDir,
opts.cliOptions.stripLeadingPaths,
`.${opts.outFileExtension ?? mapTsExt(opts.filename)}`
);
const sourceFileName = slash(relative(dirname(dest), clonedOpts.filename));

// Create a fresh copy of the swcOptions
const options = deepClone(clonedOpts.swcOptions);
const sourceFileName = slash(relative(dirname(dest), opts.filename));

// Set sourceFileName in the options
options.sourceFileName = sourceFileName;
const options = { ...opts.swcOptions, sourceFileName };

// Ensure we have the right extension for output files
// Instead of directly setting on module.outFileExtension (which might not exist in the type),
// we'll pass it separately to the compile function

const result = await compile(
clonedOpts.filename,
options,
clonedOpts.sync,
dest
);
const result = await compile(opts.filename, options, opts.sync, dest);

if (result) {
const destDts = getDest(
clonedOpts.filename,
clonedOpts.outDir,
clonedOpts.cliOptions.stripLeadingPaths,
`.${mapDtsExt(clonedOpts.filename)}`
opts.filename,
opts.outDir,
opts.cliOptions.stripLeadingPaths,
`.${mapDtsExt(opts.filename)}`
);
const destSourcemap = dest + ".map";
await outputResult({
output: result,
sourceFile: clonedOpts.filename,
sourceFile: opts.filename,
destFile: dest,
destDtsFile: destDts,
destSourcemapFile: destSourcemap,
Expand Down
38 changes: 2 additions & 36 deletions packages/cli/src/swc/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,6 @@ import { mkdirSync, writeFileSync, promises } from "fs";
import { dirname, extname, join, relative } from "path";
import { stderr } from "process";

/**
* Deep clone an object to ensure no shared references
* @param obj The object to clone
* @returns A new deep-cloned object
*/
export function deepClone<T>(obj: T): T {
if (obj === null || typeof obj !== "object") {
return obj;
}

if (Array.isArray(obj)) {
return (obj.map(item => deepClone(item)) as unknown) as T;
}

const result = {} as T;
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}

export async function exists(path: string): Promise<boolean> {
let pathExists = true;
try {
Expand Down Expand Up @@ -66,22 +43,11 @@ export async function compile(
sync: boolean,
outputPath: string | undefined
): Promise<swc.Output | void> {
// Deep clone the options to ensure we don't have any shared references
opts = deepClone({
opts = {
...opts,
});

};
if (outputPath) {
opts.outputPath = outputPath;

// Extract the extension from the output path to ensure module resolution uses it
const ext = extname(outputPath);
if (ext && opts.module && typeof opts.module === "object") {
// Force the module to use the correct extension for import path resolution
// This explicit setting helps ensure we don't reuse cached module config
// @ts-ignore: Adding a custom property that might not be in the type definition
opts.module.forcedOutputFileExtension = ext.slice(1); // Remove the leading dot
}
}

try {
Expand Down
Loading