Sunday, 18 March 2018

How to use Ant Design library with Isomorphic style loader in React Starter Kit Project

I wanted to use isomorphic-style-loader in combination with Ant Design in a project built using React Starter Kit so that I could use the less processor to customise the default Ant styles. If you try to do it the way suggested by the Ant website using babel-import-plugin:

module: {
    rules: [
        ...
        loader: 'babel-loader,
        options: {
            ...
            plugins: [
                ...
                ['import', {libraryName: 'antd', style: true}]
            ] 
        }
    ]
}

Then you'll quickly run into this type of issue:

[19:51:42] Launching server...
/home/frontend/node_modules/antd/lib/style/index.less:1
(function (exports, require, module, __filename, __dirname) { @import "./themes/default";
                                                              ^

SyntaxError: Invalid or unexpected token
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:607:28)
    at Module._extensions..js (module.js:654:10)
    at Object.require.extensions.(anonymous function) [as .js] (/home/frontend/node_modules/babel-register/lib/node.js:152:7)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
error An unexpected error occurred: "Command failed.
Exit code: 1

Why it doesn't work


This is because the babel-import-plugin transforms this:

import {Button} from 'antd'

Into:

require('antd/lib/button/style')
var _button = require('antd/lib/button')

In hindsight, I don't know why/how I ever thought this could work.

The whole point of using the isomorphic style loader is to be explicit about which style files are required by each component so your sever can package only the ones required for the initial page render. This is antithetical to what is happening with the babel-import-plugin output, which is just injecting require statements into files and not keeping track of any association with components. If you were using the regular style-loader this would be sufficient to ensure the styles were injected into the head of the html document. If you are using the isomorphic-style-loader then you are generating  the html dynamically in your server code and using it's API to insert just the styles in the current React provider context, so none of the Ant styles will get included.

Furthermore, if you are using a common module config in your webpack.config.js file for the server and client then by enabling babel-import-plugin you'll end up trying to require the Ant '.less' files from your node app which will always fail because less syntax is not valid javascript and library code (stuff in /node_modules/ ) is excluded from webpack bundles by default!


So what is the answer?

I found the simplest solution is to use the isomorphic-style-loader withStyles function to wrap the top-level application React component with *all* the styles needed by my app. The downside is that you'll ship more styles than are required for the initial render but probably not that much more, since if you are using Ant in your project, you're probably using it extensively throughout the app. The upside is that the code is explicit. I created a JS module called withAntStyles.js:

import React from 'react'
import withStyles from 'isomorphic-style-loader/lib/withStyles'


// Styles includes
// Include just the styles you are using in your project. 
// You'll have to remember to add new ones as you go along
import antdStyles from 'antd/lib/style/index.less'
import layoutStyles from 'antd/lib/layout/style/index.less'
import gridStyles from 'antd/lib/grid/style/index.less'
...
import badgeStyles from 'antd/lib/badge/style/index.less'
import uploadStyles from 'antd/lib/upload/style/index.less'


function withAntStyles(AntStyledComponent) {
  return withStyles(
    antdStyles,
    layoutStyles,
    gridStyles,
    ...
    badgeStyles,
    uploadStyles
  )(AntStyledComponent)
}

export default withAntStyles

So now all you have to do is wrap your top most application React Component, e.g.:


import React from 'react'
import withStyles from 'isomorphic-style-loader/lib/withStyles'
import {Layout} from 'antd'
import withAntStyles from '../withAntStyles'

const {Content, Sider} = Layout

class AppLayout extends React.Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
  }
  render(){
    return (
      <layout>
        ...
      </layout>
    )
  }
}

export default withAntStyles(AppLayout)

Finally I added the less-loader to my Webpack config:

          // Compile Less to CSS
          // https://github.com/webpack-contrib/less-loader
          // Install dependencies before uncommenting: yarn add --dev less-loader less
          {
            test: /\.less$/,
            use:[
              {
                loader: 'less-loader',
                options: {
                  modifyVars: {}, // custom theme overrides go here...
                  javascriptEnabled: true
                }
              }
            ]
          }

5 comments:

Eric Chen said...

THANKS! Just got these styles working thanks to your help setting it up :) I was dreading getting all these ant styles setup properly, but thank god it works.

Also, helped me understand how the babel loader and styles works in the isomorphic stylesheets better.

cuo said...

hi cris, i'm using react-starter-kit too
and i'm stucked -__- do you have github? i wanted to see your work if you dont mind

James said...

Surprised to find such a detailed and well-written guide on Ant Design LIBRARY, thanks!

Robet John said...

It’s my fortune to go to at this blog and realize out my required stuff that is also in the quality.
visit here

Roof & Driveway Cleaning London said...

We have been ensuring and broadening the existence of rooftop tiles utilizing airless splash hardware for 25 or more years. Our demonstrated, attempted and tried, German fabricated, clear or shading pigmented defensive coatings, will leave your rooftop resembling a fresh out of the box new one for a small portion of the expense. I compare the utilization of these remarkable coatings as like ensuring the bodywork of your vehicle. We wash our vehicles routinely ourselves or we take them to a carwash. Eventually, we'll notice that the paintwork is beginning to look dull and will at that point, sooner or later, either apply the clean and buff it ourselves or once more, pay for another person to do it. Why clean it?

Well it will unquestionably look better, water will dab and run off rapidly and bird-droppings or tree sap will at this point don't start to "destroy" your paintwork.

We do this to something that degrades each time we fire it up (much of the time). Your home (your mansion) over the long haul, simply does the inverse! I'm truly glad that you're thinking about rooftop cleaning and would invite the chance to give a free citation to you. On the off chance that you like and simultaneously we can give a citation to securing your now perfect rooftop (yet not ensured) from the components.

I'm not going to talk "over your head" about the specialized determinations and cycles of these shocking defensive coatings, yet know this:Once we have cleaned and taken out the greenery, lichen, and green growth from your rooftop tiles and before the use of either a reasonable or shaded defensive covering, our master worker for hire will place another tip into his splash firearm. We just utilize the market-pioneer for our tips. Graco tips are made out of the greatest grade of tungsten carbide, the most grating safe material utilized in the assembling of airless shower tips.

All shower tips will wear with ordinary use. All coatings contain solids that are rough some more than others. Utilizing a well used tip will bring about a sketchy completion, since when a tip wears, the size of the tip hole increments and the fan width diminishes. This powers more passes to cover the surface prompting a break in the ideal conveyance design. Joining the right Graco splash tip with our firearm assumes a major part in assisting us with making the expert completion your rooftop covering position requests. Not exclusively does the tip decide how much liquid will leave the weapon when our project worker pulls the trigger, the splash tip additionally decides how wide a shower fan the firearm will make. Our worker for hire is likewise watching the tip for any indications of stopping up We just utilize Graco's reversible tips. With a reversible tip, he can without much of a stretch clear tip stops up by just turning the tip 180 degrees to the perfect position and afterward setting off the sprayer.

Phone: 020 3929 3815

business email: info@roofanddrivewaycleaning.co.uk

Website: https://www.roofanddrivewaycleaning.co.uk/