Railsとウェブパッカーによる重要なCSS


これはWebPackerにすべての資産を移動するときにうまく利用できる新しい高度な使用法に関する記事のシリーズの最初のです.最初の部分では、CSSサイズを最適化します.
我々はすべて高速&信頼性のWebページをしたい.Aを行うときPage Speed Audit 何が頻繁に推奨として出てくる重要なCSSです.重要なCSSと特に上の重要なCSSの上に、あなたのページ(折り目より上に)のトップを与えるために必要とされる最小限のCSS(インラインで)をインライン化する能力は、あります.私はいくつかの時間のレールのアプリでこれを達成するために簡単なソリューションに見えたが、私はそれで実際に成功したことはなかった.
WebPack(IE WebPacker Rails)での素晴らしいことの一つは、それの周りのすべてのエコーシステムです.RailsのJS側はほとんど文書化されていますが、CSS & Imageにも利用可能なツールがたくさんあります.
数ヶ月前に私は素晴らしいビデオを発見GoRails 使用するPurgeCss in a Rails application .

purgecssを理解する



Purgecssの世界的な概念は、あなたが通常使用されるいくつかのCSSクラスを持っているあなたのファイルのすべてでpurgecssを供給するということです.html , html.erb , .js ). purgescss CSSセレクタである可能性のあるすべてのトークンのリストを作成します.
一方で、WebPackerはCSSバンドルを作成しますmini-css-extract-plugin . Purgecssはトークンのリストを抽出する
結果はトークンの2つのリストの交差点です.

複数のパックを複数のルール


