Webpack5+vscode搭建kintone开发环境(七)IE11 兼容

cybozu发表于:2021年01月07日 14:19:44更新于:2021年07月28日 14:31:46

目录

第一篇:初始化项目
第二篇:代码规范
第三篇:Webpack 基本配置
第四篇:开发环境设置
第五篇:生产环境设置
第六篇:css、less、scss、图片支持
第七篇:IE11 兼容
第八篇:支持 React
第九篇:支持 Typescript>
第十篇:命令行工具


大家都知道木桶效应吧,一只木桶能盛多少水,并不取决于最长的那块木板,而是取决于最短的那块木板。
在前端开发中,IE 就是那块最短的木板,为了迁就 IE,我们不得不使用过时的 ES5 语法,很多新函数也因为 IE 的关系而无法使用。
之前的 less 篇章提到了转换的概念,那么有没有工具可以提供 IE 转换这一功能呢?
有的!


JS

转译

JS 转译工具名为 Babel,我们通过以下命令安装:

npm install babel-loader @babel/core @babel/preset-env -D
  • babel-loader 使用 babel 解析文件。

  • @babel/core 是 babel 的核心模块。

  • @babel/preset-env 转译 ES6+ 语法。

在根目录下新建.babelrc 文件,这个是 babel-loader 的配置文件,并输入:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ]
  ]
}
  • presets 是一些列插件集合

  • modules 防止 babel 将任何模块类型都转译成 CommonJS 类型

之后需要告诉 @babel/preset-env 我们需要转译浏览器版本。官方文档推荐使用browserlist,这也可以和之后的 css 配置保持一致。

打开我们的 package.json,添加如下字段:

{
  //others
  "browserslist": [
    ">0.2%",
    "not dead",
    "ie >= 11",
    "not op_mini all"
  ],
  //others
}

对于上面配置不理解的同学可以在命令行中输入

npx browserslist

它会告诉你这么配置能支持哪些浏览器。

接下来打开我们的 webpack.common.js 文件,在 module.rules 增加以下代码:

module.exports = {
  //others
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        options: { cacheDirectory: true },
        exclude: /node_modules/,
      },
      //others
    ],
  },
}
  • 匹配到 js 文件,就使用 babel-loader。

  • cacheDirectory babel-loader 在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率,开启 cacheDirectory 后将这些公共文件缓存起来,下次编译就会加快很多。

  • exclude node_modules 目录不需要我们去编译,将对方排除以提升效率。

运行 build 发现箭头函数已经转译成 es5 语法了,这样就行了吗?no,我们还有一步重要的工作要做。


注入

熟悉 js 的同学都知道,Promise 或 .includes 这种新的 es 特性,是没办法转译到 es5 的。
比如在我们的 index.js 中加入一句代码

Promise.resolve().then(() => console.log(2))

你会发现 build 出来的 js 不会对 Promise 有任何处理,这也意味着IE 下必定会出错

那么我们把这中新的语言特性的实现注入到打包后的文件中,不就行了吗?


这里借助 @babel/plugin-transform-runtime 这个插件,它和 @babel/polyfill 一样都能提供 ES 新 API 的垫片,都可实现按需加载,但前者不会污染原型链。

另外,Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。
显然这会增加代码的冗余。


而 @babel/plugin-transform-runtime 会将所有的辅助函数都从 @babel/runtime-corejs3 导入,从而减少冗余。

npm install @babel/plugin-transform-runtime -D
npm install @babel/runtime-corejs3 -S

注意: @babel/runtime-corejs3 的安装为生产依赖。

.babelrc 文件中输入:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": {
          "version": 3,
          "proposals": true
        },
        "useESModules": true
      }
    ]
  ]
}
  • proposals:使用 corejs3 时必须开启

  • useESModules:默认是 false 的,这里开启是为了防止 tree-shaking 失效。

再次 build 发现 Promise 已经被处理了,去 IE 上看看效果吧。


CSS

IE 的兼容问题不仅仅体现在 js 上,还有 css。

Postcss 一种对 css 编译的工具,类似 Babel 对 js 一样通过各种插件对 css 进行处理,在这里我们主要使用以下插件:

  • postcss-flexbugs-fixes :用于修复一些和 flex 布局相关的 bug。

  • postcss-preset-env :将最新的 CSS 语法转换为目标环境的浏览器能够理解的 CSS 语法。使用 autoprefixer 来自动添加浏览器头。

  • postcss-normalize :从 browserslist 中自动导入所需要的 normalize.css 内容。

npm install postcss-loader postcss postcss-flexbugs-fixes postcss-preset-env postcss-normalize -D

用法和之前 css 篇的其他 loader 一样,我们需要在 css-loader 之前使用。
为此,抽取出来的公用函数 cssLoaders 需要做些调整。
修改 webpack.common.js

const cssLoaders = (preNumber) => [
  isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
  {
    loader: 'css-loader',
    options: {
      sourceMap: isDev,
      importLoaders: preNumber + 1,
    },
  },
  {
    loader: 'postcss-loader',
    options: {
      postcssOptions: {
        plugins: [
          'postcss-flexbugs-fixes',
          [
            'postcss-preset-env',
            {
              autoprefixer: {
                grid: true,
                flexbox: 'no-2009',
              },
            },
          ],
          'postcss-normalize',
        ],
      },
      sourceMap: isDev,
    },
  },
]

importLoaders需要+1操作,另外browserslist 的设置之前 js 篇有设置过,因此不需要重复设置。

来试试效果吧,
修改 app.css


@import 'normalize.css/opinionated.css';

.app {
  flex: 1;
  font-family: system-ui;
  text-align: center;
  background-color: #12345678;
}

::placeholder {
  color: gray;
}

别忘了在 index.js 中 import 一下。


import './app.css'
kintone.events.on('app.record.index.show', (event) => {
  const root = kintone.app.getHeaderSpaceElement()
  root.innerHTML = '<div class="app"><h1>hello kintone!</h1></div>'
  return event
})

为了更好的看效果,让我们先注释掉 webpack.prod.js 中的 PurgeCSSPlugin 和 CssMinimizerPlugin 配置。

build 一下,去看看生成的 css 文件吧。


热更新的bug

相信大家都还记得,我在开发环境配置中曾经提过一次,3系的 web-dev-server 搭配 webpack5 及 browserlist 会导致LiveReloading 失效

关于Babel,可以考虑把browserlist的内容复制到 @babel/preset-env 的 targtes 属性下。

但对于 postcss-normalize 却没有什么好办法。

这里推荐的解决案是在  webpack.common.js 中添加一行:

module.exports = {
  target: isDev ? 'web' : 'browserslist',
  //others
}

缺点是无法用 IE 来调试,不过没什么人会用IE来调试吧。