Skip to content

Commit

Permalink
webpack loaders: implement emitError and emitWarning (vercel/turb…
Browse files Browse the repository at this point in the history
…orepo#3983)

This implements webpack loader context api for `emitError` and
`emitWarning`, each of which emit Turbopack issues at the appropriate
error level. As with webpack’s implementation, `emitError` does _not_
cause builds to fail [0].

This uses next-dev issue snapshots (vercel/turborepo#3774) to test that issues are
emitted.

[0] https://webpack.js.org/api/loaders/#thisemiterror

---------

Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
  • Loading branch information
wbinnssmith and jridgewell committed Mar 2, 2023
1 parent 9771a60 commit d43d053
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
experimental: {
turbo: {
loaders: {
".emit": ["emit-loader"],
},
},
},
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useEffect } from "react";
import source from "./hello.emit";

export default function Home() {
useEffect(() => {
// Only run on client
import("@turbo/pack-test-harness").then(runTests);
});

return null;
}

function runTests() {
it("runs a simple loader", () => {
// Emitted issues are snapshot in `issues/`
expect(source).toBe(null);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PlainIssue {
severity: Error,
context: "[project]/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit",
category: "loaders",
title: "Issue while running loader",
description: "Error: Error!\n",
detail: "",
documentation_link: "",
source: None,
sub_issues: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PlainIssue {
severity: Warning,
context: "[project]/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit",
category: "loaders",
title: "Issue while running loader",
description: "Error: Warning!\n at Object.module.exports (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:2:20)\n at LOADER_EXECUTION (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:55:17)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at <unknown> (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:35:9)\n at <anonymous>\n at Module.transform (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:28:12)\n at <unknown> (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]__516bc8._.js:13:212)\n at Module.run (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_ipc_evaluate.ts._.js:172:45)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)\n",
detail: "",
documentation_link: "",
source: None,
sub_issues: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PlainIssue {
severity: Error,
context: "[project]/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit",
category: "loaders",
title: "Issue while running loader",
description: "Error: Error!\n at Object.module.exports (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/node_modules/emit-loader/index.js:4:18)\n at LOADER_EXECUTION (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4134)\n at runSyncOrAsync (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4145)\n at iterateNormalLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5782)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5426)\n at readResource (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:55:17)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:6160)\n at processResource (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:5308)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4667)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4764)\n at <unknown> (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4896)\n at handleResult (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:1424)\n at loadLoader (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:963)\n at iteratePitchingLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:4794)\n at runLoaders (node_modules/.pnpm/next@13.1.7-canary.28_pjwopsidmaokadturxaafygjp4/node_modules/next/dist/compiled/loader-runner/LoaderRunner.js:1:8590)\n at <unknown> (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:35:9)\n at <anonymous>\n at Module.transform (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_transforms_webpack-loaders.ts._.js:28:12)\n at <unknown> (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]__516bc8._.js:13:212)\n at Module.run (crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/.next/build/webpack_loaders/chunks/[turbopack-node]_ipc_evaluate.ts._.js:172:45)\n at processTicksAndRejections (node:internal/process/task_queues:96:5)\n",
detail: "",
documentation_link: "",
source: None,
sub_issues: [],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
PlainIssue {
severity: Warning,
context: "[project]/crates/next-dev-tests/tests/integration/next/webpack-loaders/emitted-errors/input/pages/hello.emit",
category: "loaders",
title: "Issue while running loader",
description: "Error: Warning!\n",
detail: "",
documentation_link: "",
source: None,
sub_issues: [],
}
7 changes: 6 additions & 1 deletion crates/turbopack-node/js/src/ipc/evaluate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IPC } from "./index";
import { IPC, StructuredError } from "./index";
import type { Ipc as GenericIpc } from "./index";

type IpcIncomingMessage = {
Expand All @@ -23,6 +23,11 @@ type IpcOutgoingMessage =
type: "dirDependency";
path: string;
glob: string;
}
| {
type: "emittedError";
severity: "warning" | "error";
error: StructuredError;
};

export type Ipc = GenericIpc<IpcIncomingMessage, IpcOutgoingMessage>;
Expand Down
29 changes: 28 additions & 1 deletion crates/turbopack-node/js/src/transforms/webpack-loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import {
dirname,
resolve as pathResolve,
} from "path";
import {
StackFrame,
parse as parseStackTrace,
} from "../compiled/stacktrace-parser";

type LoaderConfig =
| string
Expand Down Expand Up @@ -57,11 +61,13 @@ const transform = (
context: {
rootContext: contextDir,
getOptions() {
var entry = this.loaders[this.loaderIndex];
const entry = this.loaders[this.loaderIndex];
return entry.options && typeof entry.options === "object"
? entry.options
: {};
},
emitWarning: makeErrorEmitter("warning", ipc),
emitError: makeErrorEmitter("error", ipc),
},
loaders: loadersWithOptions.map((loader) => ({
loader: __turbopack_external_require__.resolve(loader.loader, {
Expand Down Expand Up @@ -98,3 +104,24 @@ const transform = (
};

export { transform as default };

function makeErrorEmitter(severity: "warning" | "error", ipc: Ipc) {
return function (error: Error | string) {
ipc.send({
type: "emittedError",
severity: severity,
error:
error instanceof Error
? {
name: error.name,
message: error.message,
stack: parseStackTrace(error.stack),
}
: {
name: "Error",
message: error,
stack: [],
},
});
};
}
55 changes: 55 additions & 0 deletions crates/turbopack-node/src/evaluate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,17 @@ pub async fn evaluate(
cwd.join(&path).read_glob(GlobVc::new(&glob), false),
));
}
EvalJavaScriptIncomingMessage::EmittedError { error, severity } => {
EvaluateEmittedErrorIssue {
context: context_ident_for_issue.path(),
cwd,
error,
severity: severity.cell(),
}
.cell()
.as_issue()
.emit();
}
}
};
// Read dependencies to make them a dependencies of this task. This task will
Expand Down Expand Up @@ -395,3 +406,47 @@ async fn dir_dependency_shallow(glob: ReadGlobResultVc) -> Result<CompletionVc>
}
Ok(CompletionVc::new())
}

#[turbo_tasks::value(shared)]
pub struct EvaluateEmittedErrorIssue {
pub context: FileSystemPathVc,
pub cwd: FileSystemPathVc,
pub severity: IssueSeverityVc,
pub error: StructuredError,
}

#[turbo_tasks::value_impl]
impl Issue for EvaluateEmittedErrorIssue {
#[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc {
self.context
}

#[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc {
self.severity
}

#[turbo_tasks::function]
fn category(&self) -> StringVc {
StringVc::cell("loaders".to_string())
}

#[turbo_tasks::function]
fn title(&self) -> StringVc {
StringVc::cell("Issue while running loader".to_string())
}

#[turbo_tasks::function]
async fn description(&self) -> Result<StringVc> {
let root = to_sys_path(self.cwd.root())
.await?
.context("Must have path on disk")?;

Ok(StringVc::cell(
self.error
.print(Default::default(), &root.to_string_lossy())
.await?,
))
}
}
22 changes: 18 additions & 4 deletions crates/turbopack-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use turbo_tasks_fs::{to_sys_path, File, FileContent, FileSystemPathVc};
use turbopack_core::{
asset::{Asset, AssetVc, AssetsSetVc},
chunk::{ChunkGroupVc, ChunkVc, ChunkingContextVc},
issue::IssueSeverity,
reference::AssetReference,
source_map::{GenerateSourceMap, GenerateSourceMapVc, SourceMapVc},
virtual_asset::VirtualAssetVc,
Expand Down Expand Up @@ -268,10 +269,23 @@ enum EvalJavaScriptOutgoingMessage<'a> {
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
enum EvalJavaScriptIncomingMessage {
FileDependency { path: String },
BuildDependency { path: String },
DirDependency { path: String, glob: String },
JsonValue { data: String },
FileDependency {
path: String,
},
BuildDependency {
path: String,
},
DirDependency {
path: String,
glob: String,
},
JsonValue {
data: String,
},
EmittedError {
severity: IssueSeverity,
error: StructuredError,
},
Error(StructuredError),
}

Expand Down
17 changes: 6 additions & 11 deletions crates/turbopack-node/src/transforms/webpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
use turbo_tasks::{primitives::JsonValueVc, trace::TraceRawVcs, CompletionVc, Value};
use turbo_tasks_fs::{
json::parse_json_rope_with_source_context, File, FileContent, FileSystemPathVc,
};
use turbo_tasks_fs::{json::parse_json_rope_with_source_context, File, FileContent};
use turbopack_core::{
asset::{Asset, AssetContent, AssetContentVc, AssetVc},
context::{AssetContext, AssetContextVc},
ident::AssetIdentVc,
source_asset::SourceAssetVc,
source_transform::{SourceTransform, SourceTransformVc},
virtual_asset::VirtualAssetVc,
};
Expand All @@ -19,7 +18,7 @@ use turbopack_ecmascript::{

use super::util::{emitted_assets_to_virtual_assets, EmittedAsset};
use crate::{
embed_js::embed_file,
embed_js::embed_file_path,
evaluate::{evaluate, JavaScriptValue},
execution_context::{ExecutionContext, ExecutionContextVc},
};
Expand Down Expand Up @@ -116,13 +115,9 @@ struct ProcessWebpackLoadersResult {
}

#[turbo_tasks::function]
fn webpack_loaders_executor(project_path: FileSystemPathVc, context: AssetContextVc) -> AssetVc {
fn webpack_loaders_executor(context: AssetContextVc) -> AssetVc {
EcmascriptModuleAssetVc::new(
VirtualAssetVc::new(
project_path.join("__turbopack__/webpack-loaders-executor.ts"),
AssetContent::File(embed_file("transforms/webpack-loaders.ts")).cell(),
)
.into(),
SourceAssetVc::new(embed_file_path("transforms/webpack-loaders.ts")).into(),
context,
Value::new(EcmascriptModuleAssetType::Typescript),
EcmascriptInputTransformsVc::cell(vec![EcmascriptInputTransform::TypeScript]),
Expand Down Expand Up @@ -155,7 +150,7 @@ impl WebpackLoadersProcessedAssetVc {
let content = content.content().to_str()?;
let context = this.evaluate_context;

let webpack_loaders_executor = webpack_loaders_executor(project_path, context);
let webpack_loaders_executor = webpack_loaders_executor(context);
let resource_fs_path = this.source.ident().path().await?;
let resource_path = resource_fs_path.path.as_str();
let loaders = this.loaders.await?;
Expand Down

0 comments on commit d43d053

Please sign in to comment.