babel-plugin-transform-react-pug

Use Pug templates to write react components.

npm versionBuild StatusCodecov

babel-plugin-transform-react-pug is a plugin for babel which transpiles pug syntax within template literals to jsx.

Write your components this way:

  1. export const ReactComponent = props => pug`
  2. .wrapper
  3. if props.shouldShowGreeting
  4. p.greeting Hello World!
  5.  
  6. button(onClick=props.notify) Click Me
  7. `

And it will be transpiled into:

  1. export const ReactComponent = props => (
  2. <div className="wrapper">
  3. {props.shouldShowGreeting ? (
  4. <p className="greeting">Hello World!</p>
  5. ) : null}
  6. <button onClick={props.notify}>Click Me</button>
  7. </div>
  8. )

Usage

Syntax

Full information of the syntax you can find in official documentation: pugjs.org.

Basic example

  1. const Component = props => pug` //- const Component = props => (
  2. div //- <div>
  3. if props.amount > MAX_AMOUNT //- {props.amount > MAX_AMOUNT ? (
  4. OtherComponent(fluid crucial) //- <OtherComponent fluid={true} crucial={true} />
  5. else //- ) : (
  6. p You can set bigger amount ;) //- <p>You can set bigger amount ;)</p>
  7. //- )}
  8. each item, index in props.items //- {props.items.map((item, index) => (
  9. div(key=item.id) //- <div key={item.id}>
  10. h3 Header #{index + 1} //- <h3>Header {index + 1}</h3>
  11. = item.body //- {item.body}
  12. //- </div>
  13. //- )}
  14. //- </div>
  15. //- )
  16. `;

How to pass functions and other primitives

  1. const Component = props => pug` //- const Component = props => (
  2. div //- <div>
  3. button( //- <button
  4. type="button" //- type="button"
  5. onClick=props.onClick //- onClick={props.onClick}
  6. ) Click Me //- >Click Me</button>
  7. //-
  8. OtherComponent( //- <OtherComponent
  9. ...props.objectWithPropsForChild //- {...props.objectWithPropsForChild}
  10. fluid //- fluid={true}
  11. data-array=[1, 2, 3] //- data-array={[1, 2, 3]}
  12. ) //- />
  13. //- </div>
  14. //- )
  15. `;

Define local variables and use javascript in attributes

  1. const Component = props => pug` //- const Component = props => (
  2. Fragment //- <Fragment>
  3. button( //- <button
  4. ...one //- {...one}
  5. ...two //- {...two}
  6. onClick=() => alert('Hello') //- onClick={() => alert('Hello')}
  7. text='number ' + 10 //- text={'number ' + 10}
  8. condition=foo === bar ? foo : bar //- condition={foo === bar ? foo : bar}
  9. ) //- ></button>
  10. //-
  11. - const variable = format(props.no) //-
  12. p Variable is #{variable} //- <p>Variable is {format(props.no)}</p>
  13. //- </Fragment>
  14. //- )
  15. `;

Interpolation

If you'd prefer to use interpolation, you can. This is possible by using ${} within your template.

  1. const Component = props => pug`
  2. ul(className=${props.modifier})
  3. ${props.items.map((item, index) => pug`li(key=${index}) ${item}`)}
  4. `;

Eslint integration

Install eslint-plugin-react-pug if you use eslint-plugin-react.

CSS Modules

Whether you use babel plugin to turn on CSS Modules specifically for JSX (e.g. babel-plugin-react-css-modules) or use webpack loader for that to transform styles into key-value object, it's possible to use it with pug.

  1. {
  2. "plugins": [
  3. ["transform-react-pug", {
  4. "classAttribute": "styleName"
  5. }]
  6. ]
  7. }
  1. import './styles.css' // .hello{color:red}
  2.  
  3. const withCorrectStyles = pug`
  4. div.hello I am a red text
  5. `
  • With webpack loader or other approaches which transform styles into object
  1. import classes from './styles.css' // .hello{color:green}
  2.  
  3. const withCorrectStyles = pug`
  4. div(className=classes.hello) I am a green text
  5. `

