Inline CSS for an Ember App


#1

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?


#2

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

https://github.com/gdub22/ember-cli-inline-content seems like a good approach but unfortunately it doesn’t yet work with built assets: https://github.com/gdub22/ember-cli-inline-content/issues/14.


#3

@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?


#4

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


#5

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


#6

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


#7

@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:


#8

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"
}

#9

I’ve made an addon for this which uses a post-build hook to run Critical, making it usable with ember-cli-deploy. https://github.com/ivanvanderbyl/ember-cli-critical


#10

Very cool @ivanvanderbyl!

in the past few months I’ve also built a CSS inlining addon: https://github.com/201-created/ember-inline-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.