Webpack實戰(五):輕鬆讀懂Webpack如何分離樣式文件

在上一篇文章中我給大家分享了預處理器(loader),裏面講到了style-loader 和css-loader,有關樣式引入的問題,但是上面的樣式文件只是引入到style標籤裏面,並不是我想要的樣式文件獨立分離。

如果想了解有關css-loader和style-loader可以參考以下地址:

Webpack實戰(四):教教你如何輕鬆搞定-預處理器(loader)

通過js引入樣式文件只是把樣式添加到style標籤內,而不是引入一個獨立的css文件,一般來說,在生產環境下,我們希望樣式存在於CSS文件中而不是style標籤中,因爲文件更有利於客戶端進行緩存。

Webpack社區有專門的插件:extract-text-webpack-plugin(適用於Webpack 4之前版本)和mini-css-extract-plugin(適用於Webpack 4及以上版本),它們就是專門用於提取樣式到CSS文件的。

  1. extract-text-webpack-plugin
    extract-text-webpack-plugin安裝命令代碼如下:
# for webpack 3 
npm install --save-dev extract-text-webpack-plugin
# for webpack 2 
npm install --save-dev extract-text-webpack-plugin@2.1.2
# for webpack 1 
npm install --save-dev extract-text-webpack-plugin@1.0.1

由於webpack版本不一樣,extract-text-webpack-plugin安裝的出來版本的也不一樣。

配置代碼如下:

const ExtractTextPlugin = require("extract-text-webpack-plugin");
 const path = require('path')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.js'
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.css$/i,
       use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        }),
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  },
  plugins: [
    new ExtractTextPlugin("styles.css") //提取後css文件名稱
  ]
}

在module.rules中我們設置了處理CSS文件和js文件的規則,其中css配置的use字段並沒有直接傳入loader,而是使用了插件的extract方法包了一層。內部的fallback屬性用於指定當插件無法提取樣式時所採用的loader,use(extract方法裏面的)用於指定在提取樣式之前採用哪些loader來預先進行處理。除此之外,還要在Webpack的plugins配置中添加該插件,並傳入提取後的資源文件名。
由於我電腦項目裏裝的4.0以上的webpack版本,這裏不再做打包測試。
樣式的提取是以資源入口開始的整個chunk爲單位的。比如我們的應用從index.js開始引入了幾百個模塊,這些模塊都引入了它們各自的樣式文件,但是最終生成的c s s文件只有一個,因爲它們都來自同一個入口模塊。上面我們講styles.css作爲文件名傳給extract-text-webpack-plugin,但是當項目有多個入口的時候就會發生重名問題。就像我們前面動態配置的output.filename一樣。這裏我們也將要對插件提取的css文件使用類似模版的命名方式。

下面是入口的index.js和about.js

// index.js
import './index.css'

// about.js
import './about.css'

we bpack.config.js配置部分代碼如下

const ExtractTextPlugin = require("extract-text-webpack-plugin");
 const path = require('path')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js',
    about: './about.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.css$/i,
       use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        }),
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  },
  plugins: [
    new ExtractTextPlugin("[name].css") //提取後css文件名稱
  ]
}

我們使用[name].css來動態生成c s s文件名,name爲即entry中我們爲每一個入口分配的名字(index、about),由此可以推出[name]指的是chunk(chunk是對一組有依賴關係的模塊的封裝)的名字。

  1. mini-css-extract-plugin
    mini-css-extract-plugin 是 extract-text-webpack-plugin的升級版本,它擁有更多的特性和更好的性能。最突出的一條就是 mini-css-extract-plugin支持按需加載css,舉個例子,a.js通過import()函數異步加載了b.js,b.js裏面加載了style.css,那麼style.css最終只能被同步加載(通過HTML的link標籤)。但是現在mini-css-extract-plugin會單獨打包出一個0.css(假設使用默認配置),這個CSS文件將由a.js通過動態插入link標籤的方式加載。
    首先安裝mini-css-extract-plugin
npm install --save-dev mini-css-extract-plugin

下面是入口的index.js和index2.js

// index.js
import './common.css'

// index2.js
import './style.css'

web pack.config.js配置如下:

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  context: path.join(__dirname, './src'),
  entry: {
    index: './index.js',
    index2: './index2.js'
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [{
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: '../'
          },
        }, 'css-loader'],
        exclude: /node_modules/
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            presets: [
              [
                'env', {
                  modules: false
                }
              ]
            ]
          }
        }
      }
    ],
  },
  plugins: [new MiniCssExtractPlugin({
    filename: '[name].css',
    chunkFilename: '[id].css'
  })],
}

打包效果如下:
在這裏插入圖片描述
可以發現最後輸出兩個c s s文件名分別爲chunk 名,index.css,index2.css

在配置上mini-css-extract-plugin與extract-text-webpack-plugin有以下幾點不同

  • loader規則設置的形式不同,並且mini-css-extract-plugin支持配置publicPath,用來指定異步CSS的加載路徑。
  • 不需要設置fallback。
  • 在plugins設置中,除了指定同步加載的CSS資源名(filename),還要指定異步加載的CSS資源名(chunkFilename)。

總結

Webpack樣式文件分離,主要用兩個插件mini-css-extract-plugin與extract-text-webpack-plugin,它們有着各自的特點,但是如果webpack版本4.0以上建議用mini-css-extract-plugin,它擁有更多的特性,特別是按需加載cs s,解決了一些性能問題。

如果想了解更多,請掃描二維碼:
在這裏插入圖片描述

發佈了255 篇原創文章 · 獲贊 162 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章