iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 5
7
Modern Web

在 React 生態圈內打滾的一年 feat. TypeScript系列 第 5

Day04 | SCSS 加上 Webpack 混搭款,讓你寫 CSS 上天堂

前言

SCSS 是 CSS 的預處理器,就是替原本的 CSS 再加上一些強大的語法,讓我們在寫 CSS 的時候可以更加直觀,相關說明可以查閱 官方文檔 ,本篇就不多說了,重點說明該怎麼在 React 專案中玩轉 SCSS。


前置準備

  1. 文中的專案會以前一天的專案架構繼續講解,如果未跟到前一天的進度,可以從 GitHub 上 Clone 下來。
  2. 一顆擁有學習熱忱的心。

使用方法

使用 SCSS 並不需要特別安裝什麼套件才能使用,但是記得昨天提到的,瀏覽器看不懂 JSX,所以我們需要用 Babel 編譯成 JS, SCSS 也不例外,因此下方實作的重點會在編譯 SCSS。


編譯 SCSS

這個部分先試著將 SCSS 編譯成 CSS,因此要下載編譯的套件:

npm install node-sass

哦對啦,這邊其實我沒有打錯,真的是 node-sass 沒有錯,雖然我們要使用的是 SCSS,但它們就是一家親。

下載完後,到專案中的 src 目錄下建立一個 index.scss 的檔案,且在裡面輸入以下內容:

.main {
    color: #aaf;

    .point {
        color: #faf;
    }
}

上方是 SCSS 特有的巢狀語法,接著到 package.json 中的 script,加上下方的新指令:

{
  /* 其他省略 */
  "scripts": {
    "build-css": "node-sass src/index.scss src/index.css",
  },
  /* 其他省略 */
}

儲存完後用 npm run 執行它:

npm run build-css

執行成功會在 src 的目錄下多一個 index.css:

index.css 的內容正是由 SCSS 編譯成的:

但是這麼做太麻煩了,等於 JS 的編譯和 CSS 的編譯分開,每次發行時還要分別編譯。

理想狀況是要能夠在 Webpack 編譯 JSX 的時候,一併將 SCSS 也編譯成 CSS 才最方便。

安裝 loader

鏡頭轉換到 Webpack,要先下載一些編譯需要的套件:

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

npm install mini-css-extract-plugin --save-dev

設定 CSS loader 與 MiniCssExtractPlugin 設定

首先在 webpack.config.js 的最上面 requiremini-css-extract-plugin 套件:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 以下省略

接著要添加 loader,先是處理一般 CSS 的:

/* 其餘省略 */
module: {
  rules: [
     /* 其餘省略( JSX , JS loader 設定) */
    {
      test: /\.css$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
        },
        {
          loader: 'css-loader',
          options: {
            modules: { localIdentName: '[name]__[local]___[hash:base64:5]' },
          },
        },
      ],
    },
  ]
}

上方的結構就和 JS 及 JSX 差不多,這裡可以先留意到 moduleslocalIdentName 內的設定,待會會再提到這部分。

最後要指定處理完的 CSS 檔案位置,於是要還得再增加設定:

module.exports = {
  /* 其餘省略 */
  plugins: [
    new MiniCssExtractPlugin({
      filename: './index.css',
    }),
  ],
};

filename 的設定就是路徑加輸出的 CSS 檔名,正常來說要將它編譯到 dist 中,但 webpack.donfig.js 上方其實就有做了這件事情:

module.exports = {
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist/'),
  },
  /* 其餘省略 */
}

也就是他會先吃 output.path 的設定,再來讀你編譯過後的 CSS 要到哪,而上方指定 output.path 為 dist 目錄, MiniCssExtractPluginfilename 又指定 ./index.css,所以編譯過後的 CSS 會在 dist/index.css。

但這麼做還沒有辦法讓 Webpack 能夠找到要編譯的 CSS,因為目前的專案中並沒人使用到它對吧!所以打開 src/index.jsx,並將 src/index.css 檔案 import 使用,用法如下:

/*其餘省略*/
import styles from './index.css';

const Main = () => <h1 className={styles.main}>Hi JSX!</h1>;

// 如果要同時有多個 ClassName 得這麼做:
// const Main = () => <div className={`${styles.main} ${styles.other_class}`}/>;

上方都設定好時,就能夠以 npm run build 將專案打包,如果正確打包,會看見 dist 的目錄下多了一個 index.css

這裡也可以發現 ClassName 變了,因為上方設定了 modules.localIdentName 的關係,所以編譯過後的 CSS 按照他的規則重新命名,這樣做有個好處就是所有不同 Component 內的 ClassName 都不會有衝突。

再打開網頁看結果前,記得添加 CSS 到 html 中:

<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="./index.css">
    </head>
    <!--其餘省略-->
</html>

萬事俱備後,就能開啟 dist/index.html 確認結果了:

增加 SCSS loader

這個步驟將原本 CSS loader 設定改變一下:

module.exports = {
  /* 其餘省略 */
  module: {
    rules: [
      {
        test: /\.(scss)$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: 'css-loader',
            options: {
              modules: { localIdentName: '[name]__[local]___[hash:base64:5]' },
            },
          },
          {
            loader: 'sass-loader',
          },
        ],
      },
    ],
  },
};

上方的設定中變動了幾個地方:

  1. 偵測要編譯的副檔名變成 scss
  2. use 的陣列中增加 sass-loaderloader

記得別忘了要將 src/index.jsx 中 import 的 index.css 改成 index.scss:

import styles from './index.scss';

完成後就能將 index.css 從專案裡刪除,並執行 npm run build 進行打包,接著再將 dist/index.html 從瀏覽器開啟,仍然可以看到相同的結果!

那今天的完整範例程式碼一樣會放到 GitHub 上,歡迎大家參考。

結尾

這個是去年的鐵人賽沒有提到的部分,不曉得算不算遺憾之一,但至少在今年讓它完整了。

如果文章裡有任何問題或是不了解的地方,再麻煩留言告訴我!謝謝大家!


上一篇
Day03 | JSX 瀏覽器看不懂?要翻譯就靠 Babel
下一篇
Day05 | F5 按鍵守護者,讓網頁自動刷新的 Webpack-dev-server
系列文
在 React 生態圈內打滾的一年 feat. TypeScript31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
ert60213
iT邦新手 5 級 ‧ 2020-01-30 11:47:33

不好意思,想請教一個問題

把環境都設置好,然後自己打了一段code
如下
https://ithelp.ithome.com.tw/upload/images/20200130/20124487RVaUBU6pzt.png
結果server卻無法渲染Hello world!
只渲染出gg這個component,可是裡面無內容
檢查元素如下
https://ithelp.ithome.com.tw/upload/images/20200130/20124487pOl2OrIdG4.png
我的scss設定如下
https://ithelp.ithome.com.tw/upload/images/20200130/20124487PUmJ1ZJjnm.png
我在想是否為.jsx 上方的

import styles from './index.scss';

沒吃到的關係
不過就算沒吃到,是不是頂多顏色沒被改變
字體本身還會出現,現在字體本身也沒有出現
再麻煩了,謝謝!

神Q超人 iT邦研究生 5 級 ‧ 2020-01-30 13:08:33 檢舉

Component 的名稱字首要大寫ㄛ!
可以把 gg 改成 GG 試試看 :D

我要留言

立即登入留言