如何在项目中使用 Baseline

1. 简介

Baseline 是一项计划,旨在更清晰地说明哪些 Web 功能是可互操作的,并且现在可以安全使用。得益于 Baseline 工具的进步,您现在可以直接在项目中将 Baseline 用作 Browserslist 查询,以便您的工具链可以根据您选择的 Baseline 目标更改代码的输出。

在本 Codelab 中,您将学习如何在示例项目中使用 Baseline,以及如何对其进行配置以选择特定的 Baseline 目标。您还将观察到项目工具链的输出如何根据您选择的 Baseline 目标而变化。

2. 在本地机器上设置演示

首先,前往您喜欢的终端应用,克隆演示代码库,然后进入项目目录:

git clone git@github.com:GoogleChromeLabs/baseline-demos.git
cd baseline-demos/tooling/webpack

此时,演示已集成 Baseline,但您需要检出一个从头开始的提交:

git checkout d3793f25

克隆代码库后,现在可以启动演示了。此项目使用 nvm 来管理 Node 版本控制。如果您全局安装了相当新的 Node 版本,则可能不需要完成此步骤,但如果您使用 nvm,请运行以下命令:

nvm install
nvm use

在此处,安装项目的软件包:

npm install

如果您想查看演示,请运行以下命令:

npm start

然后前往 http://localhost:8080。演示本身是一个卡片列表,可以使用页面顶部的表单字段进行过滤。应用本身使用了多种已达到 Baseline 阈值的功能。

完成演示后,前往终端并按 Ctrl+C,随时停止运行演示。

3. 如何将 Baseline 集成到项目中

此演示在开始时未指定 Browserslist 配置。Browserslist 是一种紧凑的查询语法,用于告知工具链必须支持的最低浏览器版本。例如,使用 a query of last 3 years 查询将指定广泛的目标。在此演示中,我们将指定与您可以在工具链中使用的 Baseline 目标一致的 Browserslist 查询。基线目标可以是以下项之一:

  • 移动目标,它们会随着新浏览器的发布而随时间更新:
    • Baseline 新近可用,它与从现在到 30 个月前这段时间内在核心浏览器组中实现的互操作功能保持一致。
    • Baseline 广泛可用,它包括 30 个月或更长时间前在核心浏览器组中实现的互操作功能。
  • 固定目标,它们表示固定时间点的浏览器版本。这些目标以 2016 年到当前年份之间的年份表示。

首先,我们将为项目选择移动的 Baseline 广泛可用目标。为此,请打开 package.json 并添加以下内容:

"browserslist": "baseline widely available"

4. 通过选择不同的 Baseline 目标来观察代码输出的变化

您刚刚选择了 Baseline 广泛可用作为演示项目的目标。接下来,您需要构建项目:

npm run build

由于项目的 babel.config.js 中将 @babel/preset-envdebug 选项指定为 true,因此会产生大量额外输出。首先,请注意捆绑器统计信息中 CSS 和 JavaScript 的大小:

assets by status 213 KiB [emitted]
  asset js/home.5f3c5480.js 208 KiB [emitted] [immutable] [minimized] (name: home) 2 related assets
  asset css/home.20db50ef.css 3.64 KiB [emitted] [immutable] (name: home) 1 related asset
  asset index.html 564 bytes [emitted]

请注意,JavaScript 软件包为 208 KiB,CSS 为 3.64 KiB。这是因为此项目使用 core-js 进行 JavaScript Polyfill,并使用 autoprefixer 为尚未完全互操作的 CSS 属性应用特定于供应商的前缀。core-jsautoprefixer 都会受到所选 Baseline Browserslist 查询的影响。

输出中需要注意的另一件事是,您的 Baseline 广泛可用 Browserslist 查询如何转换为 Browserslist 查询。在您的项目中,它看起来类似于以下内容:

Using targets: {
  "chrome": "108",
  "edge": "108",
  "firefox": "108",
  "ios": "16",
  "safari": "16"
}

请注意构建输出中由 core-js 注入的 Polyfill:

