Skip to content

Commit

Permalink
feat(turbopack): basic sass-loader support (#4985)
Browse files Browse the repository at this point in the history
### Description

WEB-654.

This is pairing PR from next.js
vercel/next.js#49882 (not a breaking change
though) to have necessary support to run sass-loader. Mainly, it adds
near-dummy context in `webpack-loaders` as well as assigning specific
module types for the scss / sass.

I'm not entirely in favor of having internal custom module type logic in
webpack loaders setup by extension - however next.config.js itself
doesn't have enough information other than extension + loader to
determine module type. Something would like to address.

---------

Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
  • Loading branch information
kwonoj and jridgewell committed May 18, 2023
1 parent ef9f6b8 commit 4b91af9
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 10 deletions.
79 changes: 79 additions & 0 deletions crates/turbopack-node/js/src/transforms/webpack-loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,60 @@ const toPath = (file: string) => {
return sep !== "/" ? relPath.replaceAll(sep, "/") : relPath;
};

const LogType = Object.freeze({
error: "error",
warn: "warn",
info: "info",
log: "log",
debug: "debug",

trace: "trace",

group: "group",
groupCollapsed: "groupCollapsed",
groupEnd: "groupEnd",

profile: "profile",
profileEnd: "profileEnd",

time: "time",

clear: "clear",
status: "status",
});

const loaderFlag = "LOADER_EXECUTION";

const cutOffByFlag = (stack, flag) => {
const errorStack = stack.split("\n");
for (let i = 0; i < errorStack.length; i++) {
if (errorStack[i].includes(flag)) {
errorStack.length = i;
}
}
return errorStack.join("\n");
};

/**
* @param {string} stack stack trace
* @returns {string} stack trace without the loader execution flag included
*/
const cutOffLoaderExecution = (stack) => cutOffByFlag(stack, loaderFlag);

class DummySpan {
traceChild() {
return new DummySpan();
}

traceFn<T>(fn: (span: DummySpan) => T): T {
return fn(this);
}

async traceAsyncFn<T>(fn: (span: DummySpan) => T | Promise<T>): Promise<T> {
return await fn(this);
}
}

const transform = (
ipc: Ipc,
content: string,
Expand All @@ -59,16 +113,41 @@ const transform = (
{
resource,
context: {
currentTraceSpan: new DummySpan(),
rootContext: contextDir,
getOptions() {
const entry = this.loaders[this.loaderIndex];
return entry.options && typeof entry.options === "object"
? entry.options
: {};
},
getResolve: () => ({
// [TODO] this is incomplete
}),
emitWarning: makeErrorEmitter("warning", ipc),
emitError: makeErrorEmitter("error", ipc),
getLogger: (name) => (type, args) => {
let trace;
switch (type) {
case LogType.warn:
case LogType.error:
case LogType.trace:
trace = cutOffLoaderExecution(new Error("Trace").stack)
.split("\n")
.slice(3);
break;
}
const logEntry = {
time: Date.now(),
type,
args,
trace,
};

this.hooks.log.call(name, logEntry);
},
},

loaders: loadersWithOptions.map((loader) => ({
loader: __turbopack_external_require__.resolve(loader.loader, {
paths: [resourceDir],
Expand Down
13 changes: 9 additions & 4 deletions crates/turbopack/src/module_options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,15 @@ impl ModuleOptionsVc {
ModuleRuleCondition::not(ModuleRuleCondition::ResourceIsVirtualAsset),
]),
vec![
ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
transforms: app_transforms,
options: ecmascript_options.clone(),
}),
// [TODO]: should accept rules as an option
if ext == ".scss" || ext == ".sass" {
ModuleRuleEffect::ModuleType(ModuleType::Css(css_transforms))
} else {
ModuleRuleEffect::ModuleType(ModuleType::Ecmascript {
transforms: app_transforms,
options: ecmascript_options.clone(),
})
},
ModuleRuleEffect::SourceTransforms(SourceTransformsVc::cell(vec![
WebpackLoadersVc::new(
node_evaluate_asset_context(
Expand Down
8 changes: 2 additions & 6 deletions crates/turbopack/src/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ use turbopack_ecmascript::typescript::resolve::{
apply_tsconfig_resolve_options, tsconfig, tsconfig_resolve_options,
};

use crate::{
resolve_options_context::ResolveOptionsContextVc,
unsupported_sass::UnsupportedSassResolvePluginVc,
};
use crate::resolve_options_context::ResolveOptionsContextVc;

const NODE_EXTERNALS: [&str; 51] = [
"assert",
Expand Down Expand Up @@ -112,8 +109,7 @@ async fn base_resolve_options(
}
let import_map = import_map.cell();

let mut plugins = opt.plugins.clone();
plugins.push(UnsupportedSassResolvePluginVc::new(root).as_resolve_plugin());
let plugins = opt.plugins.clone();

Ok(ResolveOptions {
extensions: if let Some(environment) = emulating {
Expand Down

0 comments on commit 4b91af9

Please sign in to comment.