diff --git a/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs b/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs index f877ba4245bff..6aa0ec2cb076c 100644 --- a/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs +++ b/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs @@ -35,8 +35,8 @@ pub async fn get_swc_ecma_transform_rule_impl( plugin_configs: &[(RcStr, serde_json::Value)], enable_mdx_rs: bool, ) -> Result> { - use anyhow::{bail, Context}; - use turbo_tasks::{TryJoinIterExt, Value}; + use anyhow::bail; + use turbo_tasks::{TryFlatJoinIterExt, Value}; use turbo_tasks_fs::FileContent; use turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext}; use turbopack_core::{ @@ -78,30 +78,34 @@ pub async fn get_swc_ecma_transform_rule_impl( ) .as_raw_module_result(), Value::new(ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined)), + // TODO proper error location *project_path, request, resolve_options, false, + // TODO proper error location None, ) .await?; - let plugin_module = plugin_wasm_module_resolve_result - .first_module() - .await? - .context("Expected to find module")?; - let content = &*plugin_module.content().file_content().await?; + let Some(plugin_module) = &*plugin_wasm_module_resolve_result.first_module().await? + else { + // Ignore unresolveable plugin modules, handle_resolve_error has already emitted an + // issue. + return Ok(None); + }; + let content = &*plugin_module.content().file_content().await?; let FileContent::Content(file) = content else { bail!("Expected file content for plugin module"); }; - Ok(( + Ok(Some(( SwcPluginModule::new(name, file.content().to_bytes()?.to_vec()).resolved_cell(), config.clone(), - )) + ))) }) - .try_join() + .try_flat_join() .await?; Ok(Some(get_ecma_transform_rule( diff --git a/test/e2e/swc-plugins/app/layout.js b/test/e2e/swc-plugins/app/layout.js new file mode 100644 index 0000000000000..9342eed18c78f --- /dev/null +++ b/test/e2e/swc-plugins/app/layout.js @@ -0,0 +1,9 @@ +import React from 'react' + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} diff --git a/test/e2e/swc-plugins/app/page.js b/test/e2e/swc-plugins/app/page.js new file mode 100644 index 0000000000000..e5e30cce60408 --- /dev/null +++ b/test/e2e/swc-plugins/app/page.js @@ -0,0 +1,5 @@ +import React from 'react' + +export default function Page({ children }) { + return
Hello World
+} diff --git a/test/e2e/swc-plugins/index.test.ts b/test/e2e/swc-plugins/index.test.ts new file mode 100644 index 0000000000000..8c5c70af08ebe --- /dev/null +++ b/test/e2e/swc-plugins/index.test.ts @@ -0,0 +1,58 @@ +import { nextTestSetup, isNextDev } from 'e2e-utils' + +describe('swcPlugins', () => { + describe('supports swcPlugins', () => { + const { next, skipped } = nextTestSetup({ + files: __dirname, + skipDeployment: true, + dependencies: { + '@swc/plugin-react-remove-properties': '7.0.2', + }, + }) + if (skipped) return + + it('basic case', async () => { + const html = await next.render('/') + expect(html).toContain('Hello World') + expect(html).not.toContain('data-custom-attribute') + }) + }) + ;(isNextDev ? describe : describe.skip)('invalid plugin name', () => { + const { next, skipped, isTurbopack } = nextTestSetup({ + files: __dirname, + skipDeployment: true, + overrideFiles: { + 'next.config.js': ` +module.exports = { + experimental: { + swcPlugins: [['@swc/plugin-nonexistent', {}]], + }, +}`, + }, + }) + if (skipped) return + + it('shows a redbox in dev', async () => { + const browser = await next.browser('/') + + if (isTurbopack) { + await expect(browser).toDisplayRedbox(` + { + "description": "Module not found: Can't resolve '@swc/plugin-nonexistent'", + "environmentLabel": null, + "label": "Build Error", + "source": "./ + Module not found: Can't resolve '@swc/plugin-nonexistent' + https://nextjs.org/docs/messages/module-not-found", + "stack": [], + } + `) + } else { + // TODO missing proper error with Webpack + await expect(browser).toDisplayRedbox( + `"Expected Redbox but found no visible one."` + ) + } + }) + }) +}) diff --git a/test/e2e/swc-plugins/next.config.js b/test/e2e/swc-plugins/next.config.js new file mode 100644 index 0000000000000..3acbf16005e7a --- /dev/null +++ b/test/e2e/swc-plugins/next.config.js @@ -0,0 +1,13 @@ +/** @type {import('next').NextConfig} */ +module.exports = { + experimental: { + swcPlugins: [ + [ + '@swc/plugin-react-remove-properties', + { + properties: ['^data-custom-attribute$'], + }, + ], + ], + }, +}