动态导入为何触发两次网络请求?基于Create React App的Webpack问题
I've created a custom Swiper.js wrapper file to handle importing Swiper's CSS and exporting the React component:
// Swiper.js import swiperStyles from '!!raw-loader!swiper/dist/css/swiper.min.css'; const swiperElement = document.createElement('style'); swiperElement.innerHTML = swiperStyles; document.head.append(swiperElement); export { default } from 'react-id-swiper';
When I lazy-load this component using const Swiper = import('./Swiper'), Webpack splits the code into two network requests: one vendor chunk containing the CSS and React component code, and another small chunk just with the logic to insert the <style> tag into the document head. I'm using Create React App—why is this happening, and how can I avoid the extra chunk?
Why Webpack is splitting the chunk
Webpack's code-splitting logic is triggering this split due to how you've structured the module:
- The
!!raw-loader!syntax bypasses CRA's default CSS loaders, treating the CSS as a raw string instead of processing it as standard bundled CSS. - Your
export { default } from 'react-id-swiper'line creates a direct reference to the external component that Webpack sees as separable from the style-injection code. Since the style-injection logic is tiny and self-contained, Webpack splits it into a separate chunk in an attempt to optimize loading—even though it creates an unnecessary extra request here.
How to fix the extra chunk
Here are practical, CRA-friendly solutions to eliminate the split:
Option 1: Merge style injection with component import
Restructure your Swiper.js to keep the style logic and component export as a single, cohesive module. This tells Webpack not to split them:
// Swiper.js import swiperStyles from '!!raw-loader!swiper/dist/css/swiper.min.css'; import SwiperComponent from 'react-id-swiper'; // Inject styles when the module loads const swiperElement = document.createElement('style'); swiperElement.innerHTML = swiperStyles; document.head.append(swiperElement); export default SwiperComponent;
Option 2: Use CRA's default CSS handling (simplest approach)
If you don't need manual <style> tag injection, let CRA handle the CSS normally. This aligns with CRA's best practices and eliminates the split entirely:
// Swiper.js import 'swiper/dist/css/swiper.min.css'; export { default } from 'react-id-swiper';
CRA's Webpack config will bundle the CSS into your main stylesheet (or a dedicated CSS chunk) automatically, no extra requests required.
Option 3: Tweak Webpack config (advanced)
If you must keep the raw-loader approach, you can adjust Webpack's chunk-splitting rules. Since CRA hides its config by default, you have two paths:
- Eject: Run
npm run ejectto expose the Webpack config, then modify thesplitChunkssettings (e.g., raise theminSizethreshold) so the tiny style-injection chunk gets merged into the vendor chunk. Note that ejecting is irreversible. - Use react-app-rewired: This tool lets you override the Webpack config without ejecting. You can add a rule to disable splitting for your custom
Swiper.jsmodule or adjust chunk-sizing rules.
内容的提问来源于stack exchange,提问作者wa4_tasty_elephant

