阿里云主机折上折
  • 微信号
Current Site:Index > Code splitting strategy

Code splitting strategy

Author:Chuan Chen 阅读数:32564人阅读 分类: 前端综合

Code splitting is one of the key techniques for front-end performance optimization. Through reasonable engineering practices, it can effectively reduce the first-screen loading time and improve user experience. Different code splitting strategies are suitable for different scenarios and should be chosen based on project scale, technology stack, and business requirements.

Core Value of Code Splitting

Modern front-end applications are becoming increasingly complex, and single-file bundling can result in excessively large bundle sizes. Code splitting addresses this by breaking the code into smaller chunks, enabling on-demand loading. Its primary benefits are reflected in three aspects:

  1. Reduced first-screen resource size: Only the code necessary for the current route is loaded.
  2. Improved cache utilization: Modifying a single module won't invalidate the entire bundle.
  3. Parallel loading advantage: Browsers can load multiple small files simultaneously.
// Traditional bundling - single file
import { heavyModule } from './heavyModule';

// Code splitting - dynamic import
const heavyModule = await import('./heavyModule');

Route-Based Splitting Strategy

Route-level splitting is the most common strategy, where each route corresponds to an independent chunk. Frameworks like React and Vue natively support this approach.

React example:

const Home = React.lazy(() => import('./routes/Home'));
const About = React.lazy(() => import('./routes/About'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  );
}

Vue example:

const routes = [
  {
    path: '/',
    component: () => import('./views/Home.vue')
  },
  {
    path: '/about',
    component: () => import('./views/About.vue')
  }
]

Fine-Grained Component-Level Splitting

For large components, further splitting at the component level is possible:

// User dashboard component
const UserChart = React.lazy(() => import('./UserChart'));
const DataTable = React.lazy(() => import('./DataTable'));

function Dashboard() {
  return (
    <div>
      <Suspense fallback={<ChartPlaceholder />}>
        <UserChart />
      </Suspense>
      <Suspense fallback={<TablePlaceholder />}>
        <DataTable />
      </Suspense>
    </div>
  );
}

Third-Party Library Splitting Strategy

Bundling third-party libraries separately can significantly improve cache hit rates:

Webpack configuration example:

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

Dynamic Import Mode Selection

Choose different dynamic import methods based on business scenarios:

  1. Active preloading:
// Preload on hover
button.addEventListener('mouseover', () => {
  import('./module').then(module => {
    // Preload complete
  });
});
  1. On-demand lazy loading:
// Load on click
button.addEventListener('click', async () => {
  const module = await import('./module');
  module.doSomething();
});
  1. Conditional loading:
// Load different modules based on conditions
const module = await import(
  isAdmin ? './adminModule' : './userModule'
);

Advanced Webpack Splitting Configuration

Use magic comments for finer control:

// Name the chunk
import(/* webpackChunkName: "chart" */ './chart');

// Prefetch resources
import(/* webpackPrefetch: true */ './modal');

// Preload critical resources
import(/* webpackPreload: true */ './critical');

Performance Monitoring and Optimization

Monitor actual performance after splitting:

// Analyze bundle size with webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
};

// Real User Monitoring (RUM)
window.addEventListener('load', () => {
  const timing = performance.getEntriesByType('navigation')[0];
  console.log('LCP:', timing.loadEventEnd);
});

Common Issue Solutions

  1. Duplicate dependency issue:
// Webpack configuration to resolve duplicate dependencies
optimization: {
  splitChunks: {
    chunks: 'all',
    minSize: 30000,
    maxSize: 0,
    minChunks: 1,
    maxAsyncRequests: 5,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
      commons: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all'
      }
    }
  }
}
  1. CSS code splitting:
// mini-css-extract-plugin configuration
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
};

Special Handling for Server-Side Rendering

SSR scenarios require special attention:

// Next.js dynamic import example
import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(
  () => import('../components/hello'),
  {
    loading: () => <p>Loading...</p>,
    ssr: false // Disable SSR
  }
);

Splitting in Micro-Frontend Architecture

Micro-frontend scenarios require coordination among multiple sub-applications:

// Main app configuration
module.exports = {
  output: {
    library: 'mainApp',
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_mainApp`
  }
};

// Sub-app configuration
module.exports = {
  output: {
    library: 'subApp1',
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_subApp1`
  }
};

Build Tool Differences

Implementation differences across build tools:

Vite example:

// Dynamic imports are similar to webpack
const module = await import('./module');

// But glob imports can be used
const modules = import.meta.glob('./dir/*.js');

Rollup example:

// rollup.config.js
export default {
  output: {
    manualChunks(id) {
      if (id.includes('node_modules')) {
        return 'vendor';
      }
    }
  }
};

Long-Term Caching Strategy

Use contenthash for persistent caching:

output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js'
},
plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/index.html',
    hash: true
  })
]

Modern Improvement Solutions

Use ES module import maps:

<script type="importmap">
{
  "imports": {
    "react": "https://esm.sh/react@18",
    "react-dom": "https://esm.sh/react-dom@18"
  }
}
</script>

Real-World Business Scenario Example

E-commerce product detail page optimization:

// Load review component skeleton on first screen
const ProductReviews = React.lazy(() => import('./Reviews'));

function ProductPage() {
  return (
    <div>
      {/* First-screen content */}
      <ProductImage />
      <ProductInfo />
      
      {/* Lazy-load non-critical content */}
      <Suspense fallback={<ReviewsSkeleton />}>
        <ProductReviews />
      </Suspense>
    </div>
  );
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:环境变量管理

下一篇:静态资源处理

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.