Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Transforms styleName to className using compile time CSS module resolution.

License

NotificationsYou must be signed in to change notification settings

gajus/babel-plugin-react-css-modules

Repository files navigation

Travis build statusNPM versionCanonical Code StyleGitterTwitter Follow

Looking for maintainers

This project is not actively maintained by the original author. However, I am happy to nominate new maintainers.If you wish to contribute tobabel-plugin-react-css-modules, please begin by raising PRs that fix existing issues.PRs must pass CI/CD tests, include tests (if they change behavior or fix a bug), and include documentation.

TransformsstyleName toclassName using compile timeCSS module resolution.

In contrast toreact-css-modules,babel-plugin-react-css-modules has a lot smaller performance overhead (0-10% vs +50%; seePerformance) and a lot smaller size footprint (less than 2kb vs 17kb react-css-modules + lodash dependency).

CSS Modules

CSS Modules are awesome! If you are not familiar with CSS Modules, it is a concept of using a module bundler such aswebpack to load CSS scoped to a particular document. CSS module loader will generate a unique name for each CSS class at the time of loading the CSS document (Interoperable CSS to be precise). To see CSS Modules in practice,webpack-demo.

In the context of React, CSS Modules look like this:

importReactfrom'react';importstylesfrom'./table.css';exportdefaultclassTableextendsReact.Component{render(){return<divclassName={styles.table}><divclassName={styles.row}><divclassName={styles.cell}>A0</div><divclassName={styles.cell}>B0</div></div></div>;}}

Rendering the component will produce a markup similar to:

<divclass="table__table___32osj"><divclass="table__row___2w27N"><divclass="table__cell___1oVw5">A0</div><divclass="table__cell___1oVw5">B0</div></div></div>

and a corresponding CSS file that matches those CSS classes.

Awesome!

However, there are several disadvantages of using CSS modules this way:

  • You have to usecamelCase CSS class names.
  • You have to usestyles object whenever constructing aclassName.
  • Mixing CSS Modules and global CSS classes is cumbersome.
  • Reference to an undefined CSS Module resolves toundefined without a warning.

babel-plugin-react-css-modules automates loading of CSS Modules usingstyleName property, e.g.

importReactfrom'react';import'./table.css';exportdefaultclassTableextendsReact.Component{render(){return<divstyleName='table'><divstyleName='row'><divstyleName='cell'>A0</div><divstyleName='cell'>B0</div></div></div>;}}

Usingbabel-plugin-react-css-modules:

  • You are not forced to use thecamelCase naming convention.

  • You do not need to refer to thestyles object every time you use a CSS Module.

  • There is clear distinction between global CSS and CSS modules, e.g.

    <divclassName='global-css'styleName='local-module'></div>

Difference fromreact-css-modules

