Inline CSS for an Ember App

Hey!

I’m trying to figure out what is the best way to inline css into index.html for the critical css or app-shell-css. For our app I want all the CSS which belongs to our loading-screen/splash-screen to be inlined into index.html. The problem is that this CSS is quite complex (some animations etc) and is built by ember-cli-sass.

What I did is, to create an in-repo-addon which implements the postBuild hook. In this hook the result of the sass compilation is injected into the index.html. Since I’m not a total expert in Broccoli/Ember-CLI I’m not sure if this is the best way to implement this. It works but I’m not sure if I miss something (caching, performance wise).

In code this looks as follows

The addons index.js

var fs = require('fs');    
module.exports = {
    name: 'inject-inline-css',

    isDevelopingAddon: function () {
        return true;
    },

    postBuild: function (result) {
        debugger;
        var index = fs.readFileSync(result.directory + '/index.html', 'utf-8');
        var inline = fs.readFileSync(result.directory + '/inline.css', 'utf-8');
        var combined = '';
        if (index.indexOf('{{inline-css}}') !== -1) {
            combined = index.replace('{{inline-css}}', '<style id="rml-inline-styles">' + inline + '</style>');
        }
        if (index.indexOf('<style id="rml-inline-styles">') !== -1) {
            combined = index.replace(/<style id="rml-inline-styles">[\s\S]*<\/style>/, '<style id="rml-inline-styles">' + inline + '</style>');
        }
        fs.writeFileSync(result.directory + '/index.html', combined);
    }
};

ember-cli-build.js:

var app = new EmberApp(defaults, {
    fingerprint: {
        exclude: ['inline.css']
    },
    outputPaths: {
        app: {
            css: {
               inline: 'inline.css'
            }
        }
    }
});

To me this feels a little bit hackish. What would be a good approach?

Hi I’m also very interested in finding a good solution for ember-cli.

GitHub - gpoitch/ember-cli-inline-content: An ember-cli add-on to render inline scripts, styles, or any content directly into your index.html file seems like a good approach but unfortunately it doesn’t yet work with built assets: How to reference built assets? · Issue #14 · gpoitch/ember-cli-inline-content · GitHub.

@oskar if I know if my approach is fine, I could try to create a pull-request for ember-cli-inline-content. But I don’t want to bring my code into ember-cli-inline-content if it is just a hack :wink:

@gdub: what do you think?

Any one has an opinion? As I said, if somebody is interested I could try to create a pull request

I’m also very interested in this kind of functionality. What’s the best approach right now?

I decided to just use gulp+critical directly and use an npm script to run it after build.

@oskar that’s a nice idea :slight_smile: but I don’t want to introduce another build tool beside ember-cli/broccoli. Not sure, but maybe I’ll develop a “generic” solution of my hack :laughing:

Here’s another solution without gulp.

  1. Run yarn add critical --dev
  2. Add an npm script to run critical and make sure it runs AFTER building:
"scripts": {
  "build": "ember build; npm run critical-css",
  "critical-css": "cat dist/index.html | critical --base dist/ --inline --minify > index.tmp && mv index.tmp dist/index.html"
}

I’ve made an addon for this which uses a post-build hook to run Critical, making it usable with ember-cli-deploy. GitHub - ivanvanderbyl/ember-cli-critical: Ember CLI addon which wraps Critical, to extract & inline critical-path (above-the-fold) CSS from HTML

Very cool @ivanvanderbyl!

in the past few months I’ve also built a CSS inlining addon: GitHub - 201-created/ember-inline-css: An Ember/Glimmer addon for inlining app CSS although it is fairly naive and has no knowledge of above/below the fold. Merely inlines CSS and lets you choose which files you want included in HTML.