Modularization in Front-End Frameworks
React Component Modularization (JSX, Hooks)
React Component Modularization Practices:
- File-Based Component Organization:
components/
├── Button/
│ ├── Button.jsx
│ ├── Button.css
│ └── index.js
├── Modal/
│ ├── Modal.jsx
│ ├── Modal.css
│ └── index.js
└── ...- JSX Modularization Example:
// Button.jsx
import React from 'react';
import PropTypes from 'prop-types';
import './Button.css';
const Button = ({ text, onClick, variant }) => {
return (
<button
className={`btn ${variant}`}
onClick={onClick}
>
{text}
</button>
);
};
Button.propTypes = {
text: PropTypes.string.isRequired,
onClick: PropTypes.func,
variant: PropTypes.oneOf(['primary', 'secondary'])
};
Button.defaultProps = {
variant: 'primary'
};
export default Button;- Hooks Modularization Example:
// useCounter.js
import { useState } from 'react';
export const useCounter = (initialValue = 0) => {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
const reset = () => setCount(initialValue);
return { count, increment, decrement, reset };
};
// Counter.jsx
import React from 'react';
import { useCounter } from './useCounter';
const Counter = () => {
const { count, increment, decrement } = useCounter();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export default Counter;Vue Single File Component (SFC) Modularization
Vue SFC Modular Structure:
<!-- Button.vue -->
<template>
<button :class="['btn', variant]" @click="onClick">
<slot></slot>
</button>
</template>
<script>
export default {
name: 'AppButton',
props: {
variant: {
type: String,
default: 'primary',
validator: value => ['primary', 'secondary'].includes(value)
}
},
methods: {
onClick() {
this.$emit('click');
}
}
}
</script>
<style scoped>
.btn {
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.primary {
background-color: #1890ff;
color: white;
}
.secondary {
background-color: #f5f5f5;
color: #333;
}
</style>Vue Composition API Modularization:
<!-- useCounter.js -->
import { ref } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => count.value++;
const decrement = () => count.value--;
const reset = () => count.value = initialValue;
return { count, increment, decrement, reset };
}
<!-- Counter.vue -->
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script>
import { useCounter } from './useCounter';
export default {
setup() {
const { count, increment, decrement } = useCounter();
return { count, increment, decrement };
}
}
</script>Angular Module System (NgModule)
Angular Modular Architecture:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { SharedModule } from './shared/shared.module';
import { FeaturesModule } from './features/features.module';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
SharedModule,
FeaturesModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }Feature Module Example:
// features/user/user.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UserListComponent } from './user-list/user-list.component';
import { UserDetailsComponent } from './user-details/user-details.component';
import { UserRoutingModule } from './user-routing.module';
@NgModule({
declarations: [
UserListComponent,
UserDetailsComponent
],
imports: [
CommonModule,
UserRoutingModule
]
})
export class UserModule { }Shared Module Example:
// shared/shared.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { SharedModule as ThirdPartySharedModule } from 'third-party-library';
@NgModule({
declarations: [],
imports: [
CommonModule,
FormsModule,
MatButtonModule,
ThirdPartySharedModule
],
exports: [
CommonModule,
FormsModule,
MatButtonModule,
ThirdPartySharedModule
]
})
export class SharedModule { }Modularization Differences and Interoperability Across Frameworks
Key Differences Comparison:
| Feature | React | Vue | Angular |
|---|---|---|---|
| Component Definition | Function Components/Hooks | Single File Components (SFC) | Class Components + Decorators |
| Styling | CSS-in-JS/CSS Modules | Scoped CSS | Component Styles |
| State Management | Hooks/Context API | Vuex/Pinia | Services + NgRx |
| Routing Modularization | React Router | Vue Router | Angular Router |
| Dependency Injection | None Built-In | None Built-In | Built-In DI System |
Interoperability Solutions:
- Micro-Frontend Integration:
- Use Module Federation (Webpack 5) to integrate components from different frameworks.
- Achieve isolation via iframes or Web Components.
- Web Components Bridging:
// Expose React component as Web Component
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
class MyReactComponent extends HTMLElement {
connectedCallback() {
const mountPoint = document.createElement('div');
this.attachShadow({ mode: 'open' }).appendChild(mountPoint);
ReactDOM.render(<App />, mountPoint);
}
}
customElements.define('my-react-component', MyReactComponent);- Universal State Management:
- Use framework-agnostic state management solutions like Redux or MobX.
- Communicate via event buses or custom events.
Modularization in Micro-Frontend Architectures
Micro-Frontend Architecture Patterns:
- Route-Based Splitting:
- Different teams manage applications under different route prefixes.
- Main application handles route distribution.
- Function-Based Splitting:
- Split application into independent functional modules.
- Each module can be developed and deployed independently.
- Technology-Based Splitting:
- Coexistence of sub-applications with different tech stacks on the same page.
- Isolation via iframes or Web Components.
Module Federation Implementation:
// Host application Webpack configuration
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
app2: 'app2@http://localhost:3002/remoteEntry.js'
},
shared: ['react', 'react-dom']
});
// Sub-application Webpack configuration
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button'
},
shared: ['react', 'react-dom']
});Micro-Frontend Communication Solutions:
- Custom Events:
// Publish event
window.dispatchEvent(new CustomEvent('data-updated', {
detail: { data: newData }
}));
// Listen for event
window.addEventListener('data-updated', (event) => {
console.log('Received data:', event.detail.data);
});- State Sharing:
- Use state management libraries like Redux or MobX.
- Communicate via iframe
postMessage.
- Service Discovery:
- Use dedicated micro-frontend coordination services.
- Dynamically load remote modules.
Modularization and Package Management
Modular Design of npm Packages (package.json, main/module Fields)
Key package.json Fields:
{
"name": "my-package",
"version": "1.0.0",
"main": "dist/index.cjs.js", // CommonJS entry
"module": "dist/index.esm.js", // ES Module entry
"exports": {
".": {
"import": "./dist/index.esm.js", // ES Modules import
"require": "./dist/index.cjs.js" // CommonJS import
},
"./styles": "./dist/styles.css" // Sub-path export
},
"files": [
"dist",
"README.md"
],
"sideEffects": false, // No side effects
"dependencies": {
"lodash": "^4.17.21"
},
"peerDependencies": {
"react": ">=16.8.0"
}
}Best Practices for Modern Package Design:
- Dual-Mode Output: Provide both ESM and CommonJS versions.
- Granular Exports: Use
exportsfield for precise control over exports. - Zero Dependencies: Minimize dependencies where possible.
- Tree-Shaking Friendly: Avoid side effects and mark as side-effect-free.
Yarn Package Modularization Support (PnP Mode)
Yarn PnP (Plug’n’Play) Features:
- Eliminates node_modules: Loads dependencies directly from cache.
- Deterministic Resolution: Precise control over dependency versions.
- Faster Installation: Skips node_modules creation.
PnP Configuration:
// .yarnrc.yml
nodeLinker: "pnp"
# Custom resolution rules
packageExtensions:
"some-package@*":
dependencies:
"missing-dep": "^1.0.0"PnP Compatibility Handling:
- Use Yarn’s Compatibility Layer:
// In package.json
"dependencies": {
"@yarnpkg/pnpify": "^3.0.0"
}- Toolchain Support:
- Babel:
babel-plugin-pnp - Webpack:
pnp-webpack-plugin - Jest:
jest-environment-jsdom-fifteen(PnP support)
Private Module Repositories (Verdaccio, Nexus)
Verdaccio Configuration Example:
# config.yaml
storage: ./storage
plugins: ./plugins
web:
title: My Private Registry
auth:
htpasswd:
file: ./htpasswd
max_users: -1
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@my-org/*':
access: $authenticated
publish: $authenticated
proxy: npmjs
'private-*':
access: $authenticated
publish: $authenticated
proxy: npmjsNexus Repository Configuration:
- Install Nexus Repository Manager.
- Create npm repository (proxy, hosted, or group).
- Configure npm client:
npm config set registry http://nexus.example.com/repository/npm-group/
npm login --registry=http://nexus.example.com/repository/npm-group/Module Version Management and Semantic Versioning (SemVer)
SemVer Specification:
MAJOR.MINOR.PATCH
- MAJOR: Breaking API changes
- MINOR: Backward-compatible feature additions
- PATCH: Backward-compatible bug fixesVersion Range Specifications:
^1.2.3: Compatible with 1.x.x (≥1.2.3)~1.2.3: Compatible with 1.2.x (≥1.2.3)1.2.3: Exact version>1.2.3 <2.0.0: Version range
Version Management Strategies:
- Lock Files:
package-lock.json(npm)yarn.lock(Yarn)pnp.lock(Yarn PnP)
- Version Update Tools:
npm-check-updatesyarn upgrade-interactive
Module Dependency Conflicts and Solutions
Common Dependency Conflict Scenarios:
- Different Versions of the Same Dependency:
A@1.0.0 → B@2.0.0
C@1.0.0 → B@1.0.0- Peer Dependency Mismatches:
React@17.0.0
Some library requires React@16.8.0Solutions:
- Dependency Hoisting:
- npm/Yarn automatically hoist common dependencies to the top level.
- Alias Resolution:
// Webpack configuration
resolve: {
alias: {
'lodash': path.resolve(__dirname, 'node_modules/lodash')
}
}- Selective Dependency Overrides:
// Yarn resolutions
"resolutions": {
"lodash": "4.17.21"
}- Module Federation:
- Isolate conflicting dependencies in different sub-applications.
Modularization Performance Fundamentals
Module Loading Performance (Network Requests, Parsing Time)
Module Loading Performance Metrics:
Network Request Overhead:
- HTTP/1.1 request number limitations.
- HTTP/2 multiplexing advantages.
Parsing Time:
- JavaScript parsing and compilation time.
- WebAssembly initialization time.
Execution Time:
- Module initialization code execution.
- Dependency graph construction time.
Optimization Strategies:
- Reduce Request Count:
- Code splitting and lazy loading.
- Bundle small modules together.
- Preload Critical Resources:
<link rel="preload" href="critical.js" as="script">
<link rel="modulepreload" href="esm-module.js">- HTTP/2 Optimizations:
- Enable server push.
- Set appropriate cache headers.
Module Bundle Size Optimization (Tree Shaking, Code Splitting)
Tree Shaking Mechanism:
- ESM Static Analysis:
- Identify unused exports.
- Remove unreferenced code.
- Side Effect Marking:
// package.json
"sideEffects": [
"*.css",
"*.global.js"
]Code Splitting Strategies:
- Entry Splitting:
// Webpack configuration
entry: {
app: './src/app.js',
admin: './src/admin.js'
}- Dynamic Imports:
// Dynamic import creates new chunk
import('./module').then(module => {
module.doSomething();
});- Common Code Extraction:
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
}
}Module Caching and Reuse
Browser Caching Mechanisms:
- Strong Caching:
Cache-Control: max-age=31536000Expiresheader
- Negotiation Caching:
ETag/Last-Modified
Service Worker Caching:
// sw.js
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/index.js',
'/styles.css'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});Module Caching Optimizations:
- Long-Term Caching:
- Content-hashed filenames.
- Stable module IDs.
- Cache Invalidation Strategies:
- Versioned cache names.
- Incremental updates.
Impact of Modularization on First-Screen Loading
First-Screen Optimization Strategies:
- Critical Rendering Path Optimization:
- Inline critical CSS.
- Defer non-critical JavaScript.
- Code Splitting:
- Split by route.
- Split by functionality.
- Preloading and Prefetching:
<link rel="preload" href="critical.js" as="script">
<link rel="prefetch" href="non-critical.js" as="script">Performance Metrics Monitoring:
- FCP (First Contentful Paint)
- LCP (Largest Contentful Paint)
- TTI (Time To Interactive)
Modularization and Performance Monitoring Tools
Custom Performance Metrics Collection:
- Module Loading Time Measurement:
// Measure module loading performance
const moduleStartTimes = {};
function measureModuleLoad(moduleName) {
moduleStartTimes[moduleName] = performance.now();
return {
end: () => {
const duration = performance.now() - moduleStartTimes[moduleName];
console.log(`${moduleName} loaded in ${duration.toFixed(2)}ms`);
// Can send to monitoring system
}
};
}
// Usage example
const moduleTimer = measureModuleLoad('user-profile');
import('./user-profile').then(module => {
moduleTimer.end();
// Use module...
});- Dependency Graph Analysis:
// Analyze module dependencies
async function analyzeDependencies(entryModule) {
const dependencyGraph = {};
const visited = new Set();
async function traverse(modulePath) {
if (visited.has(modulePath)) return;
visited.add(modulePath);
const module = await import(/* @vite-ignore */ modulePath);
dependencyGraph[modulePath] = [];
// Pseudo-code for dependency extraction
if (module.__dependencies) {
for (const dep of module.__dependencies) {
dependencyGraph[modulePath].push(dep);
await traverse(dep);
}
}
}
await traverse(entryModule);
return dependencyGraph;
}Performance Optimization Checklist:
- Bundling Optimization:
- Use Tree Shaking to remove unused code
- Ensure reasonable code splitting to avoid oversized chunks
- Implement long-term caching strategies
- Loading Optimization:
- Preload critical resources
- Defer non-critical resource loading
- Utilize HTTP/2 server push appropriately
- Runtime Optimization:
- Minimize module initialization overhead
- Optimize module dependency graph
- Use caching effectively