react-css-modules introduced a convention of usingstyleName attribute to referenceCSS module.react-css-modules is a higher-orderReact component. It is using thestyleName value to construct theclassName value at the run-time. This abstraction frees a developer from needing to reference the imported styles object when using CSS modules (What's the problem?). However, this approach has a measurable performance penalty (seePerformance).

babel-plugin-react-css-modules solves the developer experience problem without impacting the performance.

Performance

The important metric here is the "Difference from the base benchmark". "base" is defined as using React with hardcodedclassName values. The lesser the difference, the bigger the performance impact.

Note:This benchmark suite does not include a scenario whenbabel-plugin-react-css-modules can statically construct a literal value at the build time.If a literal value of theclassName is constructed at the compile time, the performance is equal to the base benchmark.

NameOperations per second (relative margin of error)Sample sizeDifference from the base benchmark
UsingclassName (base)9551 (±1.47%)587-0%
react-css-modules5914 (±2.01%)363-61%
babel-plugin-react-css-modules (runtime, anonymous)9145 (±1.94%)540-4%
babel-plugin-react-css-modules (runtime, named)8786 (±1.59%)527-8%

Platform info:

  • Darwin 16.1.0 x64
  • Node.JS 7.1.0
  • V8 5.4.500.36
  • NODE_ENV=production
  • Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz × 8

View the./benchmark.

Run the benchmark:

git clone git@github.com:gajus/babel-plugin-react-css-modules.gitcd ./babel-plugin-react-css-modulesnpm installnpm run buildcd ./benchmarknpm installNODE_ENV=production ./test

How does it work?

  1. Builds index of all stylesheet imports per file (imports of files with.css or.scss extension).
  2. Usespostcss to parse the matching CSS files into a lookup of CSS module references.
  3. Iterates through allJSX element declarations.
  4. Parses thestyleName attribute value into anonymous and named CSS module references.
  5. Finds the CSS class name matching the CSS module reference:
    • IfstyleName value is a string literal, generates a string literal value.
    • IfstyleName value is ajSXExpressionContainer, uses a helper function (getClassName) to construct theclassName value at the runtime.
  6. Removes thestyleName attribute from the element.
  7. Appends the resultingclassName to the existingclassName value (createsclassName attribute if one does not exist).

Configuration

Configure the options for the plugin within your.babelrc as follows:

{"plugins": [    ["react-css-modules", {"option":"value"    }]  ]}

Options

NameTypeDescriptionDefault
contextstringMust match webpackcontext configuration.css-loader inheritscontext values from webpack. Other CSS module implementations might use different context resolution logic.process.cwd()
excludestringA RegExp that will exclude otherwise included files e.g., to exclude all styles from node_modulesexclude: 'node_modules'
filetypes?FiletypesConfigurationTypeConfigurepostcss syntax loaders like sugarss, LESS and SCSS and extra plugins for them.
generateScopedName?GenerateScopedNameConfigurationTypeRefer toGenerating scoped names. If you use this option, make sure it matches the value oflocalIdentNamein webpack config. See thisissue[path]___[name]__[local]___[hash:base64:5]
removeImportbooleanRemove the matching style import. This option is used to enable server-side rendering.false
webpackHotModuleReloadingbooleanEnables hot reloading of CSS in webpackfalse
handleMissingStyleName"throw","warn","ignore"Determines what should be done for undefined CSS modules (using astyleName for which there is no CSS module defined). Setting this option to"ignore" is equivalent to settingerrorWhenNotFound: false inreact-css-modules."throw"
attributeNames?AttributeNameMapTypeRefer toCustom Attribute Mapping{"styleName": "className"}
skipbooleanWhether to apply plugin if no matchingattributeNames found in the filefalse
autoResolveMultipleImportsbooleanAllow multiple anonymous imports ifstyleName is only in one of them.false

Missing a configuration?Raise an issue.

Note:The default configuration should work out of the box with thecss-loader.

Option types (flow)

typeFiletypeOptionsType={|+syntax:string,+plugins?:$ReadOnlyArray<string|$ReadOnlyArray<[string,mixed]>>|};typeFiletypesConfigurationType={[key:string]:FiletypeOptionsType};typeGenerateScopedNameType=(localName:string,resourcePath:string)=>string;typeGenerateScopedNameConfigurationType=GenerateScopedNameType|string;typeAttributeNameMapType={[key:string]:string};

Configurate syntax loaders

To add support for different CSS syntaxes (e.g. SCSS), perform the following two steps:

  1. Add thepostcss syntax loader as a development dependency:
npm install postcss-scss --save-dev
  1. Add afiletypes syntax mapping to the Babel plugin configuration. For example for SCSS:
"filetypes": {".scss": {"syntax":"postcss-scss"  }}

And optionally specify extra plugins:

"filetypes": {".scss": {"syntax":"postcss-scss","plugins": ["postcss-nested"    ]  }}

NOTE:postcss-nested is added as an extra plugin for demonstration purposes only. It's not needed withpostcss-scss because SCSS already supports nesting.

Postcss plugins can have options specified by wrapping the name and an options object in an array inside your config:

"plugins": [    ["postcss-import-sync2", {"path": ["src/styles","shared/styles"]    }],"postcss-nested"  ]

Custom Attribute Mapping

You can set your own attribute mapping rules using theattributeNames option.

It's an object, where keys are source attribute names and values are destination attribute names.

For example, the<NavLink> component fromReact Router has aactiveClassName attribute to accept an additional class name. You can set"attributeNames": { "activeStyleName": "activeClassName" } to transform it.

The defaultstyleName ->className transformationwill not be affected by anattributeNames value without astyleName key. Of course you can use{ "styleName": "somethingOther" } to change it, or use{ "styleName": null } to disable it.

Installation

Whenbabel-plugin-react-css-modules cannot resolve CSS module at a compile time, it imports a helper function (readRuntimestyleName resolution). Therefore, you must installbabel-plugin-react-css-modules as a direct dependency of the project.

npm install babel-plugin-react-css-modules --save

React Native

If you'd like to get this working in React Native, you're going to have to allow custom import extensions, via arn-cli.config.js file:

module.exports={getAssetExts(){return["scss"];}}

Remember, also, that the bundler caches things like plugins and presets. If you want to change your.babelrc (to add this plugin) then you'll want to add the--reset-cache flag to the end of the package command.

Demo

git clone git@github.com:gajus/babel-plugin-react-css-modules.gitcd ./babel-plugin-react-css-modules/demonpm installnpm start
open http://localhost:8080/

Conventions

Anonymous reference

Anonymous reference can be used when there is only one stylesheet import.

Format:CSS module name.

Example:

import'./foo1.css';// Imports "a" CSS module from ./foo1.css.<divstyleName="a"></div>;

Named reference

Named reference is used to refer to a specific stylesheet import.

Format:[name of the import].[CSS module name].

Example:

importfoofrom'./foo1.css';importbarfrom'./bar1.css';// Imports "a" CSS module from ./foo1.css.<divstyleName="foo.a"></div>;// Imports "a" CSS module from ./bar1.css.<divstyleName="bar.a"></div>;

Example transpilations

AnonymousstyleName resolution

WhenstyleName is a literal string value,babel-plugin-react-css-modules resolves the value ofclassName at the compile time.

Input:

import'./bar.css';<divstyleName="a"></div>;

Output:

import'./bar.css';<divclassName="bar___a"></div>;

NamedstyleName resolution

When a file imports multiple stylesheets, you must use anamed reference.

Have suggestions for an alternative behaviour?Raise an issue with your suggestion.

Input:

importfoofrom'./foo1.css';importbarfrom'./bar1.css';<divstyleName="foo.a"></div>;<divstyleName="bar.a"></div>;

Output:

importfoofrom'./foo1.css';importbarfrom'./bar1.css';<divclassName="foo___a"></div>;<divclassName="bar___a"></div>;

RuntimestyleName resolution

When the value ofstyleName cannot be determined at the compile time,babel-plugin-react-css-modules inlines all possible styles into the file. It then usesgetClassName helper function to resolve thestyleName value at the runtime.

Input:

import'./bar.css';<divstyleName={Math.random()>.5 ?'a' :'b'}></div>;

Output:

import_getClassNamefrom'babel-plugin-react-css-modules/dist/browser/getClassName';importfoofrom'./bar.css';const_styleModuleImportMap={foo:{a:'bar__a',b:'bar__b'}};<divstyleName={_getClassName(Math.random()>.5 ?'a' :'b',_styleModuleImportMap)}></div>;

Limitations

Have a question or want to suggest an improvement?

FAQ

How to migrate from react-css-modules to babel-plugin-react-css-modules?

Follow the following steps:

  • Removereact-css-modules.
  • Addbabel-plugin-react-css-modules.
  • Configure.babelrc (seeConfiguration).
  • Remove all uses of thecssModules decorator and/or HoC.

If you are still having problems, refer to one of the user submitted guides:

How to reference multiple CSS modules?

react-css-modules had an optionallowMultiple.allowMultiple allows multiple CSS module names in astyleName declaration, e.g.

<divstyleName='foo bar'/>

This behaviour is enabled by default inbabel-plugin-react-css-modules.

How to live reload the CSS?

babel-plugin-react-css-modules utilises webpackHot Module Replacement (HMR) to live reload the CSS.

To enable live reloading of the CSS:

Note:

This enables live reloading of the CSS. To enable HMR of the React components, refer to theHot Module Replacement - React guide.

Note:

This is awebpack specific option. If you are usingbabel-plugin-react-css-modules in a different setup and require CSS live reloading, raise an issue describing your setup.

I get a "Cannot use styleName attribute for style name '[X]' without importing at least one stylesheet." error

First, ensure that you are correctly importing the CSS file following theconventions.

If you are correctly importing but using different CSS (such as SCSS), this is likely happening because your CSS file wasn't able to be successfully parsed. You need toconfigure a syntax loader.

I get a "Could not resolve the styleName '[X]' error but the class exists in the CSS included in the browser.

First, verify that the CSS is being included in the browser. Remove fromstyleName the reference to the CSS class that's failing and view the page. Search through the<style> tags that have been added to the<head> and find the one related to your CSS module. Copy the code into your editor and search for the class name.

Once you've verified that the class is being rendered in CSS, the likely cause is that thebabel-plugin-react-css-modules is unable to find your CSS class in the parsed code. If you're using different CSS (such as SCSS), verify that you haveconfigured a syntax loader.

However, if you're using a syntaxes such aspostcss-scss orpostcss-less, they do not compile down to CSS. So if you are programmatically building a class name (see below), webpack will be able to generate the rendered CSS from SCSS/LESS, butbabel-plugin-react-css-modules will not be able to parse the SCSS/LESS.

A SCSS example:

$scales:10,20,30,40,50;@each$scalein$scales {.icon-#{$scale} {width:$scale;height:$scale;  }  }

babel-plugin-react-css-modules will not receiveicon-10 oricon-50, buticon-#{$scale}. That is why you receive the error thatstyleName"icon-10" cannot be found.

About

Transforms styleName to className using compile time CSS module resolution.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

No packages published

Contributors34


[8]ページ先頭

©2009-2025 Movatter.jp