폴리필 및 도우미 - 번들 크기를 저장하는 방법

Yoo, I'm nazha(那吒)




.
blog .
Notion .
Github .
知乎


웹 프로그래머로서 우리는 최신 기능을 사용하고 싶습니다. 반면에 이러한 기능을 이해하지 못하는 이전 브라우저에서 최신 코드가 작동하도록 하려면 어떻게 해야 할까요?

이를 위한 두 가지 도구가 있습니다.
  • 폴리필
  • 트랜스파일러

  • 폴리필 대 트랜스파일러



    폴리필



    폴리필은 새로운 기능이나 속성을 업데이트/추가하는 코드입니다.

    예를 들어 string.prototype.matchAllfirst introduced in ES2020이었고 can-i-use에 따라 67세 미만의 Chrome에서는 작동하지 않습니다. 사용자가 67세 미만의 Chrome을 사용하는 경우 string.prototyp.matchAll가 없으므로 해당 코드는 실패합니다.

    이 경우 "polyfill"은 소스 코드를 교체하지 않고 String 의 프로토타입 체인을 수정하여 간격을 "채우고"누락된 구현을 추가합니다.

    다음과 같이 코드를 작성하십시오.

    const matchString = 'abbbbc'.matchAll(/a/, 'd');
    


    그런 다음 Babel과 같은 트랜스파일러를 통해 실행합니다.

    require("core-js/modules/es.string.match-all.js");
    
    var matchString = 'abbbbc'.matchAll(/a/, 'd');
    


    트랜스파일러



    트랜스파일러는 소스 코드를 다른 코드로 변환하는 도구입니다. 최신 구문을 구문 분석하고 이전 구문을 사용하여 다시 작성하여 이전 브라우저에서 작동하도록 합니다.

    spread operator , async/await , Class이 이 경우의 좋은 예입니다.

    이 코드로 동일한 작업을 수행하십시오.

    const extendsObj = { ...{ a: 'a' } };
    


    당신은 얻을 것이다:

    var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
    var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
    
    function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
    function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
    
    var extendsObj = _objectSpread({}, {
      a: 'a'
    });
    


    코드 변환에 도움이 되는 @babel/runtime/helpers 에서 가져온 일부 함수가 있음에 유의하십시오. 그들은 내가 "도우미"라고 부르는 것입니다.

    단점



    우리의 코드가 이전 브라우저(예: IE)에서 실행될 수 있다는 것을 알게 되어 기쁩니다. 반면에 폴리필과 헬퍼는 우리의 애플리케이션을 큰 배로 만들 수도 있습니다.

    예를 들어 React 애플리케이션(node_modules에 있는 수천 개의 모듈 내)을 두 부분으로 나누어 논의합니다.
  • node_modules 디렉토리의 NPM 반응 구성 요소
  • 애플리케이션 자체

  • 도우미는 인라인해서는 안 됩니다.



    변환할 때 헬퍼 함수가 필요한 모든 파일에 추가됩니다. 이 복제는 때때로 불필요합니다.

    babel에서는 @babel/plugin-transform-runtime 플러그인이 들어오는 곳입니다. 다음과 같이 사용해야 합니다.

    "presets": [
      ["@babel/preset-env", {
        // Disable useBuiltIns by default
        "useBuiltIns": false,
      }]
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "absoluteRuntime": false,
          "helpers": true, // Helpers will not be inlined
        }
      ]
    ]
    


    swc 을 사용하는 경우 .swcrc 에서 인라인되지 않은 헬퍼를 활성화하십시오.

    "jsc": {
      "externalHelpers": true
    }
    


    도우미 버전 확인



    모듈이 동일한 경로로 확인되면 webpackrollup과 같은 번들러가 한 번 번들링합니다.

    @swc/[email protected](swc에서 사용하는 도우미)이 NPM 패키지에 설치되어 있고 응용 프로그램 루트에 @swc/[email protected]가 있다고 가정해 보겠습니다.

    서로 다른 확인된 경로에 대해 서로 다른 모듈로 간주됩니다. 때로는 이러한 복제가 불필요합니다.

    응용 프로그램의 pnpm.overrides 파일에 resolutions(yarn을 사용하는 경우) 또는 package.json(pnpm을 사용하는 경우) 필드를 추가하여 이 문제를 해결할 수 있습니다.

    "name": "react-application",
    "pnpm": {
      "overrides": {
        "@swc/helpers": "^0.3.0"
      }
    }
    


    더 우아한 방법도 존재합니다: 도우미를 위한 모듈 별칭을 만드는 것입니다. 예를 들어:

    // webpack.config.js
    module.exports = {
      //...
      resolve: {
        alias: {
          "@swc/helpers": path.resolve(__dirname, 'node_modules'),
        }
      }
    }
    


    내 NPM 패키지를 폴리필해야 합니까?



    나는 이것을하지 않는 것을 선호합니다. 반응 애플리케이션은 종속된 모든 NPM 패키지가 완전히 폴리필되었는지 여부를 알 수 없습니다. 모든 NPM 패키지가 완전히 폴리필되더라도 중단을 방지하기 위해 리액트 애플리케이션은 완전히 폴리필되어야 합니다.

    더 유연하게 만드는 두 가지 방법이 있습니다.
  • 사전 묶음(다른 게시물에서 다루겠습니다)
  • 환경을 기반으로 모든 기능을 폴리필함

  • 폴리필된 모든 기능



    babel을 사용하신다면 @babel/preset-env을 추가하시면 편리합니다. 그리고 다음과 같이 .babelrc 파일을 구성합니다.

    "presets": [
      ["@babel/preset-env", {
        "target": "79",
        "useBuiltIns": "entry",
        "corejs": "3.8"
      }]
    ]
    


    swc 사용자의 경우 다음과 같이 .swrrc 파일을 구성합니다.

    {
      "env": {
        "targets": {
          "chrome": "79"
        },
        "mode": "entry",
        "coreJs": "3.8"
      }
    }
    


    하지만 정말 완벽하지는 않습니다. "polyfill"을 사용하지 않고 polyfill을 사용하는 경우가 있습니다.

    번들 크기를 줄이기 위해 이러한 폴리필이 필요한 브라우저에 대해서만 이러한 폴리필을 로드할 수 있으므로 전 세계적으로 대부분의 웹 트래픽이 이러한 폴리필을 다운로드하지 않습니다.

    추가 자료


  • Polyfills: everything you ever wanted to know, or maybe a bit less
  • babel-polyfills
  • tsdx issue
  • 좋은 웹페이지 즐겨찾기