Getting Started with Fable. CSS

Photo by Lee Campbell on Unsplash

This article is the continuation of “Getting started with Fable” series, so if you missed the previous articles please visit:

In these articles I’m trying to create the project using Fable and F# as main language. I’m doing this from the perspective of front-end developer, so all these Webpack configurations are not a surprise to me, but I hope that this information will be useful for .NET developers. On the other hand, I face a lot of problems/questions related to Fable and F# and I hope my findings will help front-end developers who are looking for something new in front-end development (personally I dislike TypeScript and looking for a good alternative).

CSS Import

So what we have right now: we have a React/Fable project which compiles and produces a single line of text. Frankly speaking it’s not much. And it’s definitely not enough to build a fully-functional enterprise application. All applications should look attractive enough and to achieve this goal we’ll include one more language into our application – CSS. There is no significant difference between incorporating SASS/LESS/Stylus and pure CSS but nowadays I’m thinking that preprocessors are no longer must have for front-end development:

  • Nesting which is provided by most of the preprocessors out of the box often used incorrectly producing huge and slow selectors;
  • Mixins encourage code duplication, because they exist only on compile time, bloating the resulting CSS bundle. So from my personal observations people who are not aware of mixins writing much more concise and supportable styles;
  • Variables which were a killer feature of all preprocessors are available in all major browsers right now.

As a result from my perspective the only thing you’ll need is a tool called autoprefixer. This tool allows to generate a proper CSS for browsers which do not comply with the CSS specification, e.g. CSS grid is partially implemented in Internet Explorer 11 but all available properties have -ms- vendor prefix. Of course you can write all these prefixed properties yourself. But it’s really easy to miss something. Also if at some point of time your customer/company decide to drop support for particular browser you just change supported browsers configuration file and reduce the size of bundle!

So the first thing you need to do to start writing CSS in your Fable project you need to install corresponding webpack loaders:

yarn add style-loader –dev
yarn add css-loader –dev
view raw hosted with ❤ by GitHub

Also you need to register these loaders similar to Fable loader:

// No changes
module.exports = {
// No changes
module: {
rules: [{
test: /\.fs(x|proj)?$/,
use: 'fable-loader'
}, {
test: /\.css$/,
use: [
view raw webpack.config.js hosted with ❤ by GitHub

Now to add any CSS file to your project you just need to reference it in appropriate F# script file by writing something like importSideEffects "./reset.css". At this point of time you probably have several questions:

  • Why are you referencing styles in scripts? Because it’s much easier to track styles, remove obsolete when component is getting removed from the project. This is a very common situation on the project when styles and components live in separate directories and have separate dependency trees. In the webpack project has two different references to index script and to index stylesheet. As a result everyone lost track of abandon styles and project has tons of unused CSS. Don’t do it;
  • Why are you not using type providers? Because I don’t think that I need one. It’s quite simple. In general using a CSS in component ends up in adding several classes for appropriate HTML elements. If I’ll not add this classes elements will not look the way I expect. I’ll not miss it. Refactoring of CSS is rarely needed. I can’t imagine a situation when I’ll need to rename dozens of class names. I often change the styles but renaming the class names is often a result of changes in markup.


But it doesn’t mean that I don’t think we need some sort of control over CSS code. To verify the fact that all styles in application are written in the same way we’ll use stylelint:

yarn add stylelint –dev
yarn add stylelint-webpack-plugin –dev
yarn add stylelint-config-standard –dev

After that you need to update webpack configuration, because we want to make linting a part of our build and include into our Continuous Integration pipeline:

// No changes
const StylelintPlugin = require('stylelint-webpack-plugin');
module.exports = {
// No changes
plugins: [
// No changes
new StylelintPlugin({
configFile: 'stylelint.config.js',
context: './src',
files: '**/*.css',
fix: true
// No changes
view raw webpack.config.js hosted with ❤ by GitHub

And as a last step you’ll need to create configuration file stylelint.config.js. Here is the sample configuration, which uses recommended basic configuration and shows how to extend/override properties (personally I found two space indentation not very visual):

module.exports = {
extends: 'stylelint-config-standard',
rules: {
indentation: 4
view raw stylelint.config.js hosted with ❤ by GitHub


As I’ve mentioned earlier, autoprefixer is a very important tool in modern web development. It helps you to provide to end users the styles they need. You can target different browsers based on your direct requirements, based on market share or taking analytics of your application (if available). Having this information you can support the browsers you need. Installation is very simple:

yarn add postcss –dev
view raw hosted with ❤ by GitHub

The first step as usual is installation of package. The second step is creation of configuration for this package. To do so you need to create a postcss.config.js file and add basic configuration:

module.exports = {
plugins: [
view raw postcss.config.js hosted with ❤ by GitHub

Also you need to add postcss-loader to the list of CSS loaders, just after style-loader and css-loader. And the last, but the most important thing you need is to create a configuration file with targeted browsers. This file is called .browserslistrc. This file is very flexible, you can find a full guide here. As a starting point I would recommend to add only one line “defaults” (without quotes). To understand which browsers will be used in that case you can by typing npx browserslist. You should see the list of browsers which satisfy you ruleset :

browserslist defaults configuration

Continuous integration

And the last step for today. I want to show that all these configurations can be easily integrated with CI tools and can help you to write consistent code. I’ll show the configuration file for the recently released GitHub Actions. You need to create a file in you repository ,github/workflows/nodejs.yml and add the code below:

name: Node CI
on: [push]
runs-on: ubuntu-latest
node-version: [12.x]
uses: actions/checkout@v1
name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
node-version: ${{ matrix.node-version }}
name: action-yarn
uses: comchangs/action-yarn@v0.1-beta
name: yarn install and build
run: |
yarn build
CI: true
view raw nodejs.yml hosted with ❤ by GitHub

In my opinion this configuration file is self-descriptive, we run Ubuntu with Node.js 12, install Yarn, install project’s dependencies and run our build. That’s it!


The last thing I want to add is the screenshot of project directory tree structure to avoid any confusion:

Directory tree

That’s basically it for today. In the next posts I’ll concentrate on development itself, I hope it’s enough from infrastructure’s stand point for now. If you have any questions or faced any issues during following this manual don’t hesitate to write in the comments below.

Thanks a lot for reading! I hope you’ve enjoyed. If you find this material useful, don’t forget to subscribe and share with your colleagues and friends! Thanks!

6 thoughts on “Getting Started with Fable. CSS

  1. I’m enjoying this series, specifically because of your frontend dev view (which I do not have 😀).
    Have you taken a look at Fulma/Bulma ? Would be interested in your take.

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s