The corejs3 polyfill added the following polyfills:
  es.iterator.constructor { "chrome":"108", "edge":"108", "firefox":"108", "ios":"16", "safari":"16" }
  es.iterator.filter { "chrome":"108", "edge":"108", "firefox":"108", "ios":"16", "safari":"16" }
  es.iterator.map { "chrome":"108", "edge":"108", "firefox":"108", "ios":"16", "safari":"16" }

如果您更改 Baseline 目标,此输出可能会发生变化。假设您的应用必须支持一组较旧的浏览器,因为 SLA 更加严格。如果是这种情况,您可能会选择更保守的目标。在 package.json 文件中,更改 Browserslist 配置以反映以下内容:

"browserslist": "baseline 2016"

这会选择 Baseline 2016 作为目标,并转换为 Browserslist 查询。重新运行构建后,您可以注意到工具链输出中的差异:

npm run build

首先,请注意捆绑器统计信息中项目 JavaScript 和 CSS 的文件大小变化:

assets by status 237 KiB [emitted]
  asset js/home.b228612d.js 232 KiB [emitted] [immutable] [minimized] (name: home) 2 related assets
  asset css/home.0c3e4fd7.css 3.91 KiB [emitted] [immutable] (name: home) 1 related asset
  asset index.html 564 bytes [emitted]

您会注意到,JavaScript 软件包的大小增加了近 30 KiB。由于 autoprefixer 根据 2016 Baseline 目标添加了更多供应商前缀,因此项目的 CSS 仅略有增加。另请注意 Browserslist 查询的变化:

Using targets: {
  "chrome": "53",
  "edge": "14",
  "firefox": "49",
  "ios": "10",
  "safari": "10"
}

与 Baseline 广泛可用目标相比,这些浏览器版本要早得多,以至于在这种情况下定位的 Edge 版本是 Chromium 之前的版本。

core-js 注入的 Polyfill 也会发生变化,这比选择 Baseline 广泛可用作为目标时要多得多:

