SCSS 是 CSS 的預處理器,就是替原本的 CSS 再加上一些強大的語法,讓我們在寫 CSS 的時候可以更加直觀,相關說明可以查閱 官方文檔 ,本篇就不多說了,重點說明該怎麼在 React 專案中玩轉 SCSS。
使用 SCSS 並不需要特別安裝什麼套件才能使用,但是記得昨天提到的,瀏覽器看不懂 JSX,所以我們需要用 Babel 編譯成 JS, 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 才最方便。
鏡頭轉換到 Webpack,要先下載一些編譯需要的套件:
npm install style-loader css-loader sass-loader --save-dev
npm install mini-css-extract-plugin --save-dev
首先在 webpack.config.js 的最上面 require
進 mini-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 差不多,這裡可以先留意到 modules
內 localIdentName
內的設定,待會會再提到這部分。
最後要指定處理完的 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 目錄, MiniCssExtractPlugin
的 filename
又指定 ./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 確認結果了:
這個步驟將原本 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',
},
],
},
],
},
};
上方的設定中變動了幾個地方:
scss
。use
的陣列中增加 sass-loader
的 loader
。記得別忘了要將 src/index.jsx 中 import
的 index.css 改成 index.scss:
import styles from './index.scss';
完成後就能將 index.css
從專案裡刪除,並執行 npm run build
進行打包,接著再將 dist/index.html 從瀏覽器開啟,仍然可以看到相同的結果!
那今天的完整範例程式碼一樣會放到 GitHub 上,歡迎大家參考。
這個是去年的鐵人賽沒有提到的部分,不曉得算不算遺憾之一,但至少在今年讓它完整了。
如果文章裡有任何問題或是不了解的地方,再麻煩留言告訴我!謝謝大家!
不好意思,想請教一個問題
把環境都設置好,然後自己打了一段code
如下
結果server卻無法渲染Hello world!
只渲染出gg這個component,可是裡面無內容
檢查元素如下
我的scss設定如下
我在想是否為.jsx 上方的
import styles from './index.scss';
沒吃到的關係
不過就算沒吃到,是不是頂多顏色沒被改變
字體本身還會出現,現在字體本身也沒有出現
再麻煩了,謝謝!
Component 的名稱字首要大寫ㄛ!
可以把 gg
改成 GG
試試看 :D