2017-09-15 49 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中運行webpack = <themeName> evironment。

主題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 */ 
    /* ... */ 
} 

要實現深色主題,我們不需要更改所有flex和填充工作人員,也許nav和header沒有自己的背景和字體顏色設置。所以我們只需要重寫主機元素樣式。我們創建app.component.dark.css

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

的,我們設定爲黑暗的環境變量主題的WebPack運行。加載程序需要處理app.component.css,試圖加載app.component.dark.css並且瞧!主題的css被附加到結果文件的末尾。由於級聯的,

如果多用戶競爭選擇具有相同的重要性和特殊性,...後面的規則將贏得比早期規則(MDN)。

對於HTML我們沒有這樣的方法。所以我們必須完全重寫我們的模板。希望你不需要經常這樣做。我的情況是,我想要改變頁眉和頁腳以適應客戶的品牌需求。

這是我第一次嘗試創建一個webpack loader,如果您發現問題,請留下評論。

+0

幫我更換資產很多。必須禁用raw-loader才能使用默認加載器。 (行結束問題) – feskr

相關問題