You’re Using Materialize CSS Wrong
Smaller bundles, code splitting and easy monolithic library breaking!
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:
- Using create-react-app / webpack / es6 modules
- Moderately concerned about bundle size
- Enjoy knowing you’re only using what you import
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.
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.
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.
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.
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.
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!