導入 PostCSS

PostCSS 是一個 CSS 工具,有許多加工 CSS 內容的功能插件,
雖然經常被翻成「後處理器」,但根據選用插件的不同,它也能做到像 SASS 一樣的「預處理器」功能!

PostCSS 的任務可以透過 CLI 或 webpack 編譯完成。

CLI

安裝 PostCSS 與 CLI,這邊以 autoprefixer 這個插件為例順便安裝進去。

npm install -D postcss postcss-cli autoprefixer

成套的框架系統有的會包進 PostCSS(像 Next.js),但目前我們是手動建環境來了解運作過程,
所以我們要自己在根目錄新增 postcss.config.js 這個檔案,
然後依照下面的格式把剛剛安裝的 autoprefixer 載入進來。

module.exports = {
  plugins: {
    autoprefixer: {},
  },
};

接下來新增要加工的 css 檔案,然後透過剛剛安裝的 postcss-cli,去設定檔案路徑:

npx postcss ./src/style.css -o ./src/all.css -w

如果確定檔案名稱和路徑不會改動的話,可以把這個指令寫到 package.json,
這樣下次繼續開發時就不用再打這個冗長的路徑,用 npm run watch 就可以啟動編譯:

"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"watch": "postcss ./src/style.css -o ./src/all.css -w"
},

HTML 檔要記得引入加工完的 CSS 檔,不然就做白工啦~~

<link rel="stylesheet" href="./src/all.css" />

這邊示範有安裝 autoprefix 插件的狀況下編譯的結果:

autoprefix 展示

這裡使用了 ::selection 這個偽元素功能,經過 autoprefix 判斷後在 FireFox 瀏覽器有可能不支援, 所以幫忙加上了 -moz- 的前綴!


Webpack

利用 webpack 打包就不需要 postCSS 的 CLI 編譯了,但反過來說這次要換 webpack-CLI 編譯。
因為 postcss-preset-env 這個套件已經集成一些 postCSS 的插件,
所以 webpack 官方推薦安裝這個,不用再另外安裝 autoprefixer。

npm install -D webpack webpack-cli postcss

webpack 是依靠各種 loader 的功能解析檔案的,這邊把所有用到的 loader 都安裝:

npm install -D css-loader postcss-loader postcss-preset-env

要注意 webpack 預設會載入一個 js 檔作為進入點,
而最後編譯完成都會變成一支 bundle.js 檔給我們使用。

如果是練習原生 JS 的東西,應該不希望 css 檔也被整合進去,
所以需要另外一個插件 mini-css-extract-plugin :

npm install -D mini-css-extract-plugin

大費周章安裝完所有東西後,在根目錄新增 webpack.config.js,
把示範裡面的 code 都摳過來~~(沒辦法 webpack 設定就是長這麼醜)~~

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'postcss-preset-env',
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
};

style-loader 是在最後輸出成 bundle.js 時把 css 檔也抓進來編譯,
最後在 html 載入時也會一起載入原本寫好的樣式,
但在這邊我們不需要~~(而且剛剛注意剛剛並沒有安裝這個 loader 哦!)
所以要把 style-loader 替換成我們剛剛安裝的插件 mini-css-extract-plugin,
順便設定一下 webpack 的輸入輸出路徑和模式:

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  mode: 'development', // mode 選 development 即可
  entry: './src/main.js', // 輸入點是必填的不然 webpack 沒辦法啟動編譯
  output: {
    // 輸出路徑設定
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },

  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [
          MiniCssExtractPlugin.loader, // 把 style-loader 替換掉
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'postcss-preset-env',
                    {
                      // Options
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'all.css', // 輸出的 css 檔名,這個也會在上面設定的 dist 資料夾出現
    }),
  ],
};

設定完之後直接敲 webpack 的 CLI 就會編譯了,跟其他 CLI 一樣,webpack 也可以監聽,這邊就不示範直接編譯:

npx webpack

去 dist 資料夾找到剛剛編譯完成的 all.css,內容已經被 autoprefixer 修改過:

/*!****************************************************************************************************************************************************************************************************************************************************************!*\

!*** css ./node_modules/.pnpm/css-loader@6.8.1_webpack@5.88.2/node_modules/css-loader/dist/cjs.js!./node_modules/.pnpm/postcss-loader@7.3.3_postcss@8.4.31_webpack@5.88.2/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./src/style.css ***!

\****************************************************************************************************************************************************************************************************************************************************************/

h1::-moz-selection {
  color: red;
}

h1::selection {
  color: red;
}

參考資料