diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml
index e2b02075f956a6d..ef3e5b93f3ccfd5 100644
--- a/.github/workflows/build_test_deploy.yml
+++ b/.github/workflows/build_test_deploy.yml
@@ -88,6 +88,44 @@ jobs:
- run: ./scripts/check-manifests.js
- run: yarn lint
+ rust-check:
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - name: Install
+ uses: actions-rs/toolchain@v1
+ if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
+ with:
+ profile: minimal
+ toolchain: nightly-2021-11-15
+ components: rustfmt, clippy
+
+ - name: Cache cargo registry
+ uses: actions/cache@v2
+ if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
+ with:
+ path: ~/.cargo/registry
+ key: stable-ubuntu-clippy-cargo-registry
+
+ - name: Cache cargo index
+ uses: actions/cache@v2
+ if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
+ with:
+ path: ~/.cargo/git
+ key: stable-ubuntu-clippy-cargo-index
+
+ - uses: actions/cache@v2
+ id: restore-build
+ with:
+ path: ./*
+ key: ${{ github.sha }}-${{ github.run_number }}-${{ github.run_attempt }}
+
+ - name: Check
+ run: |
+ cargo fmt -- --check
+ cargo clippy --all -- -D warnings
+ working-directory: packages/next-swc
+
checkPrecompiled:
name: Check Pre-compiled
runs-on: ubuntu-latest
@@ -610,14 +648,14 @@ jobs:
toolchain: nightly-2021-11-15
- name: Cache cargo registry
- uses: actions/cache@v1
+ uses: actions/cache@v2
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
with:
path: ~/.cargo/registry
key: stable-ubuntu-18.04-cargo-registry
- name: Cache cargo index
- uses: actions/cache@v1
+ uses: actions/cache@v2
if: ${{ steps.docs-change.outputs.DOCS_CHANGE != 'docs only change' }}
with:
path: ~/.cargo/git
diff --git a/docs/advanced-features/output-file-tracing.md b/docs/advanced-features/output-file-tracing.md
index dce5f2cc628606d..7ca97b5b19daa10 100644
--- a/docs/advanced-features/output-file-tracing.md
+++ b/docs/advanced-features/output-file-tracing.md
@@ -34,7 +34,7 @@ module.exports = {
This will create a folder at `.next/standalone` which can then be deployed on it's own without installing `node_modules`.
-Additionally, a minimal `server.js` file is also output which can be used instead of `next start`. This minimal server does not copy the `.next/static` directory by default as this should ideally be handled by a CDN instead, although it can be copied to the `standalone` folder manually and the `server.js` file will serve it automatically.
+Additionally, a minimal `server.js` file is also output which can be used instead of `next start`. This minimal server does not copy the `public` or `.next/static` folders by default as these should ideally be handled by a CDN instead, although these folders can be copied to the `standalone` folder manually and the `server.js` file will serve it automatically.
## Caveats
diff --git a/docs/faq.md b/docs/faq.md
index cd97832dfbcf5b1..fe9ca683803402b 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -7,7 +7,7 @@ description: Get to know more about Next.js with the frequently asked questions.
Is Next.js production ready?
Yes! Next.js is used by many of the top websites in the world. See the
- Showcase for more info.
+ Showcase for more info.
diff --git a/errors/swc-disabled.md b/errors/swc-disabled.md
index 701f260c785b4c6..ce026dd0e882e25 100644
--- a/errors/swc-disabled.md
+++ b/errors/swc-disabled.md
@@ -10,8 +10,6 @@ When an application has custom Babel configuration Next.js will automatically op
Many of the integrations with external libraries that currently require custom Babel transformations will be ported to Rust-based SWC transforms in the near future. These include but are not limited to:
-- Styled Components
- Emotion
-- Relay
In order to prioritize transforms that will help you adopt SWC please provide your `.babelrc` on [the feedback thread](https://github.com/vercel/next.js/discussions/30174).
diff --git a/examples/with-tailwindcss/prettier.config.js b/examples/with-tailwindcss/prettier.config.js
index f18d82f4928bd2a..3f714ac456ec4e6 100644
--- a/examples/with-tailwindcss/prettier.config.js
+++ b/examples/with-tailwindcss/prettier.config.js
@@ -1,6 +1,4 @@
module.exports = {
- arrowParens: 'always',
singleQuote: true,
- tabWidth: 2,
semi: false,
}
diff --git a/packages/next-swc/crates/core/src/amp_attributes.rs b/packages/next-swc/crates/core/src/amp_attributes.rs
index b222d019d4a4e55..a5935641edd92eb 100644
--- a/packages/next-swc/crates/core/src/amp_attributes.rs
+++ b/packages/next-swc/crates/core/src/amp_attributes.rs
@@ -1,63 +1,63 @@
use swc_atoms::JsWord;
use swc_ecmascript::ast::{
- Ident, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXElementName, JSXOpeningElement,
+ Ident, JSXAttr, JSXAttrName, JSXAttrOrSpread, JSXElementName, JSXOpeningElement,
};
use swc_ecmascript::visit::Fold;
pub fn amp_attributes() -> impl Fold {
- AmpAttributePatcher::default()
+ AmpAttributePatcher::default()
}
#[derive(Debug, Default)]
struct AmpAttributePatcher {}
impl Fold for AmpAttributePatcher {
- fn fold_jsx_opening_element(&mut self, node: JSXOpeningElement) -> JSXOpeningElement {
- let JSXOpeningElement {
- name,
- mut attrs,
- span,
- self_closing,
- type_args,
- } = node;
- let n = name.clone();
-
- if let JSXElementName::Ident(Ident { sym, .. }) = name {
- if sym.starts_with("amp-") {
- for i in 0..attrs.len() {
- if let JSXAttrOrSpread::JSXAttr(JSXAttr {
- name:
- JSXAttrName::Ident(Ident {
- sym,
- span: s,
- optional: o,
- }),
+ fn fold_jsx_opening_element(&mut self, node: JSXOpeningElement) -> JSXOpeningElement {
+ let JSXOpeningElement {
+ name,
+ mut attrs,
span,
- value,
- }) = &attrs[i]
- {
- if sym as &str == "className" {
- attrs[i] = JSXAttrOrSpread::JSXAttr(JSXAttr {
- name: JSXAttrName::Ident(Ident {
- sym: JsWord::from("class"),
- span: s.clone(),
- optional: o.clone(),
- }),
- span: span.clone(),
- value: value.clone(),
- })
+ self_closing,
+ type_args,
+ } = node;
+ let n = name.clone();
+
+ if let JSXElementName::Ident(Ident { sym, .. }) = name {
+ if sym.starts_with("amp-") {
+ for i in &mut attrs {
+ if let JSXAttrOrSpread::JSXAttr(JSXAttr {
+ name:
+ JSXAttrName::Ident(Ident {
+ sym,
+ span: s,
+ optional: o,
+ }),
+ span,
+ value,
+ }) = &i
+ {
+ if sym as &str == "className" {
+ *i = JSXAttrOrSpread::JSXAttr(JSXAttr {
+ name: JSXAttrName::Ident(Ident {
+ sym: JsWord::from("class"),
+ span: *s,
+ optional: *o,
+ }),
+ span: *span,
+ value: value.clone(),
+ })
+ }
+ }
+ }
}
- }
}
- }
- }
- JSXOpeningElement {
- name: n,
- attrs,
- span,
- self_closing,
- type_args,
+ JSXOpeningElement {
+ name: n,
+ attrs,
+ span,
+ self_closing,
+ type_args,
+ }
}
- }
}
diff --git a/packages/next-swc/crates/core/src/auto_cjs/mod.rs b/packages/next-swc/crates/core/src/auto_cjs/mod.rs
index 3c885940fd778e6..5f35aa8cc1b7914 100644
--- a/packages/next-swc/crates/core/src/auto_cjs/mod.rs
+++ b/packages/next-swc/crates/core/src/auto_cjs/mod.rs
@@ -18,17 +18,13 @@ struct CjsFinder {
/// does not support changing configuration based on content of the file.
impl Visit for CjsFinder {
fn visit_member_expr(&mut self, e: &MemberExpr) {
- match &*e.obj {
- Expr::Ident(obj) => match &e.prop {
- MemberProp::Ident(prop) => {
- if &*obj.sym == "module" && &*prop.sym == "exports" {
- self.found = true;
- return;
- }
+ if let Expr::Ident(obj) = &*e.obj {
+ if let MemberProp::Ident(prop) = &e.prop {
+ if &*obj.sym == "module" && &*prop.sym == "exports" {
+ self.found = true;
+ return;
}
- _ => {}
- },
- _ => {}
+ }
}
e.obj.visit_with(self);
diff --git a/packages/next-swc/crates/core/src/disallow_re_export_all_in_page.rs b/packages/next-swc/crates/core/src/disallow_re_export_all_in_page.rs
index 34f1220232f3708..78983a8b32f7248 100644
--- a/packages/next-swc/crates/core/src/disallow_re_export_all_in_page.rs
+++ b/packages/next-swc/crates/core/src/disallow_re_export_all_in_page.rs
@@ -4,10 +4,7 @@ use swc_ecmascript::utils::HANDLER;
use swc_ecmascript::visit::{noop_fold_type, Fold};
pub fn disallow_re_export_all_in_page(is_page_file: bool) -> impl Fold {
- Optional::new(
- DisallowReExportAllInPage,
- is_page_file
- )
+ Optional::new(DisallowReExportAllInPage, is_page_file)
}
struct DisallowReExportAllInPage;
diff --git a/packages/next-swc/crates/core/src/hook_optimizer.rs b/packages/next-swc/crates/core/src/hook_optimizer.rs
index 0516fc8e1b48e9c..7b0726ca2256f13 100644
--- a/packages/next-swc/crates/core/src/hook_optimizer.rs
+++ b/packages/next-swc/crates/core/src/hook_optimizer.rs
@@ -75,8 +75,8 @@ impl HookOptimizer {
if let Expr::Call(c) = &*init.as_deref().unwrap() {
if let Callee::Expr(i) = &c.callee {
if let Expr::Ident(Ident { sym, .. }) = &**i {
- if self.hooks.contains(&sym) {
- let name = get_object_pattern(&a);
+ if self.hooks.contains(sym) {
+ let name = get_object_pattern(a);
return VarDeclarator {
name,
init: init_clone,
@@ -89,7 +89,7 @@ impl HookOptimizer {
}
}
- return decl;
+ decl
}
}
@@ -98,15 +98,16 @@ fn get_object_pattern(array_pattern: &ArrayPat) -> Pat {
.elems
.iter()
.enumerate()
- .filter_map(|(i, elem)| match elem {
- Some(elem) => Some(ObjectPatProp::KeyValue(KeyValuePatProp {
- key: PropName::Num(Number {
- value: i as f64,
- span: DUMMY_SP,
- }),
- value: Box::new(elem.clone()),
- })),
- None => None,
+ .filter_map(|(i, elem)| {
+ elem.as_ref().map(|elem| {
+ ObjectPatProp::KeyValue(KeyValuePatProp {
+ key: PropName::Num(Number {
+ value: i as f64,
+ span: DUMMY_SP,
+ }),
+ value: Box::new(elem.clone()),
+ })
+ })
})
.collect();
diff --git a/packages/next-swc/crates/core/src/lib.rs b/packages/next-swc/crates/core/src/lib.rs
index 7d4847998dbb87d..6e788b3cd000a27 100644
--- a/packages/next-swc/crates/core/src/lib.rs
+++ b/packages/next-swc/crates/core/src/lib.rs
@@ -27,7 +27,7 @@ DEALINGS IN THE SOFTWARE.
*/
#![recursion_limit = "2048"]
-//#![deny(clippy::all)]
+#![deny(clippy::all)]
use auto_cjs::contains_cjs;
use either::Either;
@@ -112,7 +112,11 @@ pub fn custom_before_pass(
#[cfg(not(target_arch = "wasm32"))]
let relay_plugin = {
if let Some(config) = &opts.relay {
- Either::Left(relay::relay(config, file.name.clone(), opts.pages_dir.clone()))
+ Either::Left(relay::relay(
+ config,
+ file.name.clone(),
+ opts.pages_dir.clone(),
+ ))
} else {
Either::Right(noop())
}
@@ -120,7 +124,7 @@ pub fn custom_before_pass(
chain!(
disallow_re_export_all_in_page::disallow_re_export_all_in_page(opts.is_page_file),
- styled_jsx::styled_jsx(cm.clone(), file.name.clone()),
+ styled_jsx::styled_jsx(cm, file.name.clone()),
hook_optimizer::hook_optimizer(),
match &opts.styled_components {
Some(config) => {
@@ -173,7 +177,7 @@ impl TransformOptions {
let should_enable_commonjs =
self.swc.config.module.is_none() && fm.src.contains("module.exports") && {
let syntax = self.swc.config.jsc.syntax.unwrap_or_default();
- let target = self.swc.config.jsc.target.unwrap_or(EsVersion::latest());
+ let target = self.swc.config.jsc.target.unwrap_or_else(EsVersion::latest);
let lexer = Lexer::new(syntax, target, StringInput::from(&*fm), None);
let mut p = Parser::new_from(lexer);
p.parse_module()
diff --git a/packages/next-swc/crates/core/src/next_dynamic.rs b/packages/next-swc/crates/core/src/next_dynamic.rs
index 01bff29ad322b53..87b30f968e5dbca 100644
--- a/packages/next-swc/crates/core/src/next_dynamic.rs
+++ b/packages/next-swc/crates/core/src/next_dynamic.rs
@@ -74,7 +74,7 @@ impl Fold for NextDynamicPatcher {
if let Callee::Expr(i) = &expr.callee {
if let Expr::Ident(identifier) = &**i {
if self.dynamic_bindings.contains(&identifier.to_id()) {
- if expr.args.len() == 0 {
+ if expr.args.is_empty() {
HANDLER.with(|handler| {
handler
.struct_span_err(
@@ -116,7 +116,7 @@ impl Fold for NextDynamicPatcher {
expr.args[0].expr = expr.args[0].expr.clone().fold_with(self);
self.is_next_dynamic_first_arg = false;
- if let None = self.dynamically_imported_specifier {
+ if self.dynamically_imported_specifier.is_none() {
return expr;
}
diff --git a/packages/next-swc/crates/core/src/next_ssg.rs b/packages/next-swc/crates/core/src/next_ssg.rs
index f744bc7e4e78f53..a4f389ce967a318 100644
--- a/packages/next-swc/crates/core/src/next_ssg.rs
+++ b/packages/next-swc/crates/core/src/next_ssg.rs
@@ -131,11 +131,8 @@ impl Fold for Analyzer<'_> {
fn fold_expr(&mut self, e: Expr) -> Expr {
let e = e.fold_children_with(self);
- match &e {
- Expr::Ident(i) => {
- self.add_ref(i.to_id());
- }
- _ => {}
+ if let Expr::Ident(i) = &e {
+ self.add_ref(i.to_id());
}
e
@@ -216,8 +213,8 @@ impl Fold for Analyzer<'_> {
// Visit children to ensure that all references is added to the scope.
let s = s.fold_children_with(self);
- match &s {
- ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) => match &e.decl {
+ if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) = &s {
+ match &e.decl {
Decl::Fn(f) => {
// Drop getStaticProps.
if let Ok(is_data_identifier) = self.state.is_data_identifier(&f.ident) {
@@ -235,9 +232,7 @@ impl Fold for Analyzer<'_> {
}
}
_ => {}
- },
-
- _ => {}
+ }
}
s
@@ -254,11 +249,8 @@ impl Fold for Analyzer<'_> {
fn fold_prop(&mut self, p: Prop) -> Prop {
let p = p.fold_children_with(self);
- match &p {
- Prop::Shorthand(i) => {
- self.add_ref(i.to_id());
- }
- _ => {}
+ if let Prop::Shorthand(i) = &p {
+ self.add_ref(i.to_id());
}
p
@@ -267,17 +259,14 @@ impl Fold for Analyzer<'_> {
fn fold_var_declarator(&mut self, mut v: VarDeclarator) -> VarDeclarator {
let old_in_data = self.in_data_fn;
- match &v.name {
- Pat::Ident(name) => {
- if let Ok(is_data_identifier) = self.state.is_data_identifier(&name.id) {
- if is_data_identifier {
- self.in_data_fn = true;
- }
- } else {
- return v;
+ if let Pat::Ident(name) = &v.name {
+ if let Ok(is_data_identifier) = self.state.is_data_identifier(&name.id) {
+ if is_data_identifier {
+ self.in_data_fn = true;
}
+ } else {
+ return v;
}
- _ => {}
}
let old_in_lhs_of_var = self.in_lhs_of_var;
@@ -397,18 +386,15 @@ impl Fold for NextSsg {
}
fn fold_module_item(&mut self, i: ModuleItem) -> ModuleItem {
- match i {
- ModuleItem::ModuleDecl(ModuleDecl::Import(i)) => {
- let is_for_side_effect = i.specifiers.is_empty();
- let i = i.fold_with(self);
-
- if !is_for_side_effect && i.specifiers.is_empty() {
- return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
- }
+ if let ModuleItem::ModuleDecl(ModuleDecl::Import(i)) = i {
+ let is_for_side_effect = i.specifiers.is_empty();
+ let i = i.fold_with(self);
- return ModuleItem::ModuleDecl(ModuleDecl::Import(i));
+ if !is_for_side_effect && i.specifiers.is_empty() {
+ return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
}
- _ => {}
+
+ return ModuleItem::ModuleDecl(ModuleDecl::Import(i));
}
let i = i.fold_children_with(self);
@@ -427,10 +413,7 @@ impl Fold for NextSsg {
items = items.fold_children_with(self);
// Drop nodes.
- items.retain(|s| match s {
- ModuleItem::Stmt(Stmt::Empty(..)) => false,
- _ => true,
- });
+ items.retain(|s| !matches!(s, ModuleItem::Stmt(Stmt::Empty(..))));
if !self.state.done
&& !self.state.should_run_again
@@ -461,29 +444,24 @@ impl Fold for NextSsg {
let mut new = Vec::with_capacity(items.len() + 1);
for item in take(&mut items) {
- match &item {
- ModuleItem::ModuleDecl(
- ModuleDecl::ExportNamed(..)
- | ModuleDecl::ExportDecl(..)
- | ModuleDecl::ExportDefaultDecl(..)
- | ModuleDecl::ExportDefaultExpr(..),
- ) => {
- if let Some(var) = var.take() {
- new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(
- ExportDecl {
- span: DUMMY_SP,
- decl: Decl::Var(VarDecl {
- span: DUMMY_SP,
- kind: VarDeclKind::Var,
- declare: Default::default(),
- decls: vec![var],
- }),
- },
- )))
- }
+ if let ModuleItem::ModuleDecl(
+ ModuleDecl::ExportNamed(..)
+ | ModuleDecl::ExportDecl(..)
+ | ModuleDecl::ExportDefaultDecl(..)
+ | ModuleDecl::ExportDefaultExpr(..),
+ ) = &item
+ {
+ if let Some(var) = var.take() {
+ new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
+ span: DUMMY_SP,
+ decl: Decl::Var(VarDecl {
+ span: DUMMY_SP,
+ kind: VarDeclKind::Var,
+ declare: Default::default(),
+ decls: vec![var],
+ }),
+ })))
}
-
- _ => {}
}
new.push(item);
@@ -511,14 +489,14 @@ impl Fold for NextSsg {
..
}) => self
.state
- .is_data_identifier(&exported)
+ .is_data_identifier(exported)
.map(|is_data_identifier| !is_data_identifier),
ExportSpecifier::Named(ExportNamedSpecifier {
orig: ModuleExportName::Ident(orig),
..
}) => self
.state
- .is_data_identifier(&orig)
+ .is_data_identifier(orig)
.map(|is_data_identifier| !is_data_identifier),
_ => Ok(true),
@@ -528,15 +506,13 @@ impl Fold for NextSsg {
Ok(false) => {
tracing::trace!("Dropping a export specifier because it's a data identifier");
- match s {
- ExportSpecifier::Named(ExportNamedSpecifier {
- orig: ModuleExportName::Ident(orig),
- ..
- }) => {
- self.state.should_run_again = true;
- self.state.refs_from_data_fn.insert(orig.to_id());
- }
- _ => {}
+ if let ExportSpecifier::Named(ExportNamedSpecifier {
+ orig: ModuleExportName::Ident(orig),
+ ..
+ }) = s
+ {
+ self.state.should_run_again = true;
+ self.state.refs_from_data_fn.insert(orig.to_id());
}
false
@@ -569,10 +545,7 @@ impl Fold for NextSsg {
}
Pat::Array(arr) => {
if !arr.elems.is_empty() {
- arr.elems.retain(|e| match e {
- Some(Pat::Invalid(..)) => return false,
- _ => true,
- });
+ arr.elems.retain(|e| !matches!(e, Some(Pat::Invalid(..))));
if arr.elems.is_empty() {
return Pat::Invalid(Invalid { span: DUMMY_SP });
@@ -627,6 +600,7 @@ impl Fold for NextSsg {
p
}
+ #[allow(clippy::single_match)]
fn fold_stmt(&mut self, mut s: Stmt) -> Stmt {
match s {
Stmt::Decl(Decl::Fn(f)) => {
diff --git a/packages/next-swc/crates/core/src/page_config.rs b/packages/next-swc/crates/core/src/page_config.rs
index 0b214038a15f1ae..9175f4730ca83f1 100644
--- a/packages/next-swc/crates/core/src/page_config.rs
+++ b/packages/next-swc/crates/core/src/page_config.rs
@@ -71,76 +71,73 @@ impl Fold for PageConfig {
}
fn fold_export_decl(&mut self, export: ExportDecl) -> ExportDecl {
- match &export.decl {
- Decl::Var(var_decl) => {
- for decl in &var_decl.decls {
- let mut is_config = false;
- if let Pat::Ident(ident) = &decl.name {
- if &ident.id.sym == CONFIG_KEY {
- is_config = true;
- }
+ if let Decl::Var(var_decl) = &export.decl {
+ for decl in &var_decl.decls {
+ let mut is_config = false;
+ if let Pat::Ident(ident) = &decl.name {
+ if &ident.id.sym == CONFIG_KEY {
+ is_config = true;
}
+ }
- if is_config {
- if let Some(expr) = &decl.init {
- if let Expr::Object(obj) = &**expr {
- for prop in &obj.props {
- if let PropOrSpread::Prop(prop) = prop {
- if let Prop::KeyValue(kv) = &**prop {
- match &kv.key {
- PropName::Ident(ident) => {
- if &ident.sym == "amp" {
- if let Expr::Lit(Lit::Bool(Bool {
- value,
- ..
- })) = &*kv.value
- {
- if *value && self.is_page_file {
- self.drop_bundle = true;
- }
- } else if let Expr::Lit(Lit::Str(_)) =
- &*kv.value
- {
- // Do not replace
- // bundle
- } else {
- self.handle_error(
- "Invalid value found.",
- export.span,
- );
+ if is_config {
+ if let Some(expr) = &decl.init {
+ if let Expr::Object(obj) = &**expr {
+ for prop in &obj.props {
+ if let PropOrSpread::Prop(prop) = prop {
+ if let Prop::KeyValue(kv) = &**prop {
+ match &kv.key {
+ PropName::Ident(ident) => {
+ if &ident.sym == "amp" {
+ if let Expr::Lit(Lit::Bool(Bool {
+ value,
+ ..
+ })) = &*kv.value
+ {
+ if *value && self.is_page_file {
+ self.drop_bundle = true;
}
+ } else if let Expr::Lit(Lit::Str(_)) =
+ &*kv.value
+ {
+ // Do not replace
+ // bundle
+ } else {
+ self.handle_error(
+ "Invalid value found.",
+ export.span,
+ );
}
}
- _ => {
- self.handle_error(
- "Invalid property found.",
- export.span,
- );
- }
}
- } else {
- self.handle_error(
- "Invalid property or value.",
- export.span,
- );
+ _ => {
+ self.handle_error(
+ "Invalid property found.",
+ export.span,
+ );
+ }
}
} else {
self.handle_error(
- "Property spread is not allowed.",
+ "Invalid property or value.",
export.span,
);
}
+ } else {
+ self.handle_error(
+ "Property spread is not allowed.",
+ export.span,
+ );
}
- } else {
- self.handle_error("Expected config to be an object.", export.span);
}
} else {
self.handle_error("Expected config to be an object.", export.span);
}
+ } else {
+ self.handle_error("Expected config to be an object.", export.span);
}
}
}
- _ => {}
}
export
}
diff --git a/packages/next-swc/crates/core/src/react_remove_properties.rs b/packages/next-swc/crates/core/src/react_remove_properties.rs
index 6f51f0b9a816ab6..f2944795537d980 100644
--- a/packages/next-swc/crates/core/src/react_remove_properties.rs
+++ b/packages/next-swc/crates/core/src/react_remove_properties.rs
@@ -39,12 +39,11 @@ impl Fold for RemoveProperties {
noop_fold_type!();
fn fold_jsx_opening_element(&mut self, mut el: JSXOpeningElement) -> JSXOpeningElement {
- el.attrs.retain(|attr| match attr {
- JSXAttrOrSpread::JSXAttr(JSXAttr {
- name: JSXAttrName::Ident(ident),
- ..
- }) if self.should_remove_property(ident.sym.as_ref()) => false,
- _ => true,
+ el.attrs.retain(|attr| {
+ !matches!(attr, JSXAttrOrSpread::JSXAttr(JSXAttr {
+ name: JSXAttrName::Ident(ident),
+ ..
+ }) if self.should_remove_property(ident.sym.as_ref()))
});
el.fold_children_with(self)
}
@@ -67,6 +66,5 @@ pub fn remove_properties(config: Config) -> impl Fold {
// Keep the default regex identical to `babel-plugin-react-remove-properties`.
properties.push(Regex::new(r"^data-test").unwrap());
}
- let remover = RemoveProperties { properties };
- remover
+ RemoveProperties { properties }
}
diff --git a/packages/next-swc/crates/core/src/relay.rs b/packages/next-swc/crates/core/src/relay.rs
index b9035197bbb2b6d..680eceb4de2dbf7 100644
--- a/packages/next-swc/crates/core/src/relay.rs
+++ b/packages/next-swc/crates/core/src/relay.rs
@@ -53,15 +53,13 @@ fn build_require_expr_from_path(path: &str) -> Expr {
Expr::Call(CallExpr {
span: Default::default(),
callee: quote_ident!("require").as_callee(),
- args: vec![
- Lit::Str(Str {
- span: Default::default(),
- value: JsWord::from(path),
- has_escape: false,
- kind: Default::default(),
- })
- .as_arg(),
- ],
+ args: vec![Lit::Str(Str {
+ span: Default::default(),
+ value: JsWord::from(path),
+ has_escape: false,
+ kind: Default::default(),
+ })
+ .as_arg()],
type_args: None,
})
}
diff --git a/packages/next-swc/crates/core/src/remove_console.rs b/packages/next-swc/crates/core/src/remove_console.rs
index 11238eb037e4e58..f2b3cb18683a312 100644
--- a/packages/next-swc/crates/core/src/remove_console.rs
+++ b/packages/next-swc/crates/core/src/remove_console.rs
@@ -39,12 +39,7 @@ struct RemoveConsole {
impl RemoveConsole {
fn is_global_console(&self, ident: &Ident) -> bool {
- &ident.sym == "console"
- && self
- .bindings
- .iter()
- .find(|x| x.contains(&ident.to_id()))
- .is_none()
+ &ident.sym == "console" && !self.bindings.iter().any(|x| x.contains(&ident.to_id()))
}
fn should_remove_call(&mut self, n: &CallExpr) -> bool {
@@ -73,7 +68,7 @@ impl RemoveConsole {
// Here we do an O(n) search on the list of excluded properties because the size
// should be small.
match &member_expr.prop {
- MemberProp::Ident(i) if self.exclude.iter().find(|x| **x == i.sym).is_none() => {}
+ MemberProp::Ident(i) if !self.exclude.iter().any(|x| *x == i.sym) => {}
_ => return false,
}
@@ -85,16 +80,12 @@ impl Fold for RemoveConsole {
noop_fold_type!();
fn fold_stmt(&mut self, stmt: Stmt) -> Stmt {
- match &stmt {
- Stmt::Expr(e) => match &*e.expr {
- Expr::Call(c) => {
- if self.should_remove_call(c) {
- return Stmt::Empty(EmptyStmt { span: DUMMY_SP });
- }
+ if let Stmt::Expr(e) = &stmt {
+ if let Expr::Call(c) = &*e.expr {
+ if self.should_remove_call(c) {
+ return Stmt::Empty(EmptyStmt { span: DUMMY_SP });
}
- _ => {}
- },
- _ => {}
+ }
}
stmt.fold_children_with(self)
}
@@ -135,10 +126,9 @@ pub fn remove_console(config: Config) -> impl Fold {
Config::WithOptions(x) => x.exclude,
_ => vec![],
};
- let remover = RemoveConsole {
+ RemoveConsole {
exclude,
bindings: Default::default(),
in_function_params: false,
- };
- remover
+ }
}
diff --git a/packages/next-swc/crates/core/src/shake_exports.rs b/packages/next-swc/crates/core/src/shake_exports.rs
index ba0e58ce89815bc..083e490967c2bec 100644
--- a/packages/next-swc/crates/core/src/shake_exports.rs
+++ b/packages/next-swc/crates/core/src/shake_exports.rs
@@ -26,9 +26,7 @@ struct ExportShaker {
impl Fold for ExportShaker {
fn fold_module(&mut self, module: Module) -> Module {
let module = module.fold_children_with(self);
- let module = module.fold_with(&mut dce(DCEConfig::default()));
-
- module
+ module.fold_with(&mut dce(DCEConfig::default()))
}
fn fold_module_items(&mut self, items: Vec) -> Vec {
diff --git a/packages/next-swc/crates/core/src/styled_jsx/mod.rs b/packages/next-swc/crates/core/src/styled_jsx/mod.rs
index a70666f40e321cd..21062867cd30463 100644
--- a/packages/next-swc/crates/core/src/styled_jsx/mod.rs
+++ b/packages/next-swc/crates/core/src/styled_jsx/mod.rs
@@ -26,10 +26,9 @@ mod utils;
pub fn styled_jsx(cm: Arc, file_name: FileName) -> impl Fold {
let file_name = match file_name {
- FileName::Real(real_file_name) => match real_file_name.to_str() {
- Some(real_file_name) => Some(real_file_name.to_string()),
- None => None,
- },
+ FileName::Real(real_file_name) => real_file_name
+ .to_str()
+ .map(|real_file_name| real_file_name.to_string()),
_ => None,
};
@@ -81,6 +80,7 @@ pub struct LocalStyle {
css: String,
css_span: Span,
is_dynamic: bool,
+ #[allow(clippy::vec_box)]
expressions: Vec>,
}
@@ -105,10 +105,9 @@ impl Fold for StyledJSXTransformer {
fn fold_jsx_element(&mut self, el: JSXElement) -> JSXElement {
if is_styled_jsx(&el) {
let parent_has_styled_jsx = self.has_styled_jsx;
- if !parent_has_styled_jsx {
- if self.check_for_jsx_styles(Some(&el), &el.children).is_err() {
- return el;
- }
+ if !parent_has_styled_jsx && self.check_for_jsx_styles(Some(&el), &el.children).is_err()
+ {
+ return el;
}
let el = match self.replace_jsx_style(&el) {
Ok(el) => el,
@@ -260,14 +259,12 @@ impl Fold for StyledJSXTransformer {
fn fold_var_declarator(&mut self, declarator: VarDeclarator) -> VarDeclarator {
let declarator = declarator.fold_children_with(self);
if let Some(external_hash) = &self.external_hash.take() {
- match &declarator.name {
- Pat::Ident(BindingIdent {
- id: Ident { span, sym, .. },
- ..
- }) => {
- self.add_hash = Some(((sym.clone(), span.ctxt), external_hash.clone()));
- }
- _ => {}
+ if let Pat::Ident(BindingIdent {
+ id: Ident { span, sym, .. },
+ ..
+ }) = &declarator.name
+ {
+ self.add_hash = Some(((sym.clone(), span.ctxt), external_hash.clone()));
}
}
declarator
@@ -339,7 +336,7 @@ impl Fold for StyledJSXTransformer {
if self.file_has_styled_jsx || self.file_has_css_resolve {
prepend(
&mut new_items,
- styled_jsx_import_decl(&self.style_import_name.as_ref().unwrap()),
+ styled_jsx_import_decl(self.style_import_name.as_ref().unwrap()),
);
}
@@ -361,7 +358,7 @@ impl Fold for StyledJSXTransformer {
}
fn fold_function(&mut self, mut func: Function) -> Function {
- self.func_scope_level = self.func_scope_level + 1;
+ self.func_scope_level += 1;
let surrounding_scope_bindings = take(&mut self.nearest_scope_bindings);
self.in_function_params = true;
let mut new_params = vec![];
@@ -373,12 +370,12 @@ impl Fold for StyledJSXTransformer {
self.nearest_scope_bindings.extend(collect_decls(&func));
func.body = func.body.fold_with(self);
self.nearest_scope_bindings = surrounding_scope_bindings;
- self.func_scope_level = self.func_scope_level - 1;
+ self.func_scope_level -= 1;
func
}
fn fold_arrow_expr(&mut self, mut func: ArrowExpr) -> ArrowExpr {
- self.func_scope_level = self.func_scope_level + 1;
+ self.func_scope_level += 1;
let surrounding_scope_bindings = take(&mut self.nearest_scope_bindings);
self.in_function_params = true;
let mut new_params = vec![];
@@ -390,7 +387,7 @@ impl Fold for StyledJSXTransformer {
self.nearest_scope_bindings.extend(collect_decls(&func));
func.body = func.body.fold_with(self);
self.nearest_scope_bindings = surrounding_scope_bindings;
- self.func_scope_level = self.func_scope_level - 1;
+ self.func_scope_level -= 1;
func
}
@@ -436,10 +433,10 @@ impl StyledJSXTransformer {
if el.is_some() && is_styled_jsx(el.unwrap()) {
process_style(el.unwrap())?;
} else {
- for i in 0..children.len() {
- if let JSXElementChild::JSXElement(child_el) = &children[i] {
- if is_styled_jsx(&child_el) {
- process_style(&child_el)?;
+ for i in children {
+ if let JSXElementChild::JSXElement(child_el) = &i {
+ if is_styled_jsx(child_el) {
+ process_style(child_el)?;
}
}
}
@@ -465,8 +462,8 @@ impl StyledJSXTransformer {
match style_expr {
StyleExpr::Str(Str { value, span, .. }) => {
hasher.write(value.as_ref().as_bytes());
- css = value.to_string().clone();
- css_span = span.clone();
+ css = value.to_string();
+ css_span = *span;
is_dynamic = false;
}
StyleExpr::Tpl(
@@ -480,7 +477,7 @@ impl StyledJSXTransformer {
if exprs.is_empty() {
hasher.write(quasis[0].raw.value.as_bytes());
css = quasis[0].raw.value.to_string();
- css_span = span.clone();
+ css_span = *span;
is_dynamic = false;
} else {
drop_span(expr.clone()).hash(&mut hasher);
@@ -493,15 +490,11 @@ impl StyledJSXTransformer {
};
s = format!("{}{}{}", s, quasis[i].raw.value, placeholder)
}
- css = String::from(s);
+ css = s;
css_span = *span;
is_dynamic = if self.func_scope_level > 0 {
- let res = self.evaluator.as_mut().unwrap().eval(&expr);
- if let Some(EvalResult::Lit(_)) = res {
- false
- } else {
- true
- }
+ let res = self.evaluator.as_mut().unwrap().eval(expr);
+ !matches!(res, Some(EvalResult::Lit(_)))
} else {
false
};
@@ -554,12 +547,12 @@ impl StyledJSXTransformer {
JSXStyle::Local(style_info) => {
let css = transform_css(
self.cm.clone(),
- &style_info,
+ style_info,
is_global,
&self.static_class_name,
)?;
Ok(make_local_styled_jsx_el(
- &style_info,
+ style_info,
css,
self.style_import_name.as_ref().unwrap(),
self.static_class_name.as_ref(),
@@ -589,7 +582,7 @@ impl StyledJSXTransformer {
);
let styles = vec![style];
let (static_class_name, class_name) =
- compute_class_names(&styles, &self.style_import_name.as_ref().unwrap());
+ compute_class_names(&styles, self.style_import_name.as_ref().unwrap());
let tag = match &*tagged_tpl.tag {
Expr::Ident(Ident { sym, .. }) => sym.to_string(),
Expr::Member(MemberExpr {
@@ -606,7 +599,7 @@ impl StyledJSXTransformer {
} else {
bail!("This shouldn't happen, we already know that this is a template literal");
};
- let css = transform_css(self.cm.clone(), &style, tag == "global", &static_class_name)?;
+ let css = transform_css(self.cm.clone(), style, tag == "global", &static_class_name)?;
if tag == "resolve" {
self.file_has_css_resolve = true;
return Ok(Expr::Object(ObjectLit {
@@ -618,9 +611,9 @@ impl StyledJSXTransformer {
optional: false,
}),
value: Box::new(Expr::JSXElement(Box::new(make_local_styled_jsx_el(
- &style,
+ style,
css,
- &self.style_import_name.as_ref().unwrap(),
+ self.style_import_name.as_ref().unwrap(),
self.static_class_name.as_ref(),
)))),
}))),
@@ -796,14 +789,16 @@ fn get_existing_class_name(el: &JSXOpeningElement) -> (Option, Option (Option, Option true,
- Expr::Ident(_) => true,
- _ => false,
- };
+ let valid_spread = matches!(&**expr, Expr::Member(_) | Expr::Ident(_));
if valid_spread {
let member_dot_name = Expr::Member(MemberExpr {
@@ -875,11 +866,11 @@ fn get_existing_class_name(el: &JSXOpeningElement) -> (Option, Option) -> Expr {
let mut new_expr = spreads[0].clone();
- for i in 1..spreads.len() {
+ for i in spreads.iter().skip(1) {
new_expr = Expr::Bin(BinExpr {
op: op!("||"),
left: Box::new(new_expr.clone()),
- right: Box::new(spreads[i].clone()),
+ right: Box::new(i.clone()),
span: DUMMY_SP,
})
}
diff --git a/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs b/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs
index d25cd05e634967a..32e9850857e7710 100644
--- a/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs
+++ b/packages/next-swc/crates/core/src/styled_jsx/transform_css.rs
@@ -44,7 +44,7 @@ pub fn transform_css(
Err(err) => {
HANDLER.with(|handler| {
// Print css parsing errors
- err.to_diagnostics(&handler).emit();
+ err.to_diagnostics(handler).emit();
// TODO(kdy1): We may print css so the user can see the error, and report it.
@@ -78,17 +78,17 @@ pub fn transform_css(
gen.emit(&ss).unwrap();
}
- if style_info.expressions.len() == 0 {
+ if style_info.expressions.is_empty() {
return Ok(string_literal_expr(&s));
}
let mut parts: Vec<&str> = s.split("__styled-jsx-placeholder-").collect();
let mut final_expressions = vec![];
- for i in 1..parts.len() {
- let (num_len, expression_index) = read_number(&parts[i]);
+ for i in parts.iter_mut().skip(1) {
+ let (num_len, expression_index) = read_number(i);
final_expressions.push(style_info.expressions[expression_index].clone());
- let substr = &parts[i][(num_len + 2)..];
- parts[i] = substr;
+ let substr = &i[(num_len + 2)..];
+ *i = substr;
}
Ok(Expr::Tpl(Tpl {
@@ -260,24 +260,19 @@ impl Namespacer {
&mut vec![],
)
.unwrap();
- return x;
+ x
});
return match complex_selectors {
Ok(complex_selectors) => {
- let mut v = complex_selectors.children[1..]
- .iter()
- .cloned()
- .collect::>();
-
- match v[0] {
- ComplexSelectorChildren::Combinator(Combinator {
- value: CombinatorValue::Descendant,
- ..
- }) => {
- v.remove(0);
- }
- _ => {}
+ let mut v = complex_selectors.children[1..].to_vec();
+
+ if let ComplexSelectorChildren::Combinator(Combinator {
+ value: CombinatorValue::Descendant,
+ ..
+ }) = v[0]
+ {
+ v.remove(0);
}
if v.is_empty() {
@@ -287,27 +282,21 @@ impl Namespacer {
trace!("Combinator: {:?}", combinator);
trace!("v[0]: {:?}", v[0]);
- if combinator.is_some() {
+ if let Some(combinator) = combinator {
match v.get(0) {
Some(ComplexSelectorChildren::Combinator(..)) => {}
Some(..) => {}
_ => {
- v.push(ComplexSelectorChildren::Combinator(
- combinator.unwrap(),
- ));
+ v.push(ComplexSelectorChildren::Combinator(combinator));
}
}
}
v.iter_mut().for_each(|sel| {
if i < node.subclass_selectors.len() {
- match sel {
- ComplexSelectorChildren::CompoundSelector(sel) => {
- sel.subclass_selectors.extend(
- node.subclass_selectors[i + 1..].iter().cloned(),
- );
- }
- _ => {}
+ if let ComplexSelectorChildren::CompoundSelector(sel) = sel {
+ sel.subclass_selectors
+ .extend(node.subclass_selectors[i + 1..].iter().cloned());
}
}
});
@@ -352,7 +341,7 @@ fn get_front_selector_tokens(selector_tokens: &Tokens) -> Vec {
vec![
TokenAndSpan {
span: Span {
- lo: BytePos(start_pos + 0),
+ lo: BytePos(start_pos),
hi: BytePos(start_pos + 1),
ctxt: SyntaxContext::empty(),
},
@@ -377,7 +366,7 @@ fn get_block_tokens(selector_tokens: &Tokens) -> Vec {
vec![
TokenAndSpan {
span: Span {
- lo: BytePos(start_pos + 0),
+ lo: BytePos(start_pos),
hi: BytePos(start_pos + 1),
ctxt: SyntaxContext::empty(),
},
@@ -485,7 +474,6 @@ fn nth_to_tokens(nth: &Nth) -> Tokens {
StringInput::new(&s, nth.span.lo, nth.span.hi),
ParserConfig {
allow_wrong_line_comments: true,
- ..Default::default()
},
);
diff --git a/packages/next-swc/crates/core/src/styled_jsx/utils.rs b/packages/next-swc/crates/core/src/styled_jsx/utils.rs
index f2acbf5f22bb1be..c4369ca77cf64ed 100644
--- a/packages/next-swc/crates/core/src/styled_jsx/utils.rs
+++ b/packages/next-swc/crates/core/src/styled_jsx/utils.rs
@@ -20,7 +20,7 @@ fn tpl_element(value: &str) -> TplElement {
}
pub fn compute_class_names(
- styles: &Vec,
+ styles: &[JSXStyle],
style_import_name: &str,
) -> (Option, Option) {
let mut static_class_name = None;
@@ -45,7 +45,7 @@ pub fn compute_class_names(
}
}
- if external_styles.len() > 0 {
+ if !external_styles.is_empty() {
let mut quasis = vec![tpl_element("jsx-")];
for _i in 1..external_styles.len() {
quasis.push(tpl_element(" jsx-"))
@@ -61,7 +61,7 @@ pub fn compute_class_names(
}));
}
- if static_hashes.len() > 0 {
+ if !static_hashes.is_empty() {
static_class_name = Some(format!("jsx-{}", hash_string(&static_hashes.join(","))));
}
@@ -295,7 +295,7 @@ pub fn make_local_styled_jsx_el(
}
}
-pub fn get_usable_import_specifier(_items: &Vec) -> String {
+pub fn get_usable_import_specifier(_items: &[ModuleItem]) -> String {
// TODO
String::from("_JSXStyle")
}
@@ -323,7 +323,7 @@ pub fn styled_jsx_import_decl(style_import_name: &str) -> ModuleItem {
}
// TODO: maybe use DJBHasher (need to implement)
-pub fn hash_string(str: &String) -> String {
+pub fn hash_string(str: &str) -> String {
let mut hasher = DefaultHasher::new();
hasher.write(str.as_bytes());
let hash_result = hasher.finish();
diff --git a/packages/next-swc/crates/napi/build.rs b/packages/next-swc/crates/napi/build.rs
index 1f866b6a3c3acf7..9fc236788932b31 100644
--- a/packages/next-swc/crates/napi/build.rs
+++ b/packages/next-swc/crates/napi/build.rs
@@ -1,5 +1,5 @@
extern crate napi_build;
fn main() {
- napi_build::setup();
+ napi_build::setup();
}
diff --git a/packages/next-swc/crates/napi/src/bundle/mod.rs b/packages/next-swc/crates/napi/src/bundle/mod.rs
index 3ac3de7f8275b23..1e90517d383146e 100644
--- a/packages/next-swc/crates/napi/src/bundle/mod.rs
+++ b/packages/next-swc/crates/napi/src/bundle/mod.rs
@@ -64,11 +64,11 @@ impl Task for BundleTask {
//
let mut bundler = Bundler::new(
- &self.c.globals(),
+ self.c.globals(),
self.c.cm.clone(),
CustomLoader {
cm: self.c.cm.clone(),
- handler: &handler,
+ handler,
},
make_resolver(),
swc_bundler::Config {
@@ -82,7 +82,7 @@ impl Task for BundleTask {
);
let mut entries = HashMap::default();
- let path: PathBuf = option.entry.into();
+ let path: PathBuf = option.entry;
let path = path
.canonicalize()
.context("failed to canonicalize entry file")?;
@@ -148,7 +148,7 @@ struct CustomLoader<'a> {
impl swc_bundler::Load for CustomLoader<'_> {
fn load(&self, f: &FileName) -> Result {
let fm = match f {
- FileName::Real(path) => self.cm.load_file(&path)?,
+ FileName::Real(path) => self.cm.load_file(path)?,
_ => unreachable!(),
};
@@ -163,7 +163,7 @@ impl swc_bundler::Load for CustomLoader<'_> {
let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().map_err(|err| {
- err.into_diagnostic(&self.handler).emit();
+ err.into_diagnostic(self.handler).emit();
anyhow!("failed to parse")
})?;
diff --git a/packages/next-swc/crates/napi/src/lib.rs b/packages/next-swc/crates/napi/src/lib.rs
index dcc6441fbff6a0c..de6f93fe222cb66 100644
--- a/packages/next-swc/crates/napi/src/lib.rs
+++ b/packages/next-swc/crates/napi/src/lib.rs
@@ -37,19 +37,19 @@ extern crate swc_node_base;
use backtrace::Backtrace;
use napi::{CallContext, Env, JsObject, JsUndefined};
use std::{env, panic::set_hook, sync::Arc};
-use swc::{ Compiler, TransformOutput};
+use swc::{Compiler, TransformOutput};
use swc_common::{self, sync::Lazy, FilePathMapping, SourceMap};
mod bundle;
mod minify;
+mod parse;
mod transform;
mod util;
-mod parse;
static COMPILER: Lazy> = Lazy::new(|| {
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
- Arc::new(Compiler::new(cm.clone()))
+ Arc::new(Compiler::new(cm))
});
#[module_exports]
@@ -68,7 +68,7 @@ fn init(mut exports: JsObject) -> napi::Result<()> {
exports.create_named_method("minify", minify::minify)?;
exports.create_named_method("minifySync", minify::minify_sync)?;
-
+
exports.create_named_method("parse", parse::parse)?;
Ok(())
diff --git a/packages/next-swc/crates/napi/src/minify.rs b/packages/next-swc/crates/napi/src/minify.rs
index 29d947de0c3935a..32098fbb7352db3 100644
--- a/packages/next-swc/crates/napi/src/minify.rs
+++ b/packages/next-swc/crates/napi/src/minify.rs
@@ -79,7 +79,7 @@ impl Task for MinifyTask {
try_with_handler(self.c.cm.clone(), true, |handler| {
let fm = self.code.to_file(self.c.cm.clone());
- self.c.minify(fm, &handler, &self.opts)
+ self.c.minify(fm, handler, &self.opts)
})
.convert_err()
}
@@ -110,8 +110,8 @@ pub fn minify_sync(cx: CallContext) -> napi::Result {
let fm = code.to_file(c.cm.clone());
- let output = try_with_handler(c.cm.clone(), true, |handler| c.minify(fm, &handler, &opts))
+ let output = try_with_handler(c.cm.clone(), true, |handler| c.minify(fm, handler, &opts))
.convert_err()?;
- complete_output(&cx.env, output)
+ complete_output(cx.env, output)
}
diff --git a/packages/next-swc/crates/napi/src/parse.rs b/packages/next-swc/crates/napi/src/parse.rs
index a6cb68a0291bf47..9d00b3e7ca7d086 100644
--- a/packages/next-swc/crates/napi/src/parse.rs
+++ b/packages/next-swc/crates/napi/src/parse.rs
@@ -11,7 +11,7 @@ pub struct ParseTask {
pub options: String,
}
-pub fn complete_parse<'a>(env: &Env, ast_json: String) -> napi::Result {
+pub fn complete_parse(env: &Env, ast_json: String) -> napi::Result {
env.create_string_from_std(ast_json)
}
@@ -28,7 +28,7 @@ impl Task for ParseTask {
let program = try_with_handler(c.cm.clone(), false, |handler| {
c.parse_js(
fm,
- &handler,
+ handler,
options.target,
options.syntax,
options.is_module,
diff --git a/packages/next-swc/crates/napi/src/transform.rs b/packages/next-swc/crates/napi/src/transform.rs
index 4992542638aa013..adc32cc25feb7e9 100644
--- a/packages/next-swc/crates/napi/src/transform.rs
+++ b/packages/next-swc/crates/napi/src/transform.rs
@@ -96,9 +96,9 @@ impl Task for TransformTask {
let before_pass = custom_before_pass(self.c.cm.clone(), fm.clone(), &options);
self.c.process_js_with_custom_pass(
- fm.clone(),
+ fm,
None,
- &handler,
+ handler,
&options.swc,
|_| before_pass,
|_| noop(),
@@ -177,11 +177,11 @@ where
if is_module.get_value()? {
let program: Program =
serde_json::from_str(s.as_str()?).context("failed to deserialize Program")?;
- c.process_js(&handler, program, &options.swc)
+ c.process_js(handler, program, &options.swc)
} else {
let fm =
op(&c, s.as_str()?.to_string(), &options).context("failed to load file")?;
- c.process_js_file(fm, &handler, &options.swc)
+ c.process_js_file(fm, handler, &options.swc)
}
})
})
diff --git a/packages/next-swc/crates/napi/src/util.rs b/packages/next-swc/crates/napi/src/util.rs
index ab98fea801083f1..775916055b1c4ff 100644
--- a/packages/next-swc/crates/napi/src/util.rs
+++ b/packages/next-swc/crates/napi/src/util.rs
@@ -54,7 +54,7 @@ impl CtxtExt for CallContext<'_> {
Ok(String::from_utf8_lossy(buffer.as_ref()).to_string())
}
-
+
fn get_deserialized(&self, index: usize) -> napi::Result
where
T: DeserializeOwned,
@@ -79,6 +79,6 @@ pub(crate) fn deserialize_json(s: &str) -> Result
where
T: DeserializeOwned,
{
- serde_json::from_str(&s)
+ serde_json::from_str(s)
.with_context(|| format!("failed to deserialize as {}\nJSON: {}", type_name::(), s))
}
diff --git a/packages/next-swc/crates/wasm/src/lib.rs b/packages/next-swc/crates/wasm/src/lib.rs
index 1273e36577f1d70..9816f32fa9c000b 100644
--- a/packages/next-swc/crates/wasm/src/lib.rs
+++ b/packages/next-swc/crates/wasm/src/lib.rs
@@ -22,10 +22,10 @@ pub fn minify_sync(s: &str, opts: JsValue) -> Result {
let fm = c.cm.new_source_file(FileName::Anon, s.into());
let program = c
- .minify(fm, &handler, &opts)
+ .minify(fm, handler, &opts)
.context("failed to minify file")?;
- Ok(JsValue::from_serde(&program).context("failed to serialize json")?)
+ JsValue::from_serde(&program).context("failed to serialize json")
})
.map_err(convert_err)
}
@@ -40,7 +40,7 @@ pub fn transform_sync(s: &str, opts: JsValue) -> Result {
let opts: TransformOptions = opts.into_serde().context("failed to parse options")?;
let fm = c.cm.new_source_file(
- if opts.swc.filename == "" {
+ if opts.swc.filename.is_empty() {
FileName::Anon
} else {
FileName::Real(opts.swc.filename.clone().into())
@@ -49,10 +49,10 @@ pub fn transform_sync(s: &str, opts: JsValue) -> Result {
);
let before_pass = custom_before_pass(c.cm.clone(), fm.clone(), &opts);
let out = c
- .process_js_with_custom_pass(fm, None, &handler, &opts.swc, |_| before_pass, |_| noop())
+ .process_js_with_custom_pass(fm, None, handler, &opts.swc, |_| before_pass, |_| noop())
.context("failed to process js file")?;
- Ok(JsValue::from_serde(&out).context("failed to serialize json")?)
+ JsValue::from_serde(&out).context("failed to serialize json")
})
.map_err(convert_err)
}
diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts
index 64cc4d73ec21376..abd2b01a08296b7 100644
--- a/packages/next/build/webpack-config.ts
+++ b/packages/next/build/webpack-config.ts
@@ -791,11 +791,6 @@ export default async function getBaseWebpackConfig(
minChunks: 1,
reuseExistingChunk: true,
},
- commons: {
- name: 'commons',
- minChunks: totalPages,
- priority: 20,
- },
middleware: {
chunks: (chunk: webpack.compilation.Chunk) =>
chunk.name?.match(MIDDLEWARE_ROUTE),
diff --git a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts
index beefd6dcb861411..8fa95529ea3a2ec 100644
--- a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts
+++ b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts
@@ -4,7 +4,6 @@ import type { BuildManifest } from '../../../../server/get-page-files'
import type { ReactLoadableManifest } from '../../../../server/load-components'
import { NextRequest } from '../../../../server/web/spec-extension/request'
-import { toNodeHeaders } from '../../../../server/web/utils'
import WebServer from '../../../../server/web-server'
import {
@@ -12,20 +11,6 @@ import {
WebNextResponse,
} from '../../../../server/base-http/web'
-const createHeaders = (args?: any) => ({
- ...args,
- 'x-middleware-ssr': '1',
- 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-})
-
-function sendError(req: any, error: Error) {
- const defaultMessage = 'An error occurred while rendering ' + req.url + '.'
- return new Response((error && error.message) || defaultMessage, {
- status: 500,
- headers: createHeaders(),
- })
-}
-
// Polyfilled for `path-browserify` inside the Web Server.
process.cwd = () => ''
@@ -123,31 +108,20 @@ export function getRender({
const requestHandler = server.getRequestHandler()
return async function render(request: NextRequest) {
- const { nextUrl: url, cookies, headers } = request
- const { pathname, searchParams } = url
-
+ const { nextUrl: url } = request
+ const { searchParams } = url
const query = Object.fromEntries(searchParams)
- const req = {
- url: pathname,
- cookies,
- headers: toNodeHeaders(headers),
- }
// Preflight request
if (request.method === 'HEAD') {
+ // Hint the client that the matched route is a SSR page.
return new Response(null, {
- headers: createHeaders(),
+ headers: {
+ 'x-middleware-ssr': '1',
+ },
})
}
- // @TODO: We should move this into server/render.
- if (Document.getInitialProps) {
- const err = new Error(
- '`getInitialProps` in Document component is not supported with the Edge Runtime.'
- )
- return sendError(req, err)
- }
-
const renderServerComponentData = isServerComponent
? query.__flight__ !== undefined
: false
diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx
index 08fdab14c86a070..ac8b5aa38195f46 100644
--- a/packages/next/client/index.tsx
+++ b/packages/next/client/index.tsx
@@ -702,7 +702,9 @@ if (process.env.__NEXT_RSC) {
writer.write(encoder.encode(val))
})
buffer.length = 0
- serverDataBuffer.delete(key)
+ // Clean buffer but not deleting the key to mark bootstrap as complete.
+ // Then `nextServerDataCallback` will be safely skipped in the future renders.
+ serverDataBuffer.set(key, [])
}
serverDataWriter.set(key, writer)
}
diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts
index 92847d189629c92..0c6454f8072bc64 100644
--- a/packages/next/server/dev/hot-reloader.ts
+++ b/packages/next/server/dev/hot-reloader.ts
@@ -336,6 +336,8 @@ export default class HotReloader {
)
)
+ const hasEdgeRuntimePages = this.runtime === 'edge'
+
return webpackConfigSpan
.traceChild('generate-webpack-config')
.traceAsyncFn(() =>
@@ -363,7 +365,7 @@ export default class HotReloader {
}),
// For the edge runtime, we need an extra compiler to generate the
// web-targeted server bundle for now.
- this.runtime === 'edge'
+ hasEdgeRuntimePages
? getBaseWebpackConfig(this.dir, {
dev: true,
isServer: true,
diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx
index c5be24e7da9c543..e4f121fdcd6148c 100644
--- a/packages/next/server/render.tsx
+++ b/packages/next/server/render.tsx
@@ -1,10 +1,29 @@
-import { IncomingMessage, ServerResponse } from 'http'
-import { ParsedUrlQuery, stringify as stringifyQuery } from 'querystring'
+import type { IncomingMessage, ServerResponse } from 'http'
+import type { NextRouter } from '../shared/lib/router/router'
+import type { HtmlProps } from '../shared/lib/html-context'
+import type { DomainLocale } from './config'
+import type {
+ AppType,
+ DocumentInitialProps,
+ DocumentProps,
+ DocumentContext,
+ NextComponentType,
+ RenderPage,
+ RenderPageResult,
+} from '../shared/lib/utils'
+import type { ImageConfigComplete } from './image-config'
+import type { Redirect } from '../lib/load-custom-routes'
+import type { NextApiRequestCookies, __ApiPreviewProps } from './api-utils'
+import type { FontManifest } from './font-utils'
+import type { LoadComponentsReturnType, ManifestItem } from './load-components'
+import type { GetServerSideProps, GetStaticProps, PreviewData } from '../types'
+import type { UnwrapPromise } from '../lib/coalesced-function'
+
import React from 'react'
+import { ParsedUrlQuery, stringify as stringifyQuery } from 'querystring'
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack'
import { renderToReadableStream } from 'next/dist/compiled/react-server-dom-webpack/writer.browser.server'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
-import { UnwrapPromise } from '../lib/coalesced-function'
import {
GSP_NO_RETURNED_VALUE,
GSSP_COMPONENT_MEMBER_ERROR,
@@ -15,56 +34,38 @@ import {
SSG_GET_INITIAL_PROPS_CONFLICT,
UNSTABLE_REVALIDATE_RENAME_ERROR,
} from '../lib/constants'
-import { isSerializableProps } from '../lib/is-serializable-props'
-import { GetServerSideProps, GetStaticProps, PreviewData } from '../types'
-import { isInAmpMode } from '../shared/lib/amp'
-import { AmpStateContext } from '../shared/lib/amp-context'
import {
SERVER_PROPS_ID,
STATIC_PROPS_ID,
STATIC_STATUS_PAGES,
} from '../shared/lib/constants'
+import { isSerializableProps } from '../lib/is-serializable-props'
+import { isInAmpMode } from '../shared/lib/amp'
+import { AmpStateContext } from '../shared/lib/amp-context'
import { defaultHead } from '../shared/lib/head'
import { HeadManagerContext } from '../shared/lib/head-manager-context'
import Loadable from '../shared/lib/loadable'
import { LoadableContext } from '../shared/lib/loadable-context'
import { RouterContext } from '../shared/lib/router-context'
-import { NextRouter } from '../shared/lib/router/router'
import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic'
import {
- AppType,
ComponentsEnhancer,
- DocumentInitialProps,
- DocumentProps,
- DocumentContext,
getDisplayName,
isResSent,
loadGetInitialProps,
- NextComponentType,
- RenderPage,
- RenderPageResult,
} from '../shared/lib/utils'
-
import { HtmlContext } from '../shared/lib/html-context'
-import type { HtmlProps } from '../shared/lib/html-context'
-
-import type { NextApiRequestCookies, __ApiPreviewProps } from './api-utils'
import { denormalizePagePath } from './denormalize-page-path'
-import type { FontManifest } from './font-utils'
-import type { LoadComponentsReturnType, ManifestItem } from './load-components'
import { normalizePagePath } from './normalize-page-path'
import { getRequestMeta, NextParsedUrlQuery } from './request-meta'
import {
allowedStatusCodes,
getRedirectStatus,
- Redirect,
} from '../lib/load-custom-routes'
-import { DomainLocale } from './config'
import RenderResult from './render-result'
import isError from '../lib/is-error'
import { readableStreamTee } from './web/utils'
import { ImageConfigContext } from '../shared/lib/image-config-context'
-import { ImageConfigComplete } from './image-config'
import { FlushEffectsContext } from '../shared/lib/flush-effects'
let optimizeAmp: typeof import('./optimize-amp').default
@@ -1248,6 +1249,13 @@ export async function renderToHTML(
*/
const generateStaticHTML = supportsDynamicHTML !== true
const renderDocument = async () => {
+ if (runtime === 'edge' && Document.getInitialProps) {
+ // In the Edge runtime, Document.getInitialProps isn't supported.
+ throw new Error(
+ '`getInitialProps` in Document component is not supported with the Edge Runtime.'
+ )
+ }
+
if (!runtime && Document.getInitialProps) {
const renderPage: RenderPage = (
options: ComponentsEnhancer = {}
diff --git a/packages/next/server/web/spec-extension/response.ts b/packages/next/server/web/spec-extension/response.ts
index e9993f74720a941..c34ba8a1df566ed 100644
--- a/packages/next/server/web/spec-extension/response.ts
+++ b/packages/next/server/web/spec-extension/response.ts
@@ -87,7 +87,7 @@ export class NextResponse extends Response {
})
}
- static rewrite(destination: string | NextURL) {
+ static rewrite(destination: string | NextURL | URL) {
return new NextResponse(null, {
headers: {
'x-middleware-rewrite': validateURL(destination),
diff --git a/plopfile.js b/plopfile.js
index 2dc8b7e619e01cd..44cbe6eec120d2b 100644
--- a/plopfile.js
+++ b/plopfile.js
@@ -15,7 +15,18 @@ module.exports = function (plop) {
type: 'list',
name: 'type',
message: 'Test type',
- choices: ['e2e', 'unit', 'production', 'development'],
+ choices: [
+ {
+ name: 'e2e - Test "next dev" and "next build && next start"',
+ value: 'e2e',
+ },
+ {
+ name: 'production - Test "next build && next start"',
+ value: 'production',
+ },
+ { name: 'development - Test "next dev"', value: 'development' },
+ { name: 'unit - Test individual files', value: 'unit' },
+ ],
},
],
actions: function (data) {
diff --git a/test/.stats-app/stats-config.js b/test/.stats-app/stats-config.js
index 82741d746daad4b..7996360ebeb5040 100644
--- a/test/.stats-app/stats-config.js
+++ b/test/.stats-app/stats-config.js
@@ -9,7 +9,7 @@ const imagePageData = fs.readFileSync(
const clientGlobs = [
{
- name: 'Client Bundles (main, webpack, commons)',
+ name: 'Client Bundles (main, webpack)',
globs: [
'.next/static/runtime/+(main|webpack)-*',
'.next/static/chunks/!(polyfills*)',
diff --git a/test/integration/react-streaming-and-server-components/app/next.config.js b/test/integration/react-streaming-and-server-components/app/next.config.js
index add280d239bb309..a17299bc8c9eaf2 100644
--- a/test/integration/react-streaming-and-server-components/app/next.config.js
+++ b/test/integration/react-streaming-and-server-components/app/next.config.js
@@ -1,6 +1,7 @@
const withReact18 = require('../../react-18/test/with-react-18')
module.exports = withReact18({
+ trailingSlash: true,
reactStrictMode: true,
onDemandEntries: {
maxInactiveAge: 1000 * 60 * 60,
diff --git a/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js b/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js
new file mode 100644
index 000000000000000..ac58f5e9e2c382c
--- /dev/null
+++ b/test/integration/react-streaming-and-server-components/app/pages/streaming-rsc.server.js
@@ -0,0 +1,23 @@
+import { Suspense } from 'react'
+
+let result
+let promise
+function Data() {
+ if (result) return result
+ if (!promise)
+ promise = new Promise((res) => {
+ setTimeout(() => {
+ result = 'next_streaming_data'
+ res()
+ }, 500)
+ })
+ throw promise
+}
+
+export default function Page() {
+ return (
+
+
+
+ )
+}
diff --git a/test/integration/react-streaming-and-server-components/test/index.test.js b/test/integration/react-streaming-and-server-components/test/index.test.js
index 8f8e7e0fb805ffc..826ca4d5d1428a5 100644
--- a/test/integration/react-streaming-and-server-components/test/index.test.js
+++ b/test/integration/react-streaming-and-server-components/test/index.test.js
@@ -247,12 +247,7 @@ const documentSuite = {
runTests: (context) => {
it('should error when custom _document has getInitialProps method', async () => {
const res = await fetchViaHTTP(context.appPort, '/')
- const html = await res.text()
-
expect(res.status).toBe(500)
- expect(html).toContain(
- '`getInitialProps` in Document component is not supported with the Edge Runtime.'
- )
})
},
beforeAll: () => documentPage.write(documentWithGip),
diff --git a/test/integration/react-streaming-and-server-components/test/rsc.js b/test/integration/react-streaming-and-server-components/test/rsc.js
index 604073c3930fd8e..a01fefe5eb1d605 100644
--- a/test/integration/react-streaming-and-server-components/test/rsc.js
+++ b/test/integration/react-streaming-and-server-components/test/rsc.js
@@ -82,6 +82,12 @@ export default function (context, { runtime, env }) {
expect(await browser.eval('window.beforeNav')).toBe(1)
})
+ it('should handle streaming server components correctly', async () => {
+ const browser = await webdriver(context.appPort, '/streaming-rsc')
+ const content = await browser.eval(`window.document.body.innerText`)
+ expect(content).toMatchInlineSnapshot('"next_streaming_data"')
+ })
+
// Disable next/image for nodejs runtime temporarily
if (runtime === 'edge') {
it('should suspense next/image in server components', async () => {