@hsuna/babel-plugin-styled-components-pxtorem v1.0.2
babel-plugin-styled-components-pxtorem 
Babel plugin for convert px to rem units of styled-components
Use postcss-pxtorem to process all css text in template strings.
Add a runtime
pxtoremfunction polyfill to process expression embedded in template strings when enable transformRuntime option.
Table of Contents
Requirement
You need to install the following peerDependencies of babel-plugin-styled-components-pxtorem into your project at the same time:
{
"peerDependencies": {
"@babel/core": "^7.26.0",
"postcss": "^8.0.0"
}
}Usage
see example
The use of React and styled-components test cases.
Configuration
babel.config.js:
module.exports = {
plugins: [
['styled-components-pxtorem', { rootValue: 100, unitPrecision: 5, minPixelValue: 0, transformRuntime: false }],
],
};or .babelrc:
{
"plugins": [
[
"styled-components-pxtorem",
{ "rootValue": 100, "unitPrecision": 5, "minPixelValue": 0, "transformRuntime": false }
]
]
}Composition
It should be put before babel-plugin-styled-components
{
"plugins": ["styled-components-pxtorem", "styled-components"]
}Options
Type: Object | Null
Default:
{
rootValue: 100,
unitPrecision: 5,
selectorBlackList: [],
propList: ['*'],
replace: true,
mediaQuery: false,
minPixelValue: 0,
exclude: null,
unit: 'px',
tags: ['styled', 'css', 'createGlobalStyle', 'keyframes'],
transformRuntime: false,
}rootValue(Number | Function) Represents the root element font size or returns the root element font size based on theinputparameterunitPrecision(Number) The decimal numbers to allow the REM units to grow to.propList(Array) The properties that can change from px to rem.- Values need to be exact matches.
- Use wildcard
*to enable all properties. Example:['*'] - Use
*at the start or end of a word. (['*position*']will matchbackground-position-y) - Use
!to not match a property. Example:['*', '!letter-spacing'] - Combine the "not" prefix with the other prefixes. Example:
['*', '!font*']
selectorBlackList(Array) The selectors to ignore and leave as px.- If value is string, it checks to see if selector contains the string.
['body']will match.body-class
- If value is regexp, it checks to see if the selector matches the regexp.
[/^body$/]will matchbodybut not.body
- If value is string, it checks to see if selector contains the string.
replace(Boolean) Replaces rules containing rems instead of adding fallbacks.mediaQuery(Boolean) Allow px to be converted in media queries.minPixelValue(Number) Set the minimum pixel value to replace.exclude(String, Regexp, Function) The file path to ignore and leave as px.- If value is string, it checks to see if file path contains the string.
'exclude'will match\project\postcss-pxtorem\exclude\path
- If value is regexp, it checks to see if file path matches the regexp.
/exclude/iwill match\project\postcss-pxtorem\exclude\path
- If value is function, you can use exclude function to return a true and the file will be ignored.
- the callback will pass the file path as a parameter, it should returns a Boolean result.
function (file) { return file.indexOf('exclude') !== -1; }
- If value is string, it checks to see if file path contains the string.
unit(String) Set the default unit to convert, default ispx.tags(Array) styled-components template literal taggedtransformRuntime(Boolean) since 1.1.0,enable transformation of all expressions that embedded in template strings
Simple version of the formula:
const input = '32px'; // the value in css text
const pixels = parseFloat(input);
if (Math.abs(pixels) < minPixelValue) {
return input;
}
const fixedVal = toFixed(pixels / rootValue, unitPrecision);
return `${fixedVal}rem`;Remaining options are consistent with postcss-pxtorem.
Transform Runtime
If enabled transformRuntime option, all supported expressions embedded in template strings are processed as follows:
Note: Only expression that end with px will be processed.
FunctionExpression
source code:
import styled from 'styled-components';
export const FunctionExpression = styled.button`
height: ${function(props) {
return props.height;
}}px;
`;compiled:
import styled from 'styled-components';
export const FunctionExpression = styled.button`
height: ${(...args) =>
_pxtorem(function(props) {
return props.height;
}, ...args)};
`;
function _pxtorem(input, ...args) {
if (typeof input === 'function') return _pxtorem(input(...args), ...args);
var value = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : 0;
var pixels = Number.isNaN(value) ? 0 : value;
if (Math.abs(pixels) < 0) return pixels + 'px';
var mul = Math.pow(10, 5 + 1);
return (Math.round(Math.floor(((pixels * 1) / 100) * mul) / 10) * 10) / mul + 'rem';
}ArrowFunctionExpression
source code:
import styled from 'styled-components';
const height = '44';
export const ArrowFunction = styled.input.attrs(props => ({
type: 'password',
size: props.size || '16px',
width: props.width || 100,
}))`
color: palevioletred;
font-size: 14px;
border: 1px solid palevioletred;
border-radius: 8px;
width: ${props => props.width}px; /* MemberExpression Body */
height: ${() => height}px; /* Identifier Body */
line-height: ${() => '44'}px; /* StringLiteral Body */
margin: ${() => 32}px; /* NumericLiteral Body */
padding: ${props => props.size};
`;
export const ArrowFunctionWithBlockBody = styled.button`
width: ${props => {
if (props.width) {
return props.width;
} else {
return 0;
}
}}px; /* Block Body */
${props => (props.disabled ? 'height: 400px' : 'height: 200px')};
`;
export const ArrowFunctionWithBinaryBody = styled.button`
${props =>
props.disabled &&
`
width: 200px;
font-size: 14px;
`};
height: ${props => !props.disabled && props.height}px; /* LogicalExpression Body */
width: ${() => 44 + 50}px; /* BinaryExpression Body */
`;
export const ArrowFunctionWithConditionalBody = styled.button`
height: ${props => (props.height ? height : 100)}px; /* ConditionalExpression Body */
`;compiled:
import styled from 'styled-components';
const height = '44';
export const ArrowFunction = styled.input.attrs(props => ({
type: 'password',
size: props.size || '0.16rem',
width: props.width || 100,
}))`
color: palevioletred;
font-size: 0.14rem;
border: 1px solid palevioletred;
border-radius: 0.08rem;
width: ${props => _pxtorem(props.width)}; /* PropertyAccess Body */
height: ${() => _pxtorem(height)}; /* Identifier Body */
line-height: ${() => _pxtorem('44')}; /* StringLiteral Body */
margin: ${() => _pxtorem(32)}; /* NumericLiteral Body */
padding: ${props => props.size};
`;
export const ArrowFunctionWithBlockBody = styled.button`
width: ${props =>
_pxtorem(() => {
if (props.width) {
return props.width;
} else {
return 0;
}
})}; /* Block Body */
${props => (props.disabled ? 'height: 4rem' : 'height: 2rem')};
`;
export const ArrowFunctionWithBinaryBody = styled.button`
${props =>
props.disabled &&
`
width: 2rem;
font-size: 0.14rem;
`};
height: ${props => _pxtorem(!props.disabled && props.height)}; /* ArrowFunction with a LogicalExpression Body */
width: ${() => _pxtorem(44 + 50)}; /* ArrowFunction with a BinaryExpression Body */
`;
export const ArrowFunctionWithConditionalBody = styled.button`
height: ${props =>
props.height ? _pxtorem(height) : _pxtorem(100)}; /* ArrowFunction with a ConditionalExpression Body */
`;
function _pxtorem(input, ...args) {
if (typeof input === 'function') return _pxtorem(input(...args), ...args);
var value = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : 0;
var pixels = Number.isNaN(value) ? 0 : value;
if (Math.abs(pixels) < 0) return pixels + 'px';
var mul = Math.pow(10, 5 + 1);
return (Math.round(Math.floor(((pixels * 1) / 100) * mul) / 10) * 10) / mul + 'rem';
}MemberExpression
source code:
import styled from 'styled-components';
export const MemberExpression = styled.button(
props => `
display: inline;
width: ${props.width}px;
height: ${props.height}; /* Note: Only expression end with 'px' will be processed. */
font-size: 16px;
`,
);compiled:
import styled from 'styled-components';
export const MemberExpression = styled.button(
props => `
display: inline;
width: ${_pxtorem(props.width)};
height: ${props.height}; /* Note: Only expression end with 'px' will be processed. */
font-size: 0.16rem;
`,
);
function _pxtorem(input, ...args) {
if (typeof input === 'function') return _pxtorem(input(...args), ...args);
var value = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : 0;
var pixels = Number.isNaN(value) ? 0 : value;
if (Math.abs(pixels) < 0) return pixels + 'px';
var mul = Math.pow(10, 5 + 1);
return (Math.round(Math.floor(((pixels * 1) / 100) * mul) / 10) * 10) / mul + 'rem';
}ConditionalExpression
source code:
import React from 'react';
import styled from 'styled-components';
export const ConditionalExpression = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize === 'number' ? fontSize : props => props.theme.fontSize}px;
`;
return <StyledButton />;
};
export const ConditionalExpressionWhenTrue = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize !== 'number' ? props => props.theme.fontSize : fontSize}px;
`;
return <StyledButton />;
};
export const ConditionalExpressionWhenFalse = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize === 'number' ? fontSize : 16}px;
`;
return <StyledButton />;
};compiled:
import React from 'react';
import styled from 'styled-components';
export const ConditionalExpression = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize === 'number' ? _pxtorem(fontSize) : props => _pxtorem(props.theme.fontSize)};
`;
return React.createElement(StyledButton, null);
};
export const ConditionalExpressionWhenTrue = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize !== 'number' ? props => _pxtorem(props.theme.fontSize) : _pxtorem(fontSize)};
`;
return React.createElement(StyledButton, null);
};
export const ConditionalExpressionWhenFalse = function({ fontSize } = {}) {
const StyledButton = styled.button`
font-size: ${typeof fontSize === 'number' ? _pxtorem(fontSize) : _pxtorem(16)};
`;
return React.createElement(StyledButton, null);
};
function _pxtorem(input, ...args) {
if (typeof input === 'function') return _pxtorem(input(...args), ...args);
var value = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : 0;
var pixels = Number.isNaN(value) ? 0 : value;
if (Math.abs(pixels) < 0) return pixels + 'px';
var mul = Math.pow(10, 5 + 1);
return (Math.round(Math.floor(((pixels * 1) / 100) * mul) / 10) * 10) / mul + 'rem';
}Other Expressions
Identifier, CallExpression, BinaryExpress, StringLiteral, NumericLiteral, MemberExpression, LogicalExpression...
source code:
import styled, { css, createGlobalStyle } from 'styled-components';
const fontSize = 18;
function getHeight() {
const height = 100;
return height / 2;
}
const mixins = css`
padding: 0 16px;
margin: 16px 32px 16px 32px;
`;
export const GlobalStyle = createGlobalStyle`
html body {
${mixins};
font-size: ${fontSize}px; /* Identifier */
width: 1024px;
height: ${getHeight()}px; /* CallExpression */
}
`;
const condition = false;
function calc() {
return 20;
}
export const BinaryAndLogicExpression = styled.button`
${condition ||
`
width: 200px;
`};
height: ${condition || 100}px; /* LogicExpression */
padding: ${40 + 50}px 8px ${4}px 16px; /* BinaryExpression */
line-height: ${calc() - 2}px; /* BinaryExpression */
`;compiled:
import styled, { css, createGlobalStyle } from 'styled-components';
const fontSize = 18;
function getHeight() {
const height = 100;
return height / 2;
}
const mixins = css`
padding: 0 0.16rem;
margin: 0.16rem 0.32rem 0.16rem 0.32rem;
`;
export const GlobalStyle = createGlobalStyle`
html body {
${mixins};
font-size: ${_pxtorem(fontSize)}; /* Identifier */
width: 10.24rem;
height: ${_pxtorem(getHeight())}; /* CallExpression */
}
`;
const condition = false;
function calc() {
return 20;
}
export const BinaryAndLogicExpression = styled.button`
${condition ||
`
width: 2rem;
`};
height: ${_pxtorem(condition || 100)};
padding: ${_pxtorem(40 + 50)} 0.08rem ${_pxtorem(4)} 0.16rem;
line-height: ${_pxtorem(calc() - 2)};
`;
function _pxtorem(input, ...args) {
if (typeof input === 'function') return _pxtorem(input(...args), ...args);
var value = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : 0;
var pixels = Number.isNaN(value) ? 0 : value;
if (Math.abs(pixels) < 0) return pixels + 'px';
var mul = Math.pow(10, 5 + 1);
return (Math.round(Math.floor(((pixels * 1) / 100) * mul) / 10) * 10) / mul + 'rem';
}