You’re Using Materialize CSS Wrong

Smaller bundles, code splitting and easy monolithic library breaking!

Would you want to download all of this to view a product page?

Maybe you’re not using materialize wrong, but here’s my story and use case for tweaking in my projects. Continue reading if you are:

  1. Using create-react-app / webpack / es6 modules
  2. Moderately concerned about bundle size
  3. Enjoy knowing you’re only using what you import

Why?

As per the getting started page of Materialize, your only options are to import everything lock stock and barrel. This doesn’t work for me, and you should be skeptical as well if you care at all about performance. Network, devices and user experience are implicated with huge chunks of JS and CSS.

How JS

First step is to create a custom build of materialize’s JS. I’ve created a custom grunt file. The key trick was removing 3 occurrences of a large list of JS files with a single JS files array and then culling that array to the base essentials.

To run this file from the command line you will first need to npm i in the materialize-css repo / npm module folder. Then run:

grunt --gruntfile custom-grunt.js release

Now your files in dist will be only the “core” files of materialize, no components.

Create React App / I Can’t Control Bundling

You will have to include “materialize.min.js” in the head of your public/index.html I haven’t figured out a way around this yet. Materialize components need classes like “Component” and objects like “cash” a jQuery-esque thing to be in scope before you can use imports.

How CSS

Ok this part is easy. Simply navigate to materialize-css/sass/materialize.scss and edit the imports. You will need all the core imports and leave any components you want in your project like so:

Doing ok? Great. The //actual components comment was me, because you need the global import.

Import Options for CSS

You can run the build command again and include the minified CSS in the header. Or, since most bundlers support Sass you can import it using JS in your project or using your bundler. Whatever you prefer.

Import Specific Component

The moment of truth. We can import the components “a la carte” now into our React component tree.

Notice I’m also importing the css lock stock here, but because I’ve changed the imports and webpack will not duplicate it in my bundle, it’s fine. Not sure what your preferences are, as long as the sass is compiled and injected at some point, you should be fine.

This provides the added benefit of me changing my mind about imports of components that do not require JS. The Sass will recompile, I just need to add the import in materialize.scss, that is either in my project root or node_modules folder.

Code Splitting

Right. So now we have a bunch of components being imported all over the place and the bundle size is getting larger.

What if some users only use admin components and some users a lot less components in say… more public facing paths that we’d like to load quickly. Here’s the answer: promise import syntax. WHAT?

Check that out. The Carousel JS code will be bundled separately and only loaded when this component needs to mount. This could be a route or widget style component that’s only included in a few routes.

Dig into code splitting in React here.

Alternatives

I looked into react-materialize. While I enjoy the spirit behind the project, it did seem like a rouge developer made a wrapper. I didn’t need react components for materialize, I just needed the components themselves. If I really want to remote control them, I’ll do so through refs, state and render.

Wrap Up

I hope this post was helpful in understanding that sometimes it only takes a few tweaks to break up a monolithic JS/CSS component library. Provided you don’t need React style component wrappers for materialize components, you will be fine with the provided solution. For interaction you will probably want to dig into the materialize docs and have React change class names for you based on props / state. Enjoy!

medium.com/@mattdlockyer
twitter.com/mattdlockyer
linkedin.com/in/mattlockyer