From b4705259fe041a73fe3901cf2d5c739c3b56b278 Mon Sep 17 00:00:00 2001 From: Fatih Kalifa Date: Wed, 22 Dec 2021 01:06:15 +0700 Subject: [PATCH 1/4] next-swc: fix ssg code elimination when used in render --- packages/next-swc/crates/core/src/next_ssg.rs | 23 +++++++++++++++++++ .../input.js | 9 ++++++++ .../output.js | 5 ++++ 3 files changed, 37 insertions(+) create mode 100644 packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js create mode 100644 packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js diff --git a/packages/next-swc/crates/core/src/next_ssg.rs b/packages/next-swc/crates/core/src/next_ssg.rs index 7e36c32e12bde65..06fb437d1e6c114 100644 --- a/packages/next-swc/crates/core/src/next_ssg.rs +++ b/packages/next-swc/crates/core/src/next_ssg.rs @@ -95,6 +95,7 @@ struct Analyzer<'a> { state: &'a mut State, in_lhs_of_var: bool, in_data_fn: bool, + in_render_fn: bool, } impl Analyzer<'_> { @@ -102,6 +103,8 @@ impl Analyzer<'_> { tracing::trace!("add_ref({}{:?}, data = {})", id.0, id.1, self.in_data_fn); if self.in_data_fn { self.state.refs_from_data_fn.insert(id); + } else if self.in_render_fn { + self.state.refs_from_other.insert(id); } else { if self.state.cur_declaring.contains(&id) { return; @@ -143,6 +146,24 @@ impl Fold for Analyzer<'_> { e } + fn fold_jsx_element(&mut self, jsx: JSXElement) -> JSXElement { + match &jsx.opening.name { + JSXElementName::Ident(i) => { + self.add_ref(i.to_id()); + } + _ => {} + } + let jsx = jsx.fold_children_with(self); + jsx + } + + fn fold_export_default_decl(&mut self, export: ExportDefaultDecl) -> ExportDefaultDecl { + self.in_render_fn = true; + let export = export.fold_children_with(self); + self.in_render_fn = false; + export + } + fn fold_fn_decl(&mut self, f: FnDecl) -> FnDecl { let old_in_data = self.in_data_fn; @@ -312,6 +333,7 @@ impl NextSsg { state: &mut self.state, in_lhs_of_var: false, in_data_fn: true, + in_render_fn: false, }; let n = n.fold_with(&mut v); @@ -376,6 +398,7 @@ impl Fold for NextSsg { state: &mut self.state, in_lhs_of_var: false, in_data_fn: false, + in_render_fn: false, }; m = m.fold_with(&mut v); } diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js new file mode 100644 index 000000000000000..85114d667847090 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js @@ -0,0 +1,9 @@ +import Component from '../' + +export default function Test() { + return +} + +export async function getStaticProps() { + return { props: { name: Component.displayName } } +} diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js new file mode 100644 index 000000000000000..68f6a8c6379b613 --- /dev/null +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js @@ -0,0 +1,5 @@ +import Component from '../' +export var __N_SSG = true +export default function Test() { + return __jsx(Component, null) +} From 67a8d45d4e2949c032c20738303fa87a3b0d1220 Mon Sep 17 00:00:00 2001 From: Fatih Kalifa Date: Wed, 22 Dec 2021 08:27:44 +0700 Subject: [PATCH 2/4] simplify logic and add more thorough tests --- packages/next-swc/crates/core/src/next_ssg.rs | 14 ++------ .../input.js | 33 +++++++++++++++++-- .../output.js | 16 +++++++-- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/packages/next-swc/crates/core/src/next_ssg.rs b/packages/next-swc/crates/core/src/next_ssg.rs index 06fb437d1e6c114..b74fe7dd26c4bcd 100644 --- a/packages/next-swc/crates/core/src/next_ssg.rs +++ b/packages/next-swc/crates/core/src/next_ssg.rs @@ -95,7 +95,6 @@ struct Analyzer<'a> { state: &'a mut State, in_lhs_of_var: bool, in_data_fn: bool, - in_render_fn: bool, } impl Analyzer<'_> { @@ -103,8 +102,6 @@ impl Analyzer<'_> { tracing::trace!("add_ref({}{:?}, data = {})", id.0, id.1, self.in_data_fn); if self.in_data_fn { self.state.refs_from_data_fn.insert(id); - } else if self.in_render_fn { - self.state.refs_from_other.insert(id); } else { if self.state.cur_declaring.contains(&id) { return; @@ -153,15 +150,12 @@ impl Fold for Analyzer<'_> { } _ => {} } - let jsx = jsx.fold_children_with(self); - jsx + + jsx.fold_children_with(self) } fn fold_export_default_decl(&mut self, export: ExportDefaultDecl) -> ExportDefaultDecl { - self.in_render_fn = true; - let export = export.fold_children_with(self); - self.in_render_fn = false; - export + export.fold_children_with(self) } fn fold_fn_decl(&mut self, f: FnDecl) -> FnDecl { @@ -333,7 +327,6 @@ impl NextSsg { state: &mut self.state, in_lhs_of_var: false, in_data_fn: true, - in_render_fn: false, }; let n = n.fold_with(&mut v); @@ -398,7 +391,6 @@ impl Fold for NextSsg { state: &mut self.state, in_lhs_of_var: false, in_data_fn: false, - in_render_fn: false, }; m = m.fold_with(&mut v); } diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js index 85114d667847090..2227ae3f799b624 100644 --- a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js @@ -1,9 +1,36 @@ -import Component from '../' +import { useState, useEffect } from 'react' +import { Root, Children, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect, UnusedInRender } from '../' export default function Test() { - return + const [x, setX] = useState(ValueInRender.value) + useEffect(() => { + setX(ValueInEffect.value) + }, []) + + return ( + +
+ } /> +
+
+ ) } export async function getStaticProps() { - return { props: { name: Component.displayName } } + return { + props: { + // simulate Component usage inside getStaticProps + used: [ + // these import references should not be removed + Root.value, + Children.value, + AttributeValue.value, + AttributeJSX.value, + ValueInRender.value, + ValueInEffect.value, + // this import reference should be removed + UnusedInRender.value, + ], + } + } } diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js index 68f6a8c6379b613..87f2b7651d0855d 100644 --- a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js @@ -1,5 +1,15 @@ -import Component from '../' -export var __N_SSG = true +import { useState, useEffect } from "react"; +import { Root, Children, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect } from "../"; +export var __N_SSG = true; export default function Test() { - return __jsx(Component, null) + const [x, setX] = useState(ValueInRender.value); + useEffect(() => { + setX(ValueInEffect.value); + }, []) + return __jsx(Root, { + x: x + }, __jsx('div', null, __jsx(Children, { + attr: AttributeValue, + jsx: __jsx(AttributeJSX, null) + }))); } From abecb0d4ed59ca72b8d1e25b443d5a7dc6c1b3c4 Mon Sep 17 00:00:00 2001 From: Fatih Kalifa Date: Wed, 22 Dec 2021 08:29:51 +0700 Subject: [PATCH 3/4] comment --- .../should-not-remove-import-used-in-render/input.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js index 2227ae3f799b624..8704c7059c860a3 100644 --- a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js @@ -19,7 +19,7 @@ export default function Test() { export async function getStaticProps() { return { props: { - // simulate Component usage inside getStaticProps + // simulate import usage inside getStaticProps used: [ // these import references should not be removed Root.value, From aa2baf2825f5dc75815d87a0e9045299d98649d0 Mon Sep 17 00:00:00 2001 From: Fatih Kalifa Date: Sun, 9 Jan 2022 09:21:51 +0700 Subject: [PATCH 4/4] remove fold_export_default and fix JSX member expression --- packages/next-swc/crates/core/src/next_ssg.rs | 18 ++++++++++++++---- .../input.js | 4 +++- .../output.js | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/next-swc/crates/core/src/next_ssg.rs b/packages/next-swc/crates/core/src/next_ssg.rs index b74fe7dd26c4bcd..3cc8c6e1302616a 100644 --- a/packages/next-swc/crates/core/src/next_ssg.rs +++ b/packages/next-swc/crates/core/src/next_ssg.rs @@ -144,20 +144,30 @@ impl Fold for Analyzer<'_> { } fn fold_jsx_element(&mut self, jsx: JSXElement) -> JSXElement { + fn get_leftmost_id_member_expr(e: &JSXMemberExpr) -> Id { + match &e.obj { + JSXObject::Ident(i) => { + i.to_id() + } + JSXObject::JSXMemberExpr(e) => { + get_leftmost_id_member_expr(e) + } + } + } + match &jsx.opening.name { JSXElementName::Ident(i) => { self.add_ref(i.to_id()); } + JSXElementName::JSXMemberExpr(e) => { + self.add_ref(get_leftmost_id_member_expr(e)); + } _ => {} } jsx.fold_children_with(self) } - fn fold_export_default_decl(&mut self, export: ExportDefaultDecl) -> ExportDefaultDecl { - export.fold_children_with(self) - } - fn fold_fn_decl(&mut self, f: FnDecl) -> FnDecl { let old_in_data = self.in_data_fn; diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js index 8704c7059c860a3..196f6585af0a465 100644 --- a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/input.js @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { Root, Children, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect, UnusedInRender } from '../' +import { Root, Children, JSXMemberExpression, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect, UnusedInRender } from '../' export default function Test() { const [x, setX] = useState(ValueInRender.value) @@ -11,6 +11,7 @@ export default function Test() {
} /> +
) @@ -28,6 +29,7 @@ export async function getStaticProps() { AttributeJSX.value, ValueInRender.value, ValueInEffect.value, + JSXMemberExpression.value, // this import reference should be removed UnusedInRender.value, ], diff --git a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js index 87f2b7651d0855d..06e38e50c3b907c 100644 --- a/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js +++ b/packages/next-swc/crates/core/tests/fixture/ssg/getStaticProps/should-not-remove-import-used-in-render/output.js @@ -1,5 +1,5 @@ import { useState, useEffect } from "react"; -import { Root, Children, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect } from "../"; +import { Root, Children, JSXMemberExpression, AttributeValue, AttributeJSX, ValueInRender, ValueInEffect } from "../"; export var __N_SSG = true; export default function Test() { const [x, setX] = useState(ValueInRender.value); @@ -11,5 +11,5 @@ export default function Test() { }, __jsx('div', null, __jsx(Children, { attr: AttributeValue, jsx: __jsx(AttributeJSX, null) - }))); + }), __jsx(JSXMemberExpression.Deep.Property, null))); }