标签: browserslist

  • 使用 caniuse-lite 检查目标浏览器的特性支持情况

    使用 caniuse-lite 检查目标浏览器的特性支持情况

    起因

    之前得知 loading="lazy" 新特性,正巧在学习如何使用 html-webpack-plugin,于是就写了个 lazyload-webpack-plugin,可以给页面里所有 <img><iframe> 加上 loading="lazy" 属性,以启动原生 lazyload。

    不过当初写得很简单,只会不分青红皂白加属性,甚至可能会覆盖已有的 loading="eager" 属性,引发 bug。所以这几天就想找时间升级一下:

    1. 不再覆盖 loading 属性
    2. 根据 browserslist 得到的目标浏览器器列表采取不同策略
      1. 支持 loading="lazy" 就延续之前的做法
      2. 不支持的话,用 data-src 替换 src,然后在页面里根据浏览器特性处理

    caniuse-lite

    没想到这个需求还挺难满足,找了一圈竟然没有成型的教程,只好自己摸索一下,还好并不复杂。

    以下代码实现了根据环境配置检查目标浏览器是否支持 loading="lazy" 的功能。我用在新版本的 lazyload-webpack-plugin 中,现在可以实现前面说的功能了。

    // caniuse-lite 是官方提供的 caniuse 仓库封装,方便我们查询特性支持
    const lite = require('caniuse-lite');
    const browserslist = require('browserslist');
    // `features` 是特性支持列表,`feature()` 可以将其转换成好用的 json 格式
    const {features, feature: unpackFeature} = lite;
    
    // 这一步,用特性名 'loading-lazy-attr' 获取支持列表
    const feature = unpackFeature(features['loading-lazy-attr']);
    // 直接声明 browserslist 实例,它会自动查找本地 `.browserslistrc` 或环境变量 `BROWSERSLIST` 来生成浏览器列表
    const browsers = browserslist();
    const {stats} = feature;
    // 遍历浏览器列表,根据名称、版本验证对 `loading="lazy"` 的支持情况
    const isSupport = browsers.every(browser => {
      const [name, version] = browser.split(' ');
      const browserData = stats[name];
      const isSupport = browserData && browserData[version] === 'y';
      if (!isSupport) {
        console.log(`[lazyload-webpack-plugin] target browser '${browser}' DOES NOT supported \`loading="lazy"\`.`);
      }
      return isSupport;
    });
    
    module.exports = isSupport;

    问题

    现在的情况是,如果知道特性名称(如“loading-lazy-attr”),可以判断目标浏览器是否支持;但是如果不知道准确名称,就没法判断。如果我想在项目当中使用,比如检查当前代码仓库用到哪些特性不被目标浏览器兼容,并生成 polyfill 套件,就很难操作。

    有待进一步学习。

    自荐

    欢迎有制作静态页面需求的同学使用 lazyload-webpack-plugin<img><iframe> 添加 loading="lazy"。关于使用 webpack 制作多页面站点的经验分享,可以阅读我的这篇文章《使用 Webpack 开发多页面站点》。

    有任何问题、意见、建议,欢迎通过各种方式提给我。

    (更多…)
  • Tailwind.css + Postcss 笔记

    Tailwind.css + Postcss 笔记

    0. 缘由

    去年,一篇《Tailwind CSS: From Side-Project Byproduct to Multi-Million Dollar Business》在我的时间线上刷屏,作为 side project 和自由职业的翘楚,他的产品和商业项目十分令人羡慕。

    所以,我一直想找个机会试用一下 Tailwind.css。这次春节,想着放松休闲一下,就开了个小项目,尝试一下新技术栈:

    1. Vue3 全家桶
    2. Tailwind.css + PostCSS
    3. Webpack 工具链

    这篇笔记用来记录心得和体会。


    1. 基础

    官方网站:https://tailwindcss.com/

    2. 安装&配置

    npm install tailwindcss@latest postcss@latest autoprefixer@latest
    // postcss.config.js
    module.exports = {
       plugins: {
         tailwindcss: {},
         autoprefixer: {},
       }
    }

    2.1 创建 tailwindcss 配置

    npx tailwindcss init

    生成的配置文件如下:

    // tailwind.config.js
    module.exports = {
      purge: [],
      darkMode: false, // or 'media' or 'class'
      theme: {
        extend: {},
      },
      variants: {},
      plugins: [],
    }

    2.2 创建 CSS

    @tailwind base;
    @tailwind components;
    @tailwind utilities;

    这个 CSS 无法直接被浏览器使用,需要经过 PostCSS 调用 Tailwind 插件编译后才行。

    2.3 配置 Webpack

    只需要配置 CSS 和 Stylus 规则:

    module.exports = {
      module: {
        rules: [
          {
             test: /.css$/,
             use: [
               isDevServer ? 'style-loader' : MiniCssExtractPlugin.loader,
               'css-loader',
               'postcss-loader'
             ]
           },
           {
             test: /.styl(us)?$/,
             use: [
               isDevServer ? 'style-loader' : MiniCssExtractPlugin.loader,
               'css-loader',
               'postcss-loader',
               'stylus-loader',
             ],
           },
        ]
      }
    }

    2.4 配置 .browserslistrc

    PostCSS 同样需要用 browserslist 处理兼容性问题,所以一定要配置好,比如我近期喜欢用 bootstrap-icons 为图标,需要用到 svg-mask 系列属性,在 Chrome 里就需要补充前缀。那么,如果 browserslist 里没有 Chrome 就不会加前缀(我昨天就踩在这个坑里)。可以使用 npx browserslist 来检查。

    2.5 修改 npm scripts

    PostCSS 和 Tailwind.css 需要用 NODE_ENV 变量决定动作内容,所以必须加到 npm scripts 里。

    {
      "scripts": {
        "serve": "NODE_ENV=development webpack serve --config build/webpack.config.js",
        "build": "NODE_ENV=production webpack --config build/webpack.config.prod.js --mode=production",
        "lint": "eslint --fix --ext=.vue,.js ./"
      }
    }

    2.6 完成

    至此,基础 Tailwind.css + PostCSS + Webpack 配置完成,接下来就可以使用 CSS 实现界面了。

  • 解决 mocha 测试时 `cannot use import statement outside a module` 错误,以及配置 travis

    解决 mocha 测试时 `cannot use import statement outside a module` 错误,以及配置 travis

    前些天同事突然发现一个库项目的测试无法运行,报错的内容大概是:cannot use import statement outside a module "should",即无法在模块外使用 import 导入内容。这个错误比较奇怪,简单 Google 之,基本上大家的解决方案都是使用 <script type="module"> 即在浏览器里用 ESM 加载 JS,这明显和我们的环境不同。

    Node.js 当然也支持 ESM,不过这应该也不是问题症结。大体上我可以判断,因为测试集(JS 文件)用到 import 语法,而且用 mocha --require @babel/register 启动测试,所以应该是 Babel 没有正确转译导致的问题。

    检查 Babel 的相关配置,发现同事为了能同时编译现代浏览器和 IE 两个版本的库,.babelrc 大概是这样的:

    {
      "env": {
        "default": {
          "presets": [],
        },
        "withie": {
          "presets": [],
        }
      }
    }

    猜测 mocha 走了 default 分支,然后没有转译,所以出错。解决方案就是添加 node 分支,以当前 node 版本为 target,这样该转译就转译,不转译就用原生,性能更好,修改好的配置大概是这样的:

    {
      "env": {
        "default": {"presets": []},
        "withie": {"presets": []},
        "node": {
          "presets": [
            [
              "@babel/preset-env",
              {
                "targets": {
                  "node": "current"
                },
                "useBuiltIns": false
              }
            ]
          ]
        }
      }
    }

    使用时,需要增加环境变量用来切换配置:BABEL_ENV=node mocha --require @babel/register。比较奇怪的是,其他脚本使用 BROWSERSLIST_ENV 切换,这里只能使用 BABEL_ENV,我暂时不知道为什么。

    修改之后的脚本就可以正常测试了。接下来我打算给它加上 Travis,这样就能自动 lint + 测试,比较方便控制质量。加 Travis 很简单,拷过来一个 .travis.yml 改吧改吧就行了,但是第一次运行失败了,而且是超时。经过研究,原来 mocha 从 v4 开始,完成测试后不会自动退出,除非手动指定,方法是增加 --exit 参数。

    所以最终的测试脚本是(其它配置略去):

    {
      "scripts": {
        "test": "BABEL_ENV=node mocha --require @babel/register --exit",
      }
    }

    最终 Travis 配置是:

    sudo: required
      dist: trusty
     
    
      language: node_js
      node_js:
        - 14
     
    
      branches:
        only:
          - master
     
    
      cache:
        directories:
          - ~/.npm # cache npm's cache
          - ~/npm # cache latest npm
     
    
      install:
        - npm ci
     
    
      script:
        - npm run lint
        - npm run test
  • 基于 @vue/cli 的项目配置 browserslist

    基于 @vue/cli 的项目配置 browserslist

    前些日子虽然写了 最近折腾 @babel/preset-env 的一些小心得,但其实没有正确的理解和配置 browserslist,所以今天问题又来了。

    (更多…)
  • 最近折腾 @babel/preset-env 的一些小心得

    最近折腾 @babel/preset-env 的一些小心得

    近来厂里的项目越来越多,代码共享必不可少。我现在采取的方案是:

    1. 把公共组件拿出来,开一个新仓库
    2. 使用 webpack 进行打包编译,libraryTarget: 'umd'
    3. 将打包编译的代码一起提交到仓库
    4. 使用 npm i <owner>/<repo> -S 安装依赖,因为我厂的仓库均为私有,所以不能发布到 NPM

    这套方案简单好用,实操效果良好。接下来我希望优化打包结果,于是研究了打包配置项,下面是我的一点心得。

    [2021-04-07] 更新:

    我们目前采用 GitHub Registry 托管私有 packages 的方案,比上面直接安装仓库的方案更好,想了解的同学可以看 使用 GitHub Registry 托管私有 NPM 源

    (更多…)