The corejs3 polyfill added the following polyfills:
  es.array.filter { "edge":"14" }
  es.iterator.constructor { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.iterator.filter { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.object.to-string { "edge":"14", "firefox":"49" }
  es.array.includes { "firefox":"49" }
  es.string.includes { "edge":"14" }
  es.array.map { "firefox":"49" }
  es.iterator.map { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.symbol { "edge":"14", "firefox":"49" }
  es.symbol.description { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.array.iterator { "chrome":"53", "edge":"14", "firefox":"49" }
  web.dom-collections.iterator { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.array.push { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.regexp.to-string { "edge":"14" }
  es.array.from { "edge":"14", "firefox":"49" }
  es.regexp.exec { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }
  es.regexp.test { "edge":"14" }
  es.error.cause { "chrome":"53", "edge":"14", "firefox":"49", "ios":"10", "safari":"10" }

这里的要点是,您的 Baseline 目标可能会对项目工具链转换应用的方式产生重大影响;此示例中的应用非常基本,无论是 React 还是应用本身,都没有太多尖端的开发者体验功能。对于复杂得多的应用,您可能会看到截然不同的结果,甚至可能需要添加更多 Polyfill、转换和其他来源的额外代码,以符合您选择的 Baseline 目标。

5. 定位下游浏览器

回顾一下,Baseline 目标的核心浏览器组包括以下浏览器:

  • Chrome
  • Android 上的 Chrome
  • Firefox
  • Android 上的 Firefox
  • Edge
  • macOS 上的 Safari
  • iOS 上的 Safari

不过,您可以定位所谓的“下游浏览器”。这些浏览器的引擎源自核心浏览器组中的浏览器,最常见的是 Chromium。其中包括 Opera、Samsung Internet 等浏览器。除了核心浏览器组中的浏览器之外,您还可以通过将 with downstream 添加到任何有效的 Baseline Browserslist 查询来定位这些浏览器:

"browserslist": "baseline widely available with downstream"

这会根据 Baseline 广泛可用目标定位下游浏览器。如需了解如何将其解析为 Browserslist 查询,请重新构建项目:

npm start

然后注意 Browserslist 查询的变化:

Using targets: {
  "android": "108",
  "chrome": "108",
  "edge": "108",
  "firefox": "108",
  "ios": "16",
  "opera": "94",
  "opera_mobile": "80",
  "safari": "16",
  "samsung": "21"
}

您还可以按年份定位下游浏览器。例如:

"browserslist": "baseline 2016 with downstream"

使用此配置,您的 Browserslist 查询将相应更改:

Using targets: {
  "android": "53",
  "chrome": "53",
  "edge": "14",
  "firefox": "49",
  "ios": "10",
  "opera": "40",
  "opera_mobile": "80",
  "safari": "10",
  "samsung": "6.2"
}

6. Lint 工具和其他工具

Browserslist 中内置的 Baseline 查询对于捆绑器和工具链的其他部分等工具非常方便,但其他工具(例如 Lint 工具)也很有价值,这些工具已将 Baseline 目标作为其配置的一部分。

Lint 工具支持 Baseline 的一个很好的示例是 ESLint,它作为 CSS Lint 的一部分,提供 use-baseline 规则,使用 @eslint/css 让您可以定位 Baseline 新近可用、Baseline 广泛可用或 Baseline 年份。社区 @html-eslint/eslint-plugin 软件包中也有类似的规则,让您可以在 eslint.config.js 文件中对 HTML 功能执行相同的操作:

export default [
  /* Omitted JS linting rules ... */
  // Lint CSS files for Baseline:
  {
    files: ["**/*.css"],
    plugins: {
      css
    },
    language: "css/css",
    rules: {
      "css/no-duplicate-imports": "error",
      // Lint CSS files to make sure they are using
      // only Baseline Widely available features:
      "css/use-baseline": ["warn", {
        available: "widely"
      }]
    },
  },
  // Lint HTML and JSX files for Baseline:
  {
    files: ["**/*.html"],
    ...html.configs["flat/recommended"],
    rules: {
      // Lint HTML files to make sure they are using
      // only Baseline Widely available features:
      "@html-eslint/use-baseline": ["warn", {
        available: "widely"
      }]
    }
  }
];

此配置中有几点需要注意:

  1. HTML 和 CSS Lint 软件包都使用 use-baseline 规则,并且使用 available: "widely" 配置选项将其设置为广泛可用。
  2. 对于这两个 Lint 软件包,Lint 违规的日志级别都设置为 "warn"。您可以将其设置为 "error",以使用错误代码退出,防止构建发生。

您之前可能在运行 npm run build 时看到过 Lint 工具输出,但如需单独查看 Lint 工具输出,您可以运行以下命令:

npm run lint

您将看到的输出会突出显示项目 CSS 中的多个警告:

/var/www/baseline-demos/tooling/webpack-browserslist-config-baseline/src/css/normalize.css
  222:3  warning  Property 'outline' is not a widely available baseline feature  css/use-baseline

/var/www/baseline-demos/tooling/webpack-browserslist-config-baseline/src/css/styles.css
  62:3   warning  Property 'outline' is not a widely available baseline feature                                css/use-baseline
  81:23  warning  Value 'subgrid' of property 'grid-template-rows' is not a widely available baseline feature  css/use-baseline

7. 即将完成

在项目中使用 Browserslist 提供的 Baseline 查询确实需要了解一些底层构建工具和 Browserslist 本身,但将其放入项目本身的操作非常简洁。使用它的主要好处是,您不再需要考虑您支持的浏览器版本号,而是考虑为您完成繁重工作的 Baseline 目标。

此外,还有一个在 Rollup 上运行的演示版本,您也可以使用该演示来大致遵循本 Codelab。

Baseline 支持也开始出现在其他捆绑工具中。例如,Vite 在后台使用 Rollup,自版本 7 起,现在默认定位 Baseline 广泛可用浏览器

无论您决定如何操作,将 Browserslist 中提供的 Baseline 查询引入您的项目,并选择适合您的 Baseline 目标,您都可以以更简单、更可靠的方式定位浏览器。