cklwblove / blog

记录日常遇到的bug
1 stars 0 forks source link

globalThis is not defined #114

Open cklwblove opened 1 year ago

cklwblove commented 1 year ago

问题现象

在使用 vite 工具打包应用程序的时候,出现了 glolbaThis is not defined 的错误。

image

出现问题的设备信息如下: image

问题原因

经查相关资料,globalThis 的特性是 chrome 71 版本后才支持的。 image 因此,如果需要支持低于 71 版本的浏览器,需要添加对应的垫片处理。

解决方案

方案1

html 文件头部添加

<head>
    <script>
        this.globalThis || (this.globalThis = this);
       // or
       // if (globalThis === undefined) {
       //       var globalThis = window;
       //     }
    </script>
    ...
</head>
(function() {
  if (typeof globalThis === "object") return;
  Object.defineProperty(Object.prototype, "__magic__", {
    get: function() {
      return this;
    },
    configurable: true // This makes it possible to `delete` the getter later.
  });
  __magic__.globalThis = __magic__; // lolwat
  delete Object.prototype.__magic__;
})();

// Your code can use `globalThis` now.

console.log(globalThis);

弊端在于:修改Object,Object.defineProperty或Object.prototype . defineGetter可能会破坏 polyfill。

方案2

安装 globalThis 的 npm 包

npm install globalthis

main.js 文件里添加以下代码

import 'globalthis/auto';

方案3

在 vite 的插件 @vitejs/plugin-legacy 里添加配置

// vite.config.js
import legacy from https://github.com/vitejs/vite/tree/master/packages/plugin-legacy;

export default defineConfig({
  // For production build environments only
  build: {
    target: 'es2015',
  },
  plugins: [
    // For production build environments only
    legacy({
      targets: ['chrome >= 64', 'edge >= 79', 'safari >= 11.1', 'firefox >= 67'],
      ignoreBrowserslistConfig: true,
      renderLegacyChunks: false,
      /**
       * Polyfills required by modern browsers
       *
       * Since some low-version modern browsers do not support the new syntax
       * You need to load polyfills corresponding to the syntax to be compatible
       * At build, all required polyfills are packaged according to the target browser version range
       * But when the page is accessed, only the required part is loaded depending on the browser version
       *
       * Two configuration methods:
       *
       * 1. true
       *  - Automatically load all required polyfills based on the target browser version range
       *  - Demerit: will introduce polyfills that are not needed by modern browsers in higher versions,
       *    as well as more aggressive polyfills.
       *
       * 2、string[]
       *  - Add low-version browser polyfills as needed
       *  - Demerit: It needs to be added manually, which is inflexible;
       *    it will be discovered after the production is deployed, resulting in production failure! ! !
       */
      modernPolyfills: ['es/global-this'],
      //  or
      // modernPolyfills: true,
    }),
  ],
});

推荐 3 解决方案。


vite 构建打包的底层是依赖于 rollup 的,rollup 针对 top-level this 的赋值时有个配置项 context,默认值是 undefined。但 vite build 的包却是 globalThis。原因找到了,可以看链接。vite 重新赋值为 globalThis 了。 因此还有一种解决方案,其实不用添加针对 globalThis 的垫片。

// vite.config.js
export default defineConfig({
  plugins: [
    vue(),
    legacy({
      targets: ['chrome 78'],
      ignoreBrowserslistConfig: false
    }),
  ],
  build: {
    minify: false,
   // 重新赋值为 undefined 即可。
    rollupOptions: {
      context: 'undefined'
    }
  },
})
// input
var __assign = (this && this.__assign) || function () {
  __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
        t[p] = s[p];
    }
    return t;
  };
  return __assign.apply(this, arguments);
};
// output
var __assign = function() {
  __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p2 in s)
        if (Object.prototype.hasOwnProperty.call(s, p2))
          t[p2] = s[p2];
    }
    return t;
  };
  return __assign.apply(this, arguments);
};

参考

  1. https://blog.fundebug.com/2020/02/17/detail_about_globalthis/
  2. https://juejin.cn/post/7028740836842012702