Skip to content

postcss-load-config 能够自动读取项目中的 postcss 相关配置文件。

该功能通常会内置在上述的 postcss-clipostcss-loadergulp-postcss

配置文件及其优先级

譬如,可以在 package.json 中添加 postcss 字段:

json
{
  "postcss": {
    "parser": "sugarss",
    "map": false,
    "plugins": {
      "postcss-plugin": {}
    }
  }
}

也可以在项目中专门创建配置文件,可命名为以下形式:

  1. .postcssrc.postcssrc.(json|yml)
  2. .postcssrc.(js|cjs|mjs|ts)
  3. postcss.config.(js|cjs|mjs|ts)

其中,package.json 中的 postcss 字段优先级最高,这一点确实比较反人类。

关于更加详细的优先级列表,可以点击参考postcss-load-config源码

另外,postcss-load-config 对于配置优先级的判断,使用了 lilconfig 第三方库。

lilconfig 中对于配置优先级的判断可以点击参考lilconfig源码

我们在实际项目应用中,推荐创建 JavaScript 类型的配置文件,因为方便后续扩展

配置详解

在项目开发中,常用的配置文件,大致有 JSONJS 两种类型。

大多数场景下,我们只需要在配置文件中指明要使用的插件即可

譬如,在 JSON 中的形式:

json
{
  "plugins": {
    "postcss-import": {},
    "autoprefixer": {}
  }
}

JS 中的形式:

js
module.exports = {
  plugins: {
   'postcss-import': {},
   autoprefixer: {}
  }
}

以上,都是将 plugins 属性声明为了对象形式。postcss 会自动根据配置加载插件。

但我们倾向于在 JS 中将 plugins 作为数组形式使用:

js
const postcssImport = require('postcss-import')
const autoprefixer = require('autoprefixer')

module.exports = {
  plugins: [
    postcssImport({}),
    autoprefixer({})
  ]
}

这种形式更加易读,且与 rollup 的插件使用机制类似,方便统一记忆。

配置文件中除了 plugins 属性外,还有其他可配置属性。整理如下:

NameTypeDefaultDescription
from{String}undefinedSource File Path
to{String}undefinedDestination File Path
map`{StringObject}`false
parser`{StringFunction}`false
syntax`{StringFunction}`false
stringifier`{StringFunction}`false

其中的 mapparsersyntaxstringifier 属性在某些场景下,我们可以进行自定义配置。

fromto 在大多数情况下,都无需配置。

postcss-cli 中,是通过 CLI Arguments 来定义 fromto 的,譬如:

shell
postcss -o styles/output.css styles/entry.css

而像 postcss-loadergulp-postcss 是通过 STDIN 或者文件流来获取输入和输出的。

如果要问我,什么时机下可以在 .postcssrc 配置文件中使用 fromto 属性?

我的答案是,使用 postcss-load-config 自定义一个支持 fromto 属性的插件,譬如下文中的 loaderWithPostcss 代码可以做一些拓展。

context上下文

之所以要推荐 postcss 配置文件使用 JavaScript 文件类型,还有一个原因在于该类型的配置文件可以导出一个携带 context 上下文的函数

在此基础下,我们可以更加灵活的对 postcss 配置文件进行自定义。

js
// .postcssrc.js
module.exports = ctx => {
  console.log(ctx)
  const { options: { map } } = ctx
  return {
    map,
    plugins: [
      require('postcss-import')({}),
      require('autoprefixer')({})
    ]
  }
}

当我们使用 postcss-cli 来打包时,执行:

shell
postcss -o styles/output.css styles/entry.css

ctx 打印如下:

{
  cwd: '/path/to/postcss',
  env: 'development',
  options: {
    map: { inline: true },
    parser: undefined,
    syntax: undefined,
    stringifier: undefined
  },
  file: {
    dirname: '/path/to/postcss/styles',
    basename: 'entry.css',
    extname: '.css'
  }
}

如果是在 webpack 项目下使用 postcss-loader,那么这里的 ctx 会有 [ 'mode', 'file', 'webpackLoaderContext', 'env', 'options' ]5 个属性。

我们可以根据这些属性,对配置文件作一些更加精细化的自定义控制。

代码应用

在工程化项目中,很多扩展(postcss-loadergulp-postcss 等)都会内置 postcss-load-config 功能。

对于使用这些扩展的方式,核心方面分为三部分:

  1. 定义配置文件,如 .postcssrc.js
  2. 定义 CSS 的入口。
  3. 定义 CSS 的出口。

相当于扩展给使用者预留了三个缺口项,以供使用者自定义

如果我们要创建一个类似功能的扩展,核心代码大致如下:

js
function loaderWithPostcss ({ entry, output }) {
  const { readFileSync, writeFileSync } = require('fs')
  const postcss = require('postcss')
  const postcssrc = require('postcss-load-config')

  const css = readFileSync(entry, 'utf8')

  const ctx = { parser: true, map: 'inline' }
  postcssrc(ctx).then(({ plugins, options }) => {
    // 这里要对options.from做判断 不然下面的postcss在运行时 会警告 Without `from` option PostCSS could generate wrong source map and will not find Browserslist config. Set it to CSS file path or to `undefined` to prevent this warning.
    options.from = options.from || undefined
    postcss(plugins)
      .process(css, options)
      .then((result) => {
        const { css } = result
        writeFileSync(output, css, 'utf8')
      })
  })
}

const { resolve } = require('path')
loaderWithPostcss({
  entry: resolve(__dirname, './styles/entry.css'),
  output: resolve(__dirname, './styles/output.css')
})