Revert "Revert "feat(next-core): support unsupported module runtime error (#63491)"" (#63609)

### What

This PR reenables reverted PR #63491, with fixing unexpectedly mark
supported node.js internals as unsupported.

Tried to add test cases for the supported case but hitting
https://vercel.slack.com/archives/C03EWR7LGEN/p1711128538909549, need
separate investigation.
This commit is contained in:
OJ Kwon 2024-03-22 11:50:54 -07:00 committed by GitHub
parent 8e8a86ee8f
commit 07a39eed2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 165 additions and 15 deletions

View file

@ -1,3 +1,4 @@
pub mod context;
pub mod entry;
pub mod route_regex;
pub mod unsupported;

View file

@ -0,0 +1,77 @@
use anyhow::Result;
use indoc::formatdoc;
use turbo_tasks::Vc;
use turbo_tasks_fs::File;
use turbopack_binding::{
turbo::tasks_fs::FileSystemPath,
turbopack::{
core::{
asset::AssetContent,
resolve::{
options::{ImportMapResult, ImportMapping, ImportMappingReplacement},
parse::Request,
ResolveResult,
},
virtual_source::VirtualSource,
},
node::execution_context::ExecutionContext,
},
};
/// Intercepts requests for the given request to `unsupported` error messages
/// by returning a VirtualSource proxies to any import request to raise a
/// runtime error.
///
/// This can be used by import map alias, refer `next_import_map` for the setup.
#[turbo_tasks::value(shared)]
pub struct NextEdgeUnsupportedModuleReplacer {
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
}
#[turbo_tasks::value_impl]
impl NextEdgeUnsupportedModuleReplacer {
#[turbo_tasks::function]
pub fn new(
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
) -> Vc<Self> {
Self::cell(NextEdgeUnsupportedModuleReplacer {
project_path,
execution_context,
})
}
}
#[turbo_tasks::value_impl]
impl ImportMappingReplacement for NextEdgeUnsupportedModuleReplacer {
#[turbo_tasks::function]
fn replace(&self, _capture: String) -> Vc<ImportMapping> {
ImportMapping::Ignore.into()
}
#[turbo_tasks::function]
async fn result(
&self,
context: Vc<FileSystemPath>,
request: Vc<Request>,
) -> Result<Vc<ImportMapResult>> {
let request = &*request.await?;
if let Request::Module { module, .. } = request {
// packages/next/src/server/web/globals.ts augments global with
// `__import_unsupported` and necessary functions.
let code = formatdoc! {
r#"
__turbopack_export_namespace__(__import_unsupported(`{module}`));
"#
};
let content = AssetContent::file(File::from(code).into());
let source = VirtualSource::new(context, content);
return Ok(
ImportMapResult::Result(ResolveResult::source(Vc::upcast(source)).into()).into(),
);
};
Ok(ImportMapResult::NoEntry.into())
}
}

View file

@ -26,6 +26,7 @@ use crate::{
mode::NextMode,
next_client::context::ClientContextType,
next_config::NextConfig,
next_edge::unsupported::NextEdgeUnsupportedModuleReplacer,
next_font::{
google::{
NextFontGoogleCssModuleReplacer, NextFontGoogleFontFileReplacer, NextFontGoogleReplacer,
@ -38,6 +39,58 @@ use crate::{
util::NextRuntime,
};
/// List of node.js internals that are not supported by edge runtime.
/// If these imports are used & user does not provide alias for the polyfill,
/// runtime error will be thrown.
/// This is not identical to the list of entire node.js internals, refer
/// https://vercel.com/docs/functions/runtimes/edge-runtime#compatible-node.js-modules
/// for the allowed imports.
const EDGE_UNSUPPORTED_NODE_INTERNALS: [&str; 43] = [
"child_process",
"cluster",
"console",
"constants",
"dgram",
"diagnostics_channel",
"dns",
"dns/promises",
"domain",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"path/posix",
"path/win32",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"stream/promises",
"stream/web",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tls",
"trace_events",
"tty",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib",
"pnpapi",
];
// Make sure to not add any external requests here.
/// Computes the Next-specific client import map.
#[turbo_tasks::function]
@ -416,9 +469,29 @@ pub async fn get_next_edge_import_map(
)
.await?;
insert_unsupported_node_internal_aliases(&mut import_map, project_path, execution_context);
Ok(import_map.cell())
}
/// Insert default aliases for the node.js's internal to raise unsupported
/// runtime errors. User may provide polyfills for their own by setting user
/// config's alias.
fn insert_unsupported_node_internal_aliases(
import_map: &mut ImportMap,
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
) {
let unsupported_replacer = ImportMapping::Dynamic(Vc::upcast(
NextEdgeUnsupportedModuleReplacer::new(project_path, execution_context),
))
.into();
EDGE_UNSUPPORTED_NODE_INTERNALS.iter().for_each(|module| {
import_map.insert_alias(AliasPattern::exact(*module), unsupported_replacer);
});
}
pub fn get_next_client_resolved_map(
_context: Vc<FileSystemPath>,
_root: Vc<FileSystemPath>,

View file

@ -55,7 +55,10 @@ export function expectUnsupportedModuleDevError(
output = context.logs.output
) {
expectUnsupportedModuleProdError(moduleName, output)
expect(stripAnsi(output)).toContain(importStatement)
// turbopack have correct error overly, but doesn't emit those into cli
if (!process.env.TURBOPACK) {
expect(stripAnsi(output)).toContain(importStatement)
}
const moduleNotSupportedMessage = getUnsupportedModule(moduleName)
expect(responseText).toContain(escapeLF(moduleNotSupportedMessage))

View file

@ -9531,21 +9531,17 @@
"test/integration/edge-runtime-module-errors/test/index.test.js": {
"passed": [
"Edge runtime code with imports Edge API importing vanilla 3rd party module does not throw in dev at runtime",
"Edge runtime code with imports Edge API using Buffer polyfill does not throw in dev at runtime",
"Edge runtime code with imports Middleware importing vanilla 3rd party module does not throw in dev at runtime",
"Edge runtime code with imports Edge API dynamically importing node.js module development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Edge API dynamically importing node.js module in a lib development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module in a lib development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Edge API using Buffer polyfill does not throw in dev at runtime",
"Edge runtime code with imports Middleware using Buffer polyfill does not throw in dev at runtime",
"Edge runtime code with imports Edge API statically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware statically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line"
],
"failed": [
"Edge runtime code with imports Edge API dynamically importing node.js module development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Edge API dynamically importing node.js module in a lib development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module in a lib development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module development mode throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing node.js module in a lib development mode throws unsupported module error in dev at runtime and highlights the faulty line"
],
"failed": [],
"pending": [
"Edge runtime code with imports Edge API dynamically importing node.js module in a lib production mode throws unsupported module error in production at runtime and prints error on logs",
"Edge runtime code with imports Edge API dynamically importing node.js module production mode throws unsupported module error in production at runtime and prints error on logs",
@ -9563,16 +9559,16 @@
},
"test/integration/edge-runtime-module-errors/test/module-imports.test.js": {
"passed": [
"Edge runtime code with imports Edge API importing unused node.js module does not throw in dev at runtime"
"Edge runtime code with imports Edge API importing unused node.js module does not throw in dev at runtime",
"Edge runtime code with imports Middleware importing unused node.js module does not throw in dev at runtime",
"Edge runtime code with imports Edge API statically importing node.js module throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware statically importing node.js module throws unsupported module error in dev at runtime and highlights the faulty line"
],
"failed": [
"Edge runtime code with imports Edge API dynamically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Edge API importing unused 3rd party module throws not-found module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Edge API statically importing node.js module throws unsupported module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware dynamically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware importing unused 3rd party module throws not-found module error in dev at runtime and highlights the faulty line",
"Edge runtime code with imports Middleware importing unused node.js module does not throw in dev at runtime",
"Edge runtime code with imports Middleware statically importing node.js module throws unsupported module error in dev at runtime and highlights the faulty line"
"Edge runtime code with imports Middleware importing unused 3rd party module throws not-found module error in dev at runtime and highlights the faulty line"
],
"pending": [
"Edge runtime code with imports Edge API dynamically importing 3rd party module production mode does not build and reports module not found error",