The developer experience can be improved here by setting classAttribute option to styleName value and adding babel-plugin-transform-jsx-css-modules

  1. {
  2. "plugins": [
  3. ["transform-react-pug", {
  4. "classAttribute": "styleName"
  5. }],
  6. "transform-jsx-css-modules"
  7. ]
  8. }
  1. import './styles.css' // .hello{color:green}
  2.  
  3. const withCorrectStyles = pug`
  4. div.hello I am a green text
  5. `

Install

  • Install via yarn or npm
  1. yarn add --dev babel-plugin-transform-react-pug
  1. npm install --save-dev babel-plugin-transform-react-pug
  • Add to babel configuration before transpiling jsx (usually in .babelrc)
  1. {
  2. "plugins": [
  3. "transform-react-pug",
  4. "transform-react-jsx"
  5. ]
  6. }
  • Now all your templates written with pug are understood by react and browsers.

Configuration

NameTypeDefaultDescription
classAttributeStringclassNameAttribute name which considered by PUG as "class"

classAttribute

Default:

  1. pug`p.one`
  2. =>
  3. <p className="one" />

With "styleName" as value:

  1. pug`p.one`
  2. =>
  3. <p styleName="one" />

create-react-app

Integrating with create-react-app is tricky because it does not allow you to modify babel configuration. There are two documented possibilities:

That is easy, you will get .babelrc file in your root directory, just add transform-react-pug before transform-react-jsx there.

Go through official instruction to rewire your application. Then modify your config-overrides.js:

  1. + const {injectBabelPlugin} = require('react-app-rewired');
  2. module.exports = function override(config, env) {
  3. - //do stuff with the webpack config...
  4. + config = injectBabelPlugin('transform-react-pug', config);
  5. return config;
  6. }

React Native

Just add this plugin to the list in .babelrc file.

  1. {
  2. - "presets": ["react-native"]
  3. + "presets": ["react-native"],
  4. + "plugins": ["transform-react-pug"]
  5. }

We don't need transform-react-jsx here because it's coming with react-native preset.

How it works

Coming soon…

Limitations

  • We can't use dots in component names because pugjs treats everything after dot as a className. For example, React.Fragment becomes <React className="Fragment" />, not <React.Fragment />

A nice workaround is made by babel-plugin-transform-jsx-classname-components. Just add it to .babelrc:

  1. {
  2. "plugins": [
  3. ["transform-jsx-classname-components", {
  4. "objects": ["React"]
  5. }]
  6. ]
  7. }
  • We don't support html language in pug templates. This is different than what Pug promises.

However, you can still use tag interpolation:

  1. p Good #[strong Morning]

FAQ

Can I import template from other files?

The short answer is no and we are not going to implement that in near future. Take a look at initial request with small explanation (#15).

How to get syntax highlighting in IDE (or text editors)?

WebStorm

  • Open settings

  • "Editor" -> "Language Injections"

  • Click on Add new "Generic Js" injection

See how to find this section (youtrack.jetbrains.com/issue/WEB-22106#focus=streamItem-27-2451611-0-0)

  • Name: Pug In Template Literals (JavaScript)
  • ID: Vue (Vue.js template) (current version of pug plugin is created in HTML scope, so we use workaround here)
  • Prefix: <template lang="pug">
  • Suffix: </template>
  • Places Patterns: + taggedString("pug")
    • Click "OK" and "Apply"

Atom

I suggest language-pug-jade because it works better for me. But there are more approaches for building pugjs grammar: language-pug and atom-pug, and you can try them too.

  • Open settings of language-babel in atom

  • Find the field under "JavaScript Tagged Template Literal Grammar Extensions"

  • Enter: pug:source.pug

More details: gandm/language-babel#javascript-tagged-template-literal-grammar-extensions

  • Restart the atom

Visual Studio Code

  • Open settings of extensions

  • Search "vscode-react-pug" by the search field

  • Click "Install" and "Reload"

  • If you use any grammar other than default one (e.g. Babel JavaScript which is quite popular), you might need to add supporting of Atom's Grammar (Microsoft/vscode-js-atom-grammar).

Check out the history beyond that: kaminaly/vscode-react-pug#4.

License

MIT