I had a conundrum last summer on an Angular project. We got a bug report from an influential stakeholder and attached to the bug report was a screenshot of our beautiful website mangled in IE11. There was another similar bug filed for Edge 15.
All the elements on the page looked like they had been absolutely positioned on top of one another. I knew the cause right away, IE11 and Edge 15 were trying to render the legacy display: -ms-grid
. The trouble was, I didn’t write any -ms-grid
rules, so this must be the work of Autoprefixer somewhere in the toolchain.
I began the quest looking for autoprefixer({ grid: true })
in my Webpack config… but couldn’t find where it was being called! Doing some searches, an /r/webdev/ thread suggested the ridiculous notion that Angular CLI will autodetect Autoprefixer in your node_modules/
folder and automatically run Autoprefixer. This can’t be true I thought… but it is true!
Though not a direct dependency that I could see, Angular CLI would automatically run Autoprefixer for you with the { grid: true }
flag enabled. But -ms-grid
is missing critical features like auto-fill
that can’t be back-supported by Autoprefixer.
Counterintuitively, in order to fix this issue, I had to scope Autoprefixer to ignore IE using browserlist
property in my package.json
browserlist: [
"not ie > 0"
]
In order to fix IE… I had to stop supporting IE.
The good news is that this has been fixed! A simple one-line fix inside everyone’s favorite config file packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/styles.ts
. Hiding in plain sight! I don’t know why I didn’t start looking there.
The Opaqueness of Toolchains
I hold the opinion that Angular made a mistake enabling this by default deep in its CLI internals. I also feel like Autoprefixer shouldn’t even attempt prefixing grid, but that’s another holy war. But I also concede that open source is hard and you want to make users happy and it all probably seemed to be a harmless upgrade at the time.
For me this touches on the much more meta issue about opaqueness in our toolchains. Something I’ve blabbered on about before I’m sure.
As toolchains grow and become more complex, unless you are expertly familiar with them, it’s very unclear what transformations are happening in our code. Tracking the differences between the input
and output
and the processes that code underwent can be overwhelming. When there’s a problem, it’s increasingly difficult to hop into the assembly line and diagnose the issue and often there’s not an precise fix.
AI has a similar problem. Cathy O’Neil’s book Weapons of Math Destruction covers this topic in depth, but it’s increasingly important to know how AI makes its decisions for our society as it’s already being used in areas like prison sentencing, loan qualifications, investments, and many more impactful sectors of life. How do we know the machine was fair and unbiased in its conclusions? (Spoiler: It’s often not.) How do we know the machine didn’t rob people of their privacy? How can we “show the work”?
Josh Clark has a great talk called “Design in the Era of the Algorithm” where he explores these AI mishaps, but then explains how he thinks we can use design to add some transparency in how these Machine Learning algorithms get to their decision. In the same way AI needs some design to show its work in how it came to its final answer, I feel that our automated build tools could use some help as well.
I think Chris Coyier has been getting at this idea with this post on Annotated Build Processes. It’s often a lot of work to understand the puzzle of how it all fits together. Perhaps it’s a symptom of increased reliance on these tools. We don’t just write CSS anymore, we compile our Sass partials then pass that to Autoprefixer and then generate sourcemaps along the way. Same with JavaScript, it’s a multistep process as well.
For me, I found great help in tools like source-map-explorer and webpack-bundle-analyzer for examining the output of my build chain. And dashboards like Vue’s GUI are great to look at for some reporting. But the steps the CodeMod-O-Tron took to create the final product are still murky.
I sometimes wonder if Webpack or Gulp or [Insert Your Build Tool Here]
could benefit from a Scratch-like interface for buildchains.
Little visual block-based operations that take you step by step in how files of different types get processed. To me, Gulp’s .pipe()
functions already sort of look like Scratch apps.
I’m sure there would be some backlash over this childish form of programming. However, knowing how much time my team and I have spent configuring and debugging build process issues, I’m sure lots of people would be eager to take things out of the opaque black box, or the painstakingly handcrafted box, and start using a Fisher Price®-style “My First Compiler” box.