Today I Learned

3 posts about #react

Babel loader transpilation for Jest

Let’s imagine a following situation: we need to create a new npm package with create-react-app, in order to bundle some files in a package to have them available in a project (it’s possible to use create-component-lib for this task). The aforementioned sometimes requires from us to update our babel config.

In my latest task I had a situation where my babel config contained invalid (for a situation) presets:

module.exports =
{
  "presets": ["@babel/preset-env", ["react-app", { "absoluteRuntime": false }]]
}

In the above example, the build process creates a transpiled code, which contains babel runtime for minimalizing package size:

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/defineProperty"));

var _objectSpread4 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/createClass"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/possibleConstructorReturn"));

var _getPrototypeOf3 = _interopRequireDefault(require("@babel/runtime/helpers/esm/getPrototypeOf"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/inherits"));

Now when we start our test which uses a transpiled component it’s possible we receive error code like this:

Jest encountered an unexpected token

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation to specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /Users/mobile32/projects/formik-generator/node_modules/@babel/runtime/helpers/esm/defineProperty.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export default function _defineProperty(obj, key, value) {
                                                                                             ^^^^^^

    SyntaxError: Unexpected token export

      10 | exports.default = void 0;
      11 |
    > 12 | var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/defineProperty"));
         |                                               ^

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
      at Object.require (dist/FormGenerator.js:12:47)

This happens because by default jest ignores transformations for everything in node_modules directory.

Now we have two possibilities to resolve this problem. In the first scenario we can add transformIgnorePatterns for our jest config to transpile babel runtime module:

transformIgnorePatterns: [
  '/node_modules/(?!@babel\/runtime)'
],

In the above example transpiled code still will be smaller in application runtime but it doesn’t crash our tests.

The second option is using another babel preset for proper transpilation:

module.exports = {
  plugins: [
    '@babel/plugin-proposal-class-properties',
  ],
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
  ],
}

Now after build, we get transpiled code working in a test environment, however, our code will be bloated with helpers required to mimic transpiled features (for example class inheritance):

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _react = _interopRequireWildcard(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _formik = require("formik");

var _yup = require("yup");

var _classnames = _interopRequireDefault(require("classnames"));

var _moment = _interopRequireDefault(require("moment"));

var _BooleanField = _interopRequireDefault(require("./FieldTypes/BooleanField"));

var _EnumField = _interopRequireDefault(require("./FieldTypes/EnumField"));

var _MoneyField = _interopRequireDefault(require("./FieldTypes/MoneyField"));

var _TextField = _interopRequireDefault(require("./FieldTypes/TextField"));

var _QuarterDateField = _interopRequireDefault(require("./FieldTypes/QuarterDateField"));

Reducing main bundle size with React lazy

On one of our projects we were able to reduce main bundle size from ~1080kB to ~820kB only by lazy loading one library (recharts).

in router file

import React, {Component, lazy, Suspense} from 'react'
//other imports

const StatisticsComponent = lazy(() => import('./path/to/component'))

export class Root extends Component {
  
  render(){
    return(
      <Router history={history}> 
        <Switch>
          // other routes
          <Suspense fallback={<div>Loading...</div>}>
            <Route exact component={StatisticsComponent} path='/statistics' />
          </Suspense>
        </Switch>
      </Router > 
      )
  }
}

ReactDatePicker Day off in Summer time issue

If you’re using react-datepicker, and the last time you’ve tested your date-picker was in winter time or sooner, please check if your date-picker still works properly.

Issue:

<DatePicker
  dateFormat="DD/MM/YYYY"
  onChange={val => this.setValue(input, val)}
  selected={input.value ? moment(input.value) : null}
  />

Seems pretty basic, right?

Date displayed:

React-date-picker displayed value

Real value:

Real value of date-picker

Solution:

Add

utcOffset={0}

to props in your react-date-picker.

<DatePicker
  dateFormat="DD/MM/YYYY"
  onChange={val => this.setValue(input, val)}
  selected={input.value ? moment(input.value) : null}
  utcOffset={0}
  />

You can read more about this issue Here.