Skip to content

Commit

Permalink
feat: enable configuration of styled-components transform and enabl…
Browse files Browse the repository at this point in the history
…e `css` prop support
  • Loading branch information
ForsakenHarmony committed Jun 21, 2022
1 parent 1f68a5d commit 9c6631d
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 68 deletions.
27 changes: 23 additions & 4 deletions docs/advanced-features/compiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,31 @@ We're working to port `babel-plugin-styled-components` to the Next.js Compiler.
First, update to the latest version of Next.js: `npm install next@latest`. Then, update your `next.config.js` file:

```js
// next.config.js

module.exports = {
compiler: {
// ssr and displayName are configured by default
styledComponents: true,
// see https://styled-components.com/docs/tooling#babel-plugin for more info on the options.
styledComponents: boolean | {
// Enabled by default in development, disabled in production to reduce file size,
// setting this will override the default for all environments.
displayName?: boolean,
// Enabled by default.
ssr?: boolean,
// Enabled by default.
fileName?: boolean,
// Empty by default.
topLevelImportPaths?: string[],
// Defaults to ["index"].
meaninglessFileNames?: string[],
// Disabled by default.
cssProp?: boolean,
// Empty by default.
namespace?: string,
// Not supported yet.
minify?: boolean,
// Not supported yet.
transpileTemplateLiterals?: boolean,
// Not supported yet.
pure?: boolean,
},
}
```
Expand Down
23 changes: 6 additions & 17 deletions packages/next-swc/crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,23 +134,12 @@ pub fn custom_before_pass<'a, C: Comments + 'a>(
styled_jsx::styled_jsx(cm.clone(), file.name.clone()),
hook_optimizer::hook_optimizer(),
match &opts.styled_components {
Some(config) => {
let config = Rc::new(config.clone());
let state: Rc<RefCell<styled_components::State>> = Default::default();

Either::Left(chain!(
styled_components::analyzer(config.clone(), state.clone()),
styled_components::display_name_and_id(
file.name.clone(),
file.src_hash,
config,
state
)
))
}
None => {
Either::Right(noop())
}
Some(config) => Either::Left(styled_components::styled_components(
file.name.clone(),
file.src_hash,
config.clone(),
)),
None => Either::Right(noop()),
},
Optional::new(
next_ssg::next_ssg(eliminated_packages),
Expand Down
19 changes: 16 additions & 3 deletions packages/next-swc/crates/styled_components/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use crate::{
use serde::Deserialize;
use std::{cell::RefCell, rc::Rc};
use swc_atoms::JsWord;
use swc_common::{chain, FileName};
use swc_common::{chain, FileName, pass::Optional};
use swc_ecmascript::visit::{Fold, VisitMut};

mod css;
Expand All @@ -28,6 +28,9 @@ pub struct Config {
#[serde(default = "true_by_default")]
pub file_name: bool,

#[serde(default = "default_index_file_name")]
pub meaningless_file_names: Vec<String>,

#[serde(default)]
pub namespace: String,

Expand All @@ -40,6 +43,9 @@ pub struct Config {
#[serde(default)]
pub minify: bool,

#[serde(default)]
pub pure: bool,

#[serde(default)]
pub css_prop: bool,
}
Expand All @@ -48,6 +54,10 @@ fn true_by_default() -> bool {
true
}

fn default_index_file_name() -> Vec<String> {
vec!["index".to_string()]
}

impl Config {
pub(crate) fn use_namespace(&self) -> String {
if self.namespace.is_empty() {
Expand All @@ -70,7 +80,10 @@ pub fn styled_components(

chain!(
analyzer(config.clone(), state.clone()),
display_name_and_id(file_name, src_file_hash, config, state),
transpile_css_prop()
display_name_and_id(file_name, src_file_hash, config.clone(), state),
Optional {
enabled: config.css_prop,
visitor: transpile_css_prop()
}
)
}
37 changes: 19 additions & 18 deletions packages/next-swc/crates/styled_components/src/utils/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,28 @@ impl Visit for Analyzer<'_> {
fn visit_var_declarator(&mut self, v: &VarDeclarator) {
v.visit_children_with(self);

if let Pat::Ident(name) = &v.name {
if let Some(Expr::Call(CallExpr {
if let (
Pat::Ident(name),
Some(Expr::Call(CallExpr {
callee: Callee::Expr(callee),
args,
..
})) = v.init.as_deref()
{
if let Expr::Ident(callee) = &**callee {
if &*callee.sym == "require" && args.len() == 1 && args[0].spread.is_none() {
if let Expr::Lit(Lit::Str(v)) = &*args[0].expr {
let is_styled = if self.config.top_level_import_paths.is_empty() {
&*v.value == "styled-components"
|| v.value.starts_with("styled-components/")
} else {
self.config.top_level_import_paths.contains(&v.value)
};

if is_styled {
self.state.styled_required = Some(name.id.to_id());
self.state.unresolved_ctxt = Some(callee.span.ctxt);
}
})),
) = (&v.name, v.init.as_deref())
{
if let Expr::Ident(callee) = &**callee {
if &*callee.sym == "require" && args.len() == 1 && args[0].spread.is_none() {
if let Expr::Lit(Lit::Str(v)) = &*args[0].expr {
let is_styled = if self.config.top_level_import_paths.is_empty() {
&*v.value == "styled-components"
|| v.value.starts_with("styled-components/")
} else {
self.config.top_level_import_paths.contains(&v.value)
};

if is_styled {
self.state.styled_required = Some(name.id.to_id());
self.state.unresolved_ctxt = Some(callee.span.ctxt);
}
}
}
Expand Down
13 changes: 5 additions & 8 deletions packages/next-swc/crates/styled_components/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
pub use self::analyzer::{analyze, analyzer};
use once_cell::sync::Lazy;
use regex::{Captures, Regex};
use std::{borrow::Cow, cell::RefCell};
use swc_atoms::js_word;
use swc_common::{collections::AHashMap, SyntaxContext};
Expand Down Expand Up @@ -304,10 +302,9 @@ impl State {
}

pub fn prefix_leading_digit(s: &str) -> Cow<str> {
static REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"^(\d)").unwrap());

REGEX.replace(s, |s: &Captures| {
//
format!("sc-{}", s.get(0).unwrap().as_str())
})
if s.chars().next().map(|c| c.is_digit(10)).unwrap_or(false) {
Cow::Owned(format!("sc-{}", s))
} else {
Cow::Borrowed(s)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,10 @@ struct DisplayNameAndId {

impl DisplayNameAndId {
fn get_block_name(&self, p: &Path) -> String {
let file_stem = p.file_stem();
if let Some(file_stem) = file_stem {
if file_stem == "index" {
} else {
return file_stem.to_string_lossy().to_string();
}
} else {
match p.file_stem().map(|s| s.to_string_lossy().to_string()) {
Some(file_stem) if !self.config.meaningless_file_names.contains(&file_stem) => file_stem,
_ => self.get_block_name(p.parent().expect("path only contains meaningless filenames (e.g. /index/index)?")),
}

self.get_block_name(p.parent().expect("/index/index/index?"))
}

fn get_display_name(&mut self, _: &Expr) -> JsWord {
Expand Down
18 changes: 13 additions & 5 deletions packages/next/build/swc/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,7 @@ function getBaseSWCOptions({
},
},
sourceMaps: jest ? 'inline' : undefined,
styledComponents: nextConfig?.compiler?.styledComponents
? {
displayName: Boolean(development),
}
: null,
styledComponents: getStyledComponentsOptions(nextConfig, development),
removeConsole: nextConfig?.compiler?.removeConsole,
// disable "reactRemoveProperties" when "jest" is true
// otherwise the setting from next.config.js will be used
Expand All @@ -121,6 +117,18 @@ function getBaseSWCOptions({
}
}

function getStyledComponentsOptions (nextConfig, development) {
let styledComponentsOptions = nextConfig?.compiler?.styledComponents;
if (!styledComponentsOptions) {
return null
}

return {
...styledComponentsOptions,
displayName: styledComponentsOptions.displayName ?? Boolean(development),
}
}

function getEmotionOptions(nextConfig, development) {
if (!nextConfig?.compiler?.emotion) {
return null
Expand Down
19 changes: 18 additions & 1 deletion packages/next/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,24 @@ export interface NextConfig extends Record<string, any> {
| {
exclude?: string[]
}
styledComponents?: boolean
styledComponents?:
| boolean
| {
/**
* Enabled by default in development, disabled in production to reduce file size,
* setting this will override the default for all environments.
*/
displayName?: boolean,
topLevelImportPaths?: string[],
ssr?: boolean,
fileName?: boolean,
meaninglessFileNames?: string[],
minify?: boolean,
transpileTemplateLiterals?: boolean,
namespace?: string,
pure?: boolean,
cssProp?: boolean,
},
emotion?:
| boolean
| {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-refresh-utils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
}
},
"include": ["**/*.ts"],
"exclude": ["node_modules"]
"exclude": ["node_modules", "dist"]
}
5 changes: 4 additions & 1 deletion test/development/basic/styled-components/next.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module.exports = {
compiler: {
styledComponents: true,
styledComponents: {
displayName: true,
cssProp: true,
},
},
}
2 changes: 1 addition & 1 deletion test/development/basic/styled-components/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const Button = styled.a`
export default function Home() {
console.log('__render__')
return (
<div>
<div css={`background: black`}>
<Button
href="https://github.com/styled-components/styled-components"
target="_blank"
Expand Down

0 comments on commit 9c6631d

Please sign in to comment.