WebPackerでは、複数のパックを持って簡単です.あなただけの新しい作成する必要がありますsome-pack.js ファイルapp/javascript/packs ディレクトリ.
我々がしようとしていることの世界的な考えは、
  • セカンドパックcritical.js それにいくつかのCSSのインポートだけで.
  • 私たちのpurgescssプロセスを分割するために、より厳格なルールを適用するcritical.css .
  • インラインで私たちの重要なCSSをインラインでDev.to .
  • 怠惰な負荷application.css .
  • 我々の重要。ジェイトリーエントポイント


    アプリケーションを与えられます.以下のように見えます.
    // app/javascript/packs/application.js
    
    require("@rails/ujs").start();
    require("local-time").start();
    require("turbolinks").start();
    
    window.Rails = Rails;
    
    // import CSS
    import "stylesheets/application.scss";
    
    // import Stimulus controllers
    import "controllers/index";
    
    // import vendor JS
    import "bootstrap";
    
    私たちの主なエントリポイントは、当社のメインアプリケーションをインポートします.通常、そのように見えるSCSS
    // app/javascript/stylesheets/application.scss
    
    // Fonts
    @import "config/fonts";
    
    // Graphical variables
    @import "config/colors";
    
    // Vendor
    @import "~bootstrap/scss/functions";
    @import "config/bootstrap_variables";
    @import "~bootstrap/scss/bootstrap";
    
    $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
    @import "~@fortawesome/fontawesome-free/scss/fontawesome";
    @import "~@fortawesome/fontawesome-free/scss/brands";
    
    // Components
    @import "components/index";
    
    // layouts
    @import "layouts/sticky-footer";
    
    我々は非常に基本を作成することができますcritical.js , 唯一のことは、新しい重要なをインポートすることです.SCSSスタイルシート.
    // app/javascript/packs/critical.js
    import "stylesheets/critical.scss";
    
    我々の中でcritical.scss Purgecssがより良い仕事をするのを助けるために我々が中に入れたものとして、我々はもう少し選択的になり始めることができます.(少し違いがある)
    // colors
    @import "config/colors";
    
    // vendor
    @import "~bootstrap/scss/functions";
    @import "config/bootstrap_variables";
    @import "config/bootstrap_critical"; // pick only the Bootstrap module you need
    
    // Components
    @import "components/banner"; //just pick the components you need for the homepage
    

    Postcss / purgecss設定


    これは重要な部分です.purgecssにファイルごとに異なる規則を適用するよう指示しなければなりません.幸いにも、私たちはPostcssの情報の完全な文脈を持っています.
    それで、我々は情報文脈を環境に渡すことができます:
    module.exports = ctx => environment(ctx);
    
    文脈変数を我々の環境に加えてください
    const environment = ctx => ({
      plugins: [
        require("postcss-import"),
        require("postcss-flexbugs-fixes"),
        require("postcss-preset-env")({
          autoprefixer: {
            flexbox: "no-2009"
          },
          stage: 3
        }),
        purgeCss(ctx)
      ]
    });
    
    このコンテキストでPurgecssプラグインを呼び出します
    const purgeCss = ({ file }) => {
      return require("@fullhuman/postcss-purgecss")({
        content: htmlFilePatterns(file.basename),
        defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
      });
    };
    
    そして、私たちはpurgecssのファイル名を持っているので、それぞれのファイルに異なる規則を指定できます.私の重要なCSSのために、私はホームページと他のすべてのファイルの通常のセットに関連したページだけを指定します.
    const htmlFilePatterns = filename => {
      switch (filename) {
        case "critical.scss":
          return [
            "./app/views/pages/index.html.erb",
            "./app/views/shared/_navbar.html.erb",
            "./app/views/layouts/application.html.erb"
          ];
        default:
          return [
            "./app/**/*.html.erb",
            "./config/initializers/simple_form_bootstrap.rb",
            "./app/helpers/**/*.rb",
            "./app/javascript/**/*.js"
          ];
      }
    };
    
    それで、完全に、それはそれのように見えます
    // postcss.config.js
    
    const environment = ctx => ({
      plugins: [
        require("postcss-import"),
        require("postcss-flexbugs-fixes"),
        require("postcss-preset-env")({
          autoprefixer: {
            flexbox: "no-2009"
          },
          stage: 3
        }),
        purgeCss(ctx)
      ]
    });
    
    const purgeCss = ({ file }) => {
      return require("@fullhuman/postcss-purgecss")({
        content: htmlFilePatterns(file.basename),
        defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
      });
    };
    
    const htmlFilePatterns = filename => {
      switch (filename) {
        case "critical.scss":
          return [
            "./app/views/pages/index.html.erb",
            "./app/views/shared/_navbar.html.erb",
            "./app/views/layouts/application.html.erb"
          ];
        default:
          return [
            "./app/**/*.html.erb",
            "./config/initializers/simple_form_bootstrap.rb",
            "./app/helpers/**/*.rb",
            "./app/javascript/**/*.js"
          ];
      }
    };
    
    module.exports = ctx => environment(ctx);
    

    結果


    私がした小さなテストで、私はそれらの結果を持ちました
  • 32 KBの初期バンドルサイズ
  • パージCSSで9 KB
  • 私の批判.CSSのみ3 KB!
  • バンMM🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉

    からのインラインCSS


    私は私の頭を少しスクラッチしてHTMLで私のCSSファイルをインラインにしました.ありがとうStackoverflow 私はここでいくつかの助けを得る
    <% if current_page?(root_path) %>
      <!-- Inline the critical CSS -->
      <style>
        <%= File.read(File.join(Rails.root, 'public', Webpacker.manifest.lookup('critical.css'))).html_safe %>
      </style>
    
      <!-- Lazy load the rest with loadCSS -->
      <link rel="preload" href="<%= Webpacker.manifest.lookup('application.css') %>" as="style" onload="this.rel='stylesheet'">
      <noscript><link rel="stylesheet" href="<%= Webpacker.manifest.lookup('application.css') %>"></noscript>
    <% else %>
      <%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <% end %>
    

    ET voila !!


    デモ:https://sprockets-less-rails6.herokuapp.com
    ソースコード:https://github.com/adrienpoly/sprockets-less-rails6