「使用 webpack 5 從0到1搭建React + TypeScript 專案環境」2. 整合 css、less 與 sass

2022-01-12 17:00:01

「使用 webpack 5 從0到1搭建React + TypeScript 專案環境」2. 整合 css、less 與 sass

上篇文章帶大家使用 webpack 5整合 ReactTypeScript,同時為了提高我們的程式碼品質,我們會在構建中新增型別檢查程式碼規範校驗。這次我們在上篇的基礎上介紹如何整合 csslesssass

1. 設定 css

1.1 開發環境

為了在 JavaScript 模組中import 一個 CSS 檔案,你需要安裝 style-loadercss-loader,並在 module 設定 中新增這些 loader

我們需要安裝css-loaderstyle-loader

yarn add css-loader style-loader -D

修改組態檔:

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

這樣設定後,當 webpack 再遇到.css檔案時,它將使用css-loaderstyle-loader進行處理(use 陣列中的載入器從後向前執行)。

  • css-loaderimport 語句(在我們的範例中為app.css)中讀取參照的 CSS 檔案並解析成 JavaScript 程式碼。
  • style-loaderJavaScript 程式碼中的 CSSstyle 標籤的形式插入到 html 檔案中。

接下來再通過yarn start開啟即可看到我們引入外部.css檔案生效。

1.2 生產環境

在生產環境下,我們需要進行壓縮CSS,以便在生產環境中節省載入時間,同時還可以將CSS檔案抽離成一個單獨的檔案。實現這個功能,需要 mini-css-extract-plugin 這個外掛來幫忙。安裝外掛:

yarn add mini-css-extract-plugin -D

本外掛會將 CSS 提取到單獨的檔案中,為每個包含 CSSJS檔案建立一個 CSS檔案,並且支援 CSSSourceMaps 的按需載入。

本外掛基於 webpack 5 的新特性構建,並且需要webpack 5才能正常工作。

之後將loaderplugin 新增到你的 webpack 組態檔中。

webpack.config.pred.js中做如下新增如下設定:

const miniCssExtractPlugin = require('mini-css-extract-plugin');
// ...
module.exports = {
  // ....
  module: {
    rules: [
      // ...
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ]
  },
  plugins: [
    // ...
    new MiniCssExtractPlugin({
      filename: 'styles/[name].[contenthash].css'
    }),
  ],
  mode: 'production',

}

接下來再通過yarn build打包即可看到我們的輸出目錄多了一個styles資料夾,裡面是我們抽離出來的CSS檔案,但我們卻看到CSS檔案並沒有被壓縮,為了壓縮輸出的CSS檔案,我們需要css-minimizer-webpack-plugin這個外掛來幫忙。安裝外掛:

yarn add css-minimizer-webpack-plugin -D

webpack.config.pred.js中做如下新增如下設定:

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
// ...
module.exports = {
  // ....
  // 優化設定 
  optimization: { 
    minimizer: [
      new CssMinimizerPlugin(), 
    ], 
  },
}

接下來再通過yarn build打包即可看到我們的輸出styles檔案裡面的CSS檔案已經被壓縮了。

2. 使用 CSS modules

當開發人員命名的類有衝突時,後面的樣式會覆蓋前面的樣式。

那麼該如何解決呢?當然你可以選擇命名的時候避免衝突,還有一種方法便是使用 CSS modules,這裡便不再詳細介紹它了,只講如何設定環境。

首先,我們需要先改變參照的方式:

src/index.module.css

.h1 {
  background-color: red;
}

scr/index.tsx

import React from "react";
import ReactDOM from "react-dom";
import index from './index.module.css'

const App = () => (
  <h1 className={index.h1}>Hello World!</h1>
)

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

可以看到 import 語句跟原來的略有不同。 我們通過參照.module.css字尾的檔案,並從中匯入為一個變數

這個變數是一個物件,包含了對應樣式檔案的所有CSS類名稱, 然後在元件中參照對應的類名變數。我們還需要將index.css重新命名為index.module.css

但是TypeScript 編譯出現錯誤 「無法找到模組’.module.css’或對應的型別宣告」錯誤,因為 TS 無法解析CSS modules

image-20220111103325728

為了解決這個錯誤,我們需要建立一個src/typings.d.ts型別宣告檔案並加入以下內容:

declare module "*.module.css";

之後重新啟動應用,再次檢視介面效果,就可以看見正常了:

image-20220111103510030

image-20220111103635084

我們看到 CSS類名稱被賦予了一個看起來很隨機的名稱。 因為這樣可以確保不同元件中的樣式名稱不會衝突。

通過上述方法,每次都需要通過 *.module.css的方式實現 CSS modules 不免有些麻煩。其實,我們可以通過修改 Webpack 設定簡化 CSS modules 的寫法。

webpack.config.dev.js中我們做如下修改:

module: {
  rules: [
    ...,
    {
      test: /\.css$/i,
      use: ["style-loader", {
        loader: "css-loader",
        options: {
          modules: true,
        },
      }],
    },
  ],
},

webpack.config.prod.js中我們做如下修改:

module: {
  rules: [
    ...,
    {
      test: /\.css$/i,
      use: [MiniCssExtractPlugin.loader, {
        loader: "css-loader",
        options: {
          modules: true,
        },
      }],
    },
  ],
},

修改typings.d.ts 的設定:

declare module "*.css";

這樣,我們就可以以如下方式進行使用了:

import React from "react";
import ReactDOM from "react-dom";
import index from './index.css'

const App = () => (
  <h1 className={index.h1}>Hello World!</h1>
)

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

3. 設定 Less

如果你想在專案中使用less,那麼我們就需要less-loader這個工具。

首先,我們先安裝一下:

yarn add less less-loader -D

webpack.config.dev.js中我們做如下修改:

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

webpack.config.prod.js中我們做如下修改:

module: {
  rules: [
    ...,
    {
      test: /\.less$/i,
      use: [MiniCssExtractPlugin.loader, {
        loader: "css-loader",
        options: {
          modules: true,
        },
      }, 'less-loader'],
    },
  ],
},

同時,為了配合 CSS modules,我們需要在typings.d.ts 中加入以下內容,否則 Typescript無法識別 Less 型別:

declare module "*.less";

如此,我們就可以在專案中使用Less了。

4. 設定 Sass

接下來我們看看如何設定 Sass,其實與 Less 的設定方式是類似的。

如果你想在專案中使用Sass,那麼我們就需要sass-loader這個工具。

首先,我們先安裝一下:

yarn add sass sass-loader -D

webpack.config.dev.js中我們做如下修改:

module: {
  rules: [
    ...,
    {
      test: /\.s[ac]ss$/i,
      use: ["style-loader", {
        loader: "css-loader",
        options: {
          modules: true,
        },
      }, 'sass-loader'],
    },
  ],
},

webpack.config.prod.js中我們做如下修改:

module: {
  rules: [
    ...,
    {
      test: /\.s[ac]ss$/i,
      use: [MiniCssExtractPlugin.loader, {
        loader: "css-loader",
        options: {
          modules: true,
        },
      }, 'sass-loader'],
    },
  ],
},

同時,為了配合 CSS modules,我們需要在typings.d.ts 中加入以下內容,否則 Typescript無法識別 sassscss 型別:

declare module "*.sass";
declare module "*.scss";

如此,我們就可以在專案中使用Sass了。

這樣以來,我們的專案環境就整合 csslesssass,同時還支援css module