Skip to content
Closed
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
42 changes: 0 additions & 42 deletions crates/pack-api/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use pack_core::{
};
use serde::{Deserialize, Serialize};
use std::{
fs,
path::{Path, PathBuf},
time::Duration,
};
Expand Down Expand Up @@ -1375,18 +1374,6 @@ impl Project {
) -> Result<()> {
let span = tracing::trace_span!("emitting");
async move {
// clean dist director if configured
if self.config().output().await?.clean.is_some_and(|c| c) {
let this = self.await?;
let dist_dir = self.dist_dir().await?;

// Construct the complete absolute path by combining project_path and dist_dir
let dist_path = Path::new(&this.project_path).join(&*dist_dir);

if let Err(e) = clean_directory(&dist_path) {
tracing::debug!("Failed to clean dist directory: {}", e);
}
}
let client_root = self.client_root().owned().await?;
let client_output = self.dist_root().owned().await?;
let output_root = self.output_fs().root().owned().await?;
Expand Down Expand Up @@ -1824,35 +1811,6 @@ async fn all_assets_from_entries_operation(
Ok(all_assets_from_entries(assets))
}

fn clean_directory(dist_path: &Path) -> Result<()> {
let canonical_path = fs::canonicalize(dist_path)
.with_context(|| format!("Failed to canonicalize path: {}", dist_path.display()))?;

if canonical_path.exists() {
tracing::info!("Cleaning dist directory: {}", canonical_path.display());

// Read directory entries
for entry in fs::read_dir(&canonical_path)? {
let entry = entry?;
let path = entry.path();

if path.is_dir() {
if let Err(e) = fs::remove_dir_all(&path) {
tracing::warn!("Failed to remove directory {}: {}", path.display(), e);
}
} else if let Err(e) = fs::remove_file(&path) {
tracing::warn!("Failed to remove file {}: {}", path.display(), e);
}
}

tracing::info!("Dist directory cleaned successfully");
} else {
tracing::debug!("Dist directory does not exist, skipping clean");
}

Ok(())
}

#[cfg(test)]
mod tests {
use super::strip_root_prefix;
Expand Down
11 changes: 7 additions & 4 deletions packages/pack/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { BundleOptions } from "../config/types";
import { resolveBundleOptions, WebpackConfig } from "../config/webpackCompat";
import { projectFactory } from "../core/project";
import { HtmlPlugin } from "../plugins/HtmlPlugin";
import { cleanOutput, getOutputPath } from "../utils/cleanOutput";
import { blockStdout, getPackPath } from "../utils/common";
import { findRootDir } from "../utils/findRoot";
import { getInitialAssetsFromStats } from "../utils/getInitialAssets";
import { processHtmlEntry } from "../utils/htmlEntry";
import { normalizePath } from "../utils/normalize-path";
import { normalizePath } from "../utils/normalizePath";
import { useWorkerThreads } from "../utils/runtimePluginStratety";
import { validateEntryPaths } from "../utils/validateEntry";
import { xcodeProfilingReady } from "../utils/xcodeProfile";
Expand Down Expand Up @@ -46,6 +47,7 @@ async function buildInternal(
const persistentCaching = bundleOptions.config.persistentCaching ?? false;
processHtmlEntry(bundleOptions.config, resolvedProjectPath);
validateEntryPaths(bundleOptions.config, resolvedProjectPath);
await cleanOutput(bundleOptions.config, resolvedProjectPath);

const createProject = projectFactory();
const project = await createProject(
Expand Down Expand Up @@ -98,8 +100,7 @@ async function buildInternal(
if (htmlConfigs.length > 0) {
const assets = { js: [] as string[], css: [] as string[] };

const outputDir =
bundleOptions.config.output?.path || path.join(process.cwd(), "dist");
const outputDir = getOutputPath(bundleOptions.config, resolvedProjectPath);

if (assets.js.length === 0 && assets.css.length === 0) {
const discovered = getInitialAssetsFromStats(outputDir);
Expand All @@ -116,7 +117,9 @@ async function buildInternal(
}

if (process.env.ANALYZE) {
await analyzeBundle(bundleOptions.config.output?.path || "dist");
await analyzeBundle(
getOutputPath(bundleOptions.config, resolvedProjectPath),
);
}
await project.shutdown();

Expand Down
9 changes: 3 additions & 6 deletions packages/pack/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import {
} from "../config/webpackCompat";
import type { HotReloaderInterface } from "../core/hmr";
import { createHotReloader } from "../core/hmr";
import { createHttpProxyMiddleware } from "../core/proxy-hono";
import { createHttpProxyMiddleware } from "../core/proxyHono";
import { getOutputPath } from "../utils/cleanOutput";
import { blockStdout, getPackPath } from "../utils/common";
import { findRootDir } from "../utils/findRoot";
import { createSelfSignedCertificate } from "../utils/mkcert";
import { printServerInfo } from "../utils/printServerInfo";
import { useWorkerThreads } from "../utils/runtimePluginStratety";
import { xcodeProfilingReady } from "../utils/xcodeProfile";

// --- Path helpers (same logic as dev.ts, not exported) ---
Expand Down Expand Up @@ -242,10 +242,7 @@ async function runDev(
);
await hotReloader.start();

const distRoot = path.resolve(
projectPathResolved,
options.config?.output?.path || "./dist",
);
const distRoot = getOutputPath(options.config, projectPathResolved);
const publicPath = options.config?.output?.publicPath;
// Skip prefix stripping for "runtime" and when publicPath is absent (match dev.ts).
const normalizedPrefix =
Expand Down
8 changes: 4 additions & 4 deletions packages/pack/src/core/hmr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import {
import { IncomingMessage } from "http";
import { nanoid } from "nanoid";
import type { Socket } from "net";
import path from "path";
import { Duplex } from "stream";
import { WebSocketServer } from "ws";
import { BundleOptions } from "../config/types";
import { HtmlPlugin } from "../plugins/HtmlPlugin";
import { cleanOutput, getOutputPath } from "../utils/cleanOutput";
import { debounce, getPackPath, processIssues } from "../utils/common";
import { getInitialAssetsFromStats } from "../utils/getInitialAssets";
import { processHtmlEntry } from "../utils/htmlEntry";
import { normalizePath } from "../utils/normalize-path";
import { normalizePath } from "../utils/normalizePath";
import { useWorkerThreads } from "../utils/runtimePluginStratety";
import { validateEntryPaths } from "../utils/validateEntry";
import { projectFactory } from "./project";
Expand Down Expand Up @@ -112,6 +112,7 @@ export async function createHotReloader(
const resolvedRootPath = rootPath || projectPath || process.cwd();
processHtmlEntry(bundleOptions.config, resolvedProjectPath);
validateEntryPaths(bundleOptions.config, resolvedProjectPath);
await cleanOutput(bundleOptions.config, resolvedProjectPath);

const createProject = projectFactory();

Expand Down Expand Up @@ -226,8 +227,7 @@ export async function createHotReloader(
return;
}

const outputDir =
bundleOptions.config.output?.path || path.join(process.cwd(), "dist");
const outputDir = getOutputPath(bundleOptions.config, resolvedProjectPath);
const publicPath = bundleOptions.config.output?.publicPath;
const assets = getInitialAssetsFromStats(outputDir);

Expand Down
2 changes: 1 addition & 1 deletion packages/pack/src/core/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
TurbopackRuleConfigItem,
} from "../config/types";
import { getPackPath, rustifyEnv } from "../utils/common";
import { normalizePath } from "../utils/normalize-path";
import { normalizePath } from "../utils/normalizePath";
import { runLoaderWorkerPool } from "./loaderWorkerPool";
import {
Endpoint,
Expand Down
40 changes: 40 additions & 0 deletions packages/pack/src/utils/cleanOutput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import fs from "fs";
import path from "path";
import type { ConfigComplete } from "../config/types";

export function getOutputPath(config: ConfigComplete, projectPath: string) {
return path.resolve(projectPath, config.output?.path || "dist");
}

export async function cleanOutput(config: ConfigComplete, projectPath: string) {
if (!config.output?.clean) {
return;
}

const outputPath = getOutputPath(config, projectPath);
let entries: fs.Dirent[];

try {
entries = await fs.promises.readdir(outputPath, { withFileTypes: true });
} catch (error) {
if (isNodeError(error) && error.code === "ENOENT") {
return;
}
throw error;
}

await Promise.all(
entries.map((entry) =>
fs.promises.rm(path.join(outputPath, entry.name), {
force: true,
maxRetries: 3,
recursive: true,
retryDelay: 50,
}),
),
);
}

function isNodeError(error: unknown): error is NodeJS.ErrnoException {
return error instanceof Error && "code" in error;
}
Loading