object.hasOwn is undefined,在低版本的safari不兼容

793 阅读2分钟

问题出现原因

Object.hasOwn 是 ECMAScript 2022(也称为 ES13 或 ES2022)引入的一个新方法。它用于检查对象是否具有某个自身属性,而不检查其原型链上的属性。版本太低找不到这个方法

第一种方案:单独加Polyfill

// Polyfill for Object.hasOwn for older browsers
if (!Object.hasOwn) {
  Object.defineProperty(Object, 'hasOwn', {
    value(object: object, key: string | symbol): boolean {
      return Object.prototype.hasOwnProperty.call(object, key)
    },
    configurable: true,
    enumerable: false,
    writable: true,
  })
}

单独为这个加一下,以最小代码改动

第二种:引入所有的兼容Polyfill

npm install vite-plugin-babel @babel/preset-env core-js -D
or
pnpm install vite-plugin-babel @babel/preset-env core-js -D

配置

import react from '@vitejs/plugin-react';
import * as path from 'node:path';
import { defineConfig } from 'vite';
import VitePluginBabel from 'vite-plugin-babel';

export default defineConfig(({ mode }) => {
  const outDir = mode === 'production' ? 'build' : 'test-build';

  return {
    plugins: [
      react(),
      VitePluginBabel({
        babelConfig: {
          presets: [
            [
              '@babel/preset-env',
              {
                targets: '> 0.25%, not dead',
                useBuiltIns: 'entry',
                corejs: 3,
              },
            ],
          ],
        },
      }),
    ],
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src'),
      },
    },
    build: {
      outDir,
    },
  };
});

入口文件引入

import 'core-js/stable';

// 你的其他入口代码
import ReactDOM from 'react-dom/client';
import App from './App.tsx';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <App />
);

自己校验下低版本有无其他问题

第三种:直接打包输出ES6或者更低

// vite.config.ts
import react from '@vitejs/plugin-react';
import * as path from 'node:path';
import { defineConfig } from 'vite';

export default defineConfig(({ mode }) => {
  const outDir = mode === 'production' ? 'build' : 'test-build';

  return {
    plugins: [react()],
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src'),
      },
    },
    build: {
      outDir,
      target: 'es6', // 输出 ES6 代码
    },
  };
});

简单对比

特性使用 Polyfill直接输出 ES6 代码
兼容性提供更广泛的浏览器兼容性仅限于支持 ES6 的现代浏览器
构建配置需要配置 Babel 和 Polyfill配置 Vite 的 build.target 为 es2016或更低
打包体积较大,包含 Polyfill 代码较小,不包含 Polyfill 代码
运行时性能可能稍慢,由于 Polyfill 的运行时开销较快,没有 Polyfill 的运行时开销
开发复杂度需要了解并配置 Polyfill相对简单,只需配置目标版本
代码现代性可以使用现代 JavaScript 特性,但需要 Polyfill直接使用现代 JavaScript 特性
维护性需要定期更新 Polyfill主要依赖于浏览器的更新

需要注意的是兼容越狠,意味着打包出来的代码越多,按需采纳吧