Skip to content

Don't compile async/await in node_modules in development #7383

Description

@firatoezcan

Is your proposal related to a problem?

The problem that I have with the preset transpiling async/await is that debugging gets really hard. With the uprising of hooks a lot of libraries are abstracting a lot of functionality away which is great but this also means that if they expose functionality as a HOF that debugging and reading these is near impossible in development. It's not that I am bad at debugging either but more that the function get's compiled down more than it needs to be apart from reaching through another few layers for the generator part and the syntax gets completely fumbled up.

image

Code before transpiling

  const handleSubmit = (callback) => async (e) => {
    if (e && !nativeValidation) {
      e.preventDefault();
      e.persist();
    }
    let fieldErrors;
    let fieldValues;
    let firstFocusError = true;
    const fields = fieldsRef.current;
    const currentFieldValues = validationFields ? (validationFields.map(name => fieldsRef.current[name])) : Object.values(fields);
    isSubmittingRef.current = true;
    reRenderForm({});


    const { errors, values } = await currentFieldValues.reduce(
      async (previous, field) => {
        if (!field) return previous;
        const resolvedPrevious = await previous;
        const ref = field.ref
        const name = field.ref
        if (!fields[name]) return Promise.resolve(resolvedPrevious);

        const fieldError = await validateField(field, fields, nativeValidation);

        if (fieldError[name]) {
          if (submitFocusError && firstFocusError && ref.focus) {
            ref.focus();
            firstFocusError = false;
          }
          resolvedPrevious.errors = {
            ...(resolvedPrevious.errors || {}),
            ...fieldError,
          };
          return Promise.resolve(resolvedPrevious);
        }

        resolvedPrevious.values[name] = getFieldValue(fields, ref);
        return Promise.resolve(resolvedPrevious);
      },
      Promise.resolve({ errors, values, }),
    );

    fieldErrors = errors;
    fieldValues = values;

    if (isEmptyObject(fieldErrors)) {
      await callback(combineFieldValues(fieldValues), e);
      errorsRef.current = {};
    } else {
      errorsRef.current = fieldErrors as any;
    }
    if (isUnMount.current) return;
    isSubmittedRef.current = true;
    submitCountRef.current += 1;
    isSubmittingRef.current = false;
    reRenderForm({});
  };

Code after transpiling

var handleSubmit = function handleSubmit(callback) {
    return (
      /*#__PURE__*/
      function () {
        var _ref26 = _asyncToGenerator(
        /*#__PURE__*/
        _regeneratorRuntime.mark(function _callee5(e) {
          var fieldErrors, fieldValues, fields, currentFieldValues, _ref27, errors, values;

          return _regeneratorRuntime.wrap(function _callee5$(_context5) {
            while (1) {
              switch (_context5.prev = _context5.next) {
                case 0:
                  if (e) {
                    e.preventDefault();
                    e.persist();
                  }

                  fields = fieldsRef.current;
                  currentFieldValues = Object.values(fields);
                  isSubmittingRef.current = true;
                  reRenderForm({});

                  if (!validationSchema) {
                    _context5.next = 12;
                    break;
                  }

                  fieldValues = getFieldsValues(fields);
                  _context5.next = 9;
                  return validateWithSchema(validationSchema, fieldValues);

                case 9:
                  fieldErrors = _context5.sent;
                  _context5.next = 19;
                  break;

                case 12:
                  _context5.next = 14;
                  return currentFieldValues.reduce(
                  /*#__PURE__*/
                  function () {
                    var _ref28 = _asyncToGenerator(
                    /*#__PURE__*/
                    _regeneratorRuntime.mark(function _callee4(previous, field) {
                      var resolvedPrevious, ref, name, fieldError;
                      return _regeneratorRuntime.wrap(function _callee4$(_context4) {
                        while (1) {
                          switch (_context4.prev = _context4.next) {
                            case 0:
                              _context4.next = 2;
                              return previous;

                            case 2:
                              resolvedPrevious = _context4.sent;
                              ref = field.ref, name = field.ref.name;

                              if (fields[name]) {
                                _context4.next = 6;
                                break;
                              }

                              return _context4.abrupt("return", Promise.resolve(resolvedPrevious));

                            case 6:
                              _context4.next = 8;
                              return validateField(field, fields);

                            case 8:
                              fieldError = _context4.sent;

                              if (!fieldError[name]) {
                                _context4.next = 12;
                                break;
                              }

                              resolvedPrevious.errors = Object.assign({}, resolvedPrevious.errors || {}, fieldError);
                              return _context4.abrupt("return", Promise.resolve(resolvedPrevious));

                            case 12:
                              // @ts-ignore
                              resolvedPrevious.values[name] = getFieldValue(fields, ref);
                              return _context4.abrupt("return", Promise.resolve(resolvedPrevious));

                            case 14:
                            case "end":
                              return _context4.stop();
                          }
                        }
                      }, _callee4);
                    }));

                    return function (_x10, _x11) {
                      return _ref28.apply(this, arguments);
                    };
                  }(), Promise.resolve({
                    errors: {},
                    values: {}
                  }));

                case 14:
                  _ref27 = _context5.sent;
                  errors = _ref27.errors;
                  values = _ref27.values;
                  fieldErrors = Object.assign({}, errors, filterUndefinedErrors(errorsRef.current));
                  fieldValues = values;

                case 19:
                  isSubmittedRef.current = true;
                  submitCountRef.current += 1;
                  isSubmittingRef.current = false;

                  if (isEmptyObject(fieldErrors)) {
                    callback(combineFieldValues(fieldValues), e);
                  } else {
                    errorsRef.current = fieldErrors;
                    reRenderForm({});
                  }

                case 23:
                case "end":
                  return _context5.stop();
              }
            }
          }, _callee5);
        }));

        return function (_x9) {
          return _ref26.apply(this, arguments);
        };
      }()
    );
  };

Disable transpiling of node_modules in development. Is there a reason for that?

Additional context

The library in use is react-hook-form and source-map support is enabled (the after code is the source mapped version)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions