2017-09-15 2 views
1

私は角度4のプロジェクトでCSSテーマの種類を実装しようとしています。バンドルにはwebpack 3を使用します。この製品は、いくつかの企業によって使用されることを意図されており、ブランドブックに従っている必要があります。テーマが必要ですwebpackに条件付きで追加または代替のCSSファイルをロードさせます

いくつかのビルドがありますが、いくつかのバージョンのコードを持つことは望ましくありません。すべてのテーマは同じコードベースにとどまるべきです。違いは最小です:色、アイコン、フォント - すべてがCSSで変更される可能性があります。

私はいくつかの方法を考えましたが、もっとも明白なのは:ホストコンテキストのコンポーネント用に実装し、webpackの環境変数を変更してボディクラスを変更することです。このような方法では、バンドル内のすべてのテーマを把握することになります。多分別の方法がありますか?

webpackは、要求されたCSSファイルをロードできないのだろうかと思います。代わりに、別のファイルをパターンで探すことができます。存在する場合は、元のファイルの代わりにそのファイルを使用します。または、両方のファイルを読み込みます。

たとえば、button.component.tsがあり、button.component.cssをインポートしています。 webpackにテーマを使用するように指示しないと、通常通り動作します。しかし、それを行うと、button.component.theme-name.cssを同じディレクトリに読み込もうとします。そのファイルが存在する場合、webpackはデフォルトファイルを代わりに(または一緒に)インポートします。

これは基本的に私がやろうとしていることです。私は同じメカニズムが、角度のあるhtmlテンプレートに役立つと思います。

このような魔法を実行するプラグインはありますか?あるいは、いくつかの洗練されたローダーオプション?私の仕事を解決する別の方法があれば、コメントを削除してください!

答えて

1

ロードされたファイルの内容を、その名前に選択されたテーマのタイトルを持つ兄弟の内容で追加または置換できるローダーを作成しました。

TL; DR

  1. はローダーを使用してファイルを作成します。
  2. webpack設定で使用します。
  3. THEME = <themeName> evironmentでwebpackを実行します。

テーマloader.js

const fs = require('fs'); 
const loaderUtils = require('loader-utils'); 

module.exports = function (mainData) { 
    const options = loaderUtils.getOptions(this); 
    let themeName = options.theme; 
    let mode = options.mode; 

    if (themeName) { 
    // default mode 
    if (!Object.keys(transform).includes(mode)) { 
     mode = 'replace'; 
    } 

    // fileName.suffix.ext -> fileName.suffix.themeName.ext 
    const themeAssetPath = this.resourcePath.replace(/\.([^\.]*)$/, `.${themeName}.$1`); 
    const callback = this.async(); 

    // for HMR to work 
    this.addDependency(themeAssetPath); 

    fs.readFile(themeAssetPath, 'utf8', (err, themeData) => { 
     if (!err) { 
     callback(null, transform[mode](mainData, themeData)); 
     } else if (err.code === 'ENOENT') { 
     // don't worry! if it's not here then it's not needed 
     callback(null, mainData); 
     } else { 
     callback(err); 
     } 
    }); 
    } else { 
    return mainData; 
    } 
}; 

const transform = { 
    // concat theme file with main file 
    concat: (mainData, themeData) => mainData + '\n' + themeData, 
    // replace main file with theme file 
    replace: (mainData, themeData) => themeData 
}; 

この手作りローダ使用する試料片webpack.config.jsたとえば

resolveLoader: { 
    modules: [ 
    paths.libs, // ./node_modules 
    paths.config // this is where our custom loader sits 
    ] 
}, 

module: { 
    rules: [ 
    // component styles 
    { 
     test: /\.css$/, 
     include: path.join(paths.src, 'app'), 
     use: [ 
     'raw-loader', 
     // search for a themed one and append it to main file if found 
     { 
      loader: 'theme-loader', 
      options: { 
      theme: process.env.THEME, 
      mode: 'concat' 
      } 
     } 
     ] 
    }, 

    // angular templates — search for a themed one and use it if found 
    { 
     test: /\.html$/, 
     use: ['raw-loader', 
     { 
      loader: 'theme-loader', 
      options: { 
      theme: process.env.THEME, 
      mode: 'replace' 
      } 
     } 
     ] 
    } 
    ] 
} 

app.component.css

:host { 
    background: #f0f0f0; 
    color: #333333; 

    padding: 1rem 2rem; 

    display: flex; 
    flex-direction: column; 
    flex: 1; 
    justify-content: center; 
} 

nav { 
    /* ... */ 
    /* something about nav element */ 
    /* ... */ 
} 

header { 
    /* ... */ 
    /* pile of styles for header */ 
    /* ... */ 
} 

フレックスとパッディングのスタッフをすべて変更する必要はなく、navとヘッダーに独自の背景とフォントの色設定がない場合もあります。つまり、ホスト要素のスタイルをオーバーライドするだけです。暗いに設定した環境変数をテーマにした

:host { 
    background: #222222; 
    color: #e0e0e0; 
} 

我々の実行のWebPACK:私たちはapp.component.dark.cssを作成します。ローダーが処理する要求を受け取りましたapp.component.cssapp.component.dark.cssおよびvoilaをロードしようとしています。テーマのCSSは結果ファイルの末尾に追加されます。競合する複数のセレクタが同じ重要性と特異性を持っている場合、そのためカスケードの、

は、...後でルールは以前のルール(MDN)に勝つだろう。

HTMLの場合、このような方法はありません。だから我々は完全にテンプレートを書き直さなければならないでしょう。うまくいけば、それほど頻繁に行う必要はありません。私のケースでは、cutomerのブランド要求に合わせてヘッダーやフッターのように変更したいと思っていました。

これは初めてのWebpackローダーの作成でした。問題がある場合はコメントを残してください。

+0

アセットを交換して助けてくれました。ローダーがデフォルトローダーで動作するようにローダーを無効にする必要がありました。 (行末問題) – feskr

関連する問題