2
import React from 'react';
import clsx from 'clsx';
import ReactQuill from 'react-quill';

import 'react-quill/dist/quill.snow.css';

import styles from './styles.scss';

interface Props {
  label: string;
  value: any;
  className?: string;
  inputProps: {
    onChange: (e: any) => void;
  };
}

const RichText = ({ value = '', className, inputProps, label }: Props) => {
  const { onChange } = inputProps;

  const modules = {
    toolbar: [['bold', 'italic', 'underline'], [{ align: [] }]],
  };

  const formats = ['bold', 'italic', 'underline'];

  return (
    <div>
      <label>{label}</label>

      <ReactQuill
        value={value}
        onChange={onChange}
        formats={formats}
        modules={modules}
        className={clsx(styles.root, className)}
      />
    </div>
  );
};

export default RichText;

Above you can see my rich-text component , where I user react-quill npm package. I use it only in 1 place in my code , but it add 50-60 kb to my bundle size and it annoying me. I've tried to load it dynamically by doing

 const ref = useRef()

 useEffect(() => {
   import('react-quill').then(data => {
     ref.current = data.default
   })
 }, [])

 const ReactQuill = ref.current

But it still sit in my bundle size. I've tried to load it by external url by this hook

import { useState } from 'react'

import { useMountEffect } from 'hooks'

const useExternalLibrary = ({ url, libName }) => {
  const [lib, setLib] = useState({})

  const fetchJsFromCDN = (src, externals = []) => {
    return new Promise((resolve, reject) => {
      const script = document.createElement('script')

      script.setAttribute('src', src)

      script.addEventListener('load', () => {
        resolve(
          externals.map(key => {
            return window[key]
          })
        )
      })
      script.addEventListener('error', reject)
      document.body.appendChild(script)
    })
  }

  useMountEffect(() => {
    fetchJsFromCDN(url, [libName]).then(([library]) => {
      setLib(library)
    })
  })

  return {
    lib
  }
}

export default useExternalLibrary

Where you can pass url and how it should be called in global space, url is - https://unpkg.com/react-quill@1.3.3/dist/react-quill.js , but It throw error, that you should have for a start React in global , then it is broken by prop-types library , I don't use it in my project, etc . And I have no idea what else should I try to prevent it be in my bundle size , and load it only when I need it

    optimization: {
        minimize: true,
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendor',
              chunks: 'all',
            },
          },
        },
        minimizer: [
          new TerserPlugin({
            extractComments: false,
          }),
        ],
      },

Above you can also see webpack optimization configuration, and also i've tried to wrap it to lazy

const ReactQuill = lazy(() => import('react-quill'));
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
Andrey Radkevich
  • 3,012
  • 5
  • 25
  • 57
  • You have already tried dynamic import, and it should do [code splitting](https://reactjs.org/docs/code-splitting.html). It should create a new / separate JS chunk in your build folder which should be loaded by lazily in the browser. I don't fully understand your issue. – Ajeet Shah Jan 21 '22 at 19:53
  • above you can check my webpack optimization config – Andrey Radkevich Jan 21 '22 at 23:01
  • I think you just don't understand the problem , this package goes in bundle size(in vendor) @AjeetShah , I want to prevent it , I want to load it , only when needed – Andrey Radkevich Jan 21 '22 at 23:07
  • I see. React Quill is becoming a part of your all node_modules i.e. vendor because you have instructed webpack to do that. – Ajeet Shah Jan 22 '22 at 19:05
  • You need to add another rule to the split chunks config so that it deals specifically with react-quill in the node_modules folder. – Terry Jan 22 '22 at 19:30
  • Could you pls attach solution ? I will check , because I don't understand how to solve it ? Will appreciate it – Andrey Radkevich Jan 22 '22 at 19:31

1 Answers1

0

As per your current webpack configuration, webpack is spitting out all modules inside node_modules as a single chunk named vendor. This is why you are not able to achieve the lazy loading for react-quill.

If you want to create a separate chunk for react-quill, you can modify splitChunks so that it creates a separate chunk for quill and react-quill modules:

splitChunks: {
  cacheGroups: {
    reactQuillVendor: {
      test: /[\\/]node_modules[\\/](quill|react-quill)[\\/]/,
      name: 'reactQuillVendor',
    },
    vendor: {
      test: /[\\/]node_modules[\\/]/,
      name: 'vendor',
    },
  },
},
Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87