【webpack】-- 樣式加載

加載css須要用到css-loader和style-loader css-loader將@import 和 url 處理成正規的ES6 import ,若是@import指向的是一個外部資源,css-loader會跳過,而只會對內部資源作處理。css-loader處理以後,style-loader會將輸出的css注入到打包文件中。css默認是inline模式,且實現了HMR接口。但inline不太適用於生產環境(所有輸出在頁面上)。還須要用extracttextplugin生成一個單獨的css文件,但先一步一步來。

一,樣式打包

1.安裝css-loader,style-loader

npm install css-loader style-loader --save-dev

2.修改webpack.config.js

增長一個一級子節點
  module:{
       rules:[{
       test:/\.css$/,
       use: ['style-loader', 'css-loader'],
     }]
    },
test的正則會匹配.css的文件。use中的執行順序是從右到左。loader的執行是連續的,就像管道同樣,先到css-loader再到style-loader。loaders: ['style-loader', 'css-loader'] 能夠理解爲:styleloader(cssloader(input)) 。

3.添加樣式

app/mian.css
body {
  background: cornsilk;
}

而後在index.js中引入css

import './main.css';

再運行npm start,在http://localhost:8080/中打開html

這時候頁面出現了背景色,並且發現樣式寫入了header中,這個時候你改變顏色,界面也會無刷新的更新,這正是上一節HMR的效果。webpack

樣式也是經過webpackHotUpdate方法進行更新。git

2、加載less

再看一下如何加載less,先安裝less-loadergithub

npm install less less-loader --save-dev

再修改配置文件:web

   module:{
       rules:[{
          test: /\.less$/,
       use: ['style-loader', 'css-loader', 'less-loader'],     
        }]
    },

而後創建一個less文件。less.lessnpm

@base: #f938ab;

.box-shadow(@style, @c) when (iscolor(@c)) {
  -webkit-box-shadow: @style @c;
  box-shadow:         @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box {
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }
}

body {
  background: cornsilk;
}

修改index.jsapp

 import  './less.less';
 import component from './component';

var ele=document.createElement("div");
ele.innerHTML="this is an box";
ele.className="box";
document.body.appendChild(ele);

let demoComponent=component();
document.body.appendChild(demoComponent);

獲得效果:less

能夠看見編譯成功,要注意的是,再使用less的時候import只能是less文件,這個時候再import main.css會報錯。這一節對less就作一個簡單的演示,其餘樣式預處理器同理,下面的內容仍是繼續基於css。ide

3、理解css做用域和css 模塊

 通常來講css的做用域都是全局的,咱們常在母版頁裏面添加了多個樣式文件,後面的樣式文件會覆蓋前面的樣式文件,經常給咱們的調試帶來麻煩。而CSS Modules經過import引入了本地做用域。這樣可以避免命名空間衝突。webpack的css-loader是支持CSS Modules的,怎麼理解呢,先看幾個例子。咱們先在配置中開啓(先關掉HMR):

    module:{
       rules:[{
        test:/\.css$/,
        use: ['style-loader', {
        loader: 'css-loader',
          options: {
          modules: true,//讓css-loader支持Css Modules。
        },
        },],

而後定義一個新的樣式(main.css):

body {
  background: cornsilk;
}
.redButton {
  background: red;color:yellow;
}

給component加一個樣式,先引入main.css。

import styles from './main.css';
export default function () {
  var element = document.createElement('h1');
      element.className=styles.redButton;
     element.innerHTML = 'Hello webpack';
  return element;
}

這個時候咱們看到界面已經變化了。

 再看右邊生成的樣式,咱們的樣式名稱已經發生了改變。回顧整個過程至關於main.css中的每個類名成了一個模塊,在js中能夠像獲取模塊同樣的獲取。可是你可能想,爲毛我不能直接給元素賦值,幹嗎要import呢。這是個好問題,咱們再新增一個樣式

不一樣樣式文件的同名類

other.css

.redButton {
  background:rebeccapurple;color:snow;
}

它也有一個.redbutton的類(但效果是紫色的),而後在index.js中建立一個div元素並給它添加redbutton樣式。

import './main.css';
import styles from './other.css';
import component from './component';

var ele=document.createElement("div");
ele.innerHTML="this is an other button";
ele.className=styles.redButton;
document.body.appendChild(ele);

let demoComponent=component();
document.body.appendChild(demoComponent);

再看效果

上面這個圖說明了兩問題,一個是咱們在index.js中引入了2個樣式文件,在index頁面就輸出了兩個style,這讓人有點不爽,但咱們後面再解決。另一個就是雖然兩個樣式文件中都有redButton這個類,可是這二者仍是保持獨立的。這樣就避免了命名空間的相互干擾。若是你這個時候直接賦值

element.className="redButton";

這樣是獲取不到樣式的。直接對元素的樣式默認是全局的。

全局樣式

若是想讓某個樣式是全局的。能夠經過:global來包住。

other.css

:global(.redButton) {
  background:rebeccapurple;color:snow;
  border: 1px solid red;
}

main.css

:global(.redButton) {
  background: red;color:yellow;
}

這個時候redbutton這兩個樣式就會合並。須要直接經過樣式名來獲取。

 element.className="redButton";

組合樣式

咱們再修改other.css,建立一個shadowButton 樣式,內部經過composes組合redbutton類。

.redButton {
  background:rebeccapurple;color:snow;
  border: 1px solid red;
}
 
.shadowButton{
    composes:redButton;
    box-shadow: 0 0 15px black;
}

修改index.js:

var ele=document.createElement("div");
ele.innerHTML="this is an shadowButton button";
console.log(styles);
ele.className=styles.shadowButton;
document.body.appendChild(ele);

看一下是什麼效果:

日誌打印出來的是styles對象,它包含了兩個類名。能夠看見shadowButton是由兩個類名組合而成的。div的class和下面的對應。

 4、輸出樣式文件

css嵌在頁面裏面不是咱們想要的,咱們但願可以分離,公共的部分可以分開。extracttextplugin 能夠將多個css合成一個文件,可是它不支持HMR(直接註釋掉hotOnly:true)。用在生產環境挺好的
npm install extract-text-webpack-plugin --save-dev

先安裝extracttextplugin這個插件,而後再webpack.config.js中進行配置:

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractTxtplugin = new ExtractTextPlugin({
    filename: '[name].[contenthash:8].css',
});

const commonConfig={
 entry: {
    app: PATHS.app,
  },
  output: {
    path: PATHS.build,
    filename: '[name].js',
  },
   module:{
       rules:[{
           test:/\.css$/,
            use:extractTxtplugin.extract({
            use:'css-loader',
            fallback: 'style-loader',
          })
     }]},
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Webpack demo',
    }),
    extractTxtplugin
  ],
}

一開始看到這個配置,讓人有點懵。首先看fileName,表示最後輸出的文件按照這個格式'[name].[contenthash:8].css',name默認是對應的文件夾名稱(這裏是app),contenthash會返回特定內容的hash值,而:8表示取前8位。固然你也能夠按照其餘的格式寫,好比直接命名:

new ExtractTextPlugin('style.css')

而ExtractTextPlugin.extract自己是一個loader。fallback:'style-loader'的意思但有css沒有被提取(外部的css)的時候就用style-loader來處理。注意到如今咱們的index.js以下:

import  './main.css';
import styles from './other.css';
import component from './component';

var ele=document.createElement("div");
ele.innerHTML="this is an box";
ele.className=styles.shadowButton;
document.body.appendChild(ele);

let demoComponent=component();
document.body.appendChild(demoComponent);

//HMR 接口
if(module.hot){
    module.hot.accept('./component',()=>{
        const nextComponent=component();
        document.body.replaceChild(nextComponent,demoComponent);
        demoComponent=nextComponent;
    })
}
View Code

引入了兩個css文件。

這個時候咱們執行 npm run build

再看文件夾獲得一個樣式文件。(若是不想看到日誌能夠直接npm build)

 

可是咱們在第三部分使用了CSS Modules,發現other.css的樣式沒有打包進來。因此,咱們的webpack.config.js還要修改:

   module:{
       rules:[{
           test:/\.css$/,
           use:extractTxtplugin.extract({
            use:[ {
            loader: 'css-loader', options: { modules: true,
        },
        }],
            fallback: 'style-loader',
          })
     }]},

再次build。

 

 發現兩個樣式打包成了一個文件。只要內容發生了變化,樣式的名稱就會變化。更多配置能夠移步https://www.npmjs.com/package/extract-text-webpack-plugin

 
 小結:這一篇講的內容有點多了,從基本的樣式打包,到less,而後認識CSS Modules。最後打包輸出整個文件。能夠說對於新手仍是有點複雜,工具帶來了便利性,天然也帶來了學習的成本。諸多選擇和諸多配置的最後,咱們要找到一個適合咱們本身的配置,並瞭解各個模塊的機制才能面對不一樣需求的不一樣搭配。

 參考:

 https://www.npmjs.com/package/css-loader#local-scope

 https://survivejs.com/webpack/styling/loading/

 https://survivejs.com/webpack/styling/separating-css/
 系列:
相關文章
相關標籤